内核级利用通用Hook函数方法检测进程

    技术2022-05-11  153

    创建时间:2005-05-10 文章属性:原创 文章提交: LionD8 (liond8_at_126.com) 内核级利用通用Hook函数方法检测进程 作者:    LionD8 QQ:    10415468 Email: LionD8@126.com Blog:     http://blog.csdn.net/LionD8     or http://liond8.126.com 介绍通用Hook的一点思想:     在系统内核级中,MS的很多信息都没公开,包括函数的参数数目,每个参数的类型等。在系统内核中,访问了大量的寄存器,而很多寄存器的值,是上层调用者提供的。如果值改变系统就会变得不稳定。很可能出现不可想象的后果。另外有时候对需要Hook的函数的参数不了解,所以不能随便就去改变它的堆栈,如果不小心也有可能导致蓝屏。所以Hook的最佳原则是在自己的Hook函数中呼叫原函数的时候,所有的寄存器值,堆栈里面的值和Hook前的信息一样。这样就能保证在原函数中不会出错。一般我们自己的Hook的函数都是写在C文件里面的。例如Hook的目标函数KiReadyThread。 那么一般就自己实现一个: MyKiReadyThread(...) {     ......     call KiReadyThread     ...... } 但是用C编译器编译出来的代码会出现一个堆栈帧: Push ebp mov  ebp,esp 这就和我们的初衷不改变寄存器的数违背了。所以我们可以自己用汇编来实现MyKiReadyThread。 _func@0 proc     pushad        ;保存通用寄存器     call _cfunc@0  ;这里是在进入原来函数前进行的一些处理。     popad         ;恢复通用寄存器     push eax       mov eax,[esp+4] ;得到系统在call 目标函数时入栈的返回地址。     mov ds:_OrgRet,eax ;保存在一个临时变量中     pop eax     mov [esp],retaddr  ;把目标函数的返回地址改成自己的代码空间的返回地址,使其返回                后能接手继续的处理     jmp _OrgDestFunction ;跳到原目标函数中 retaddr:     pushad         ;原函数处理完后保存寄存器     call _HookDestFunction@0 ;再处理     popad      ;回复寄存器     jmp ds:_OrgRet ;跳到系统调用目标函数的下一条指令。 _func@0 endp 当我们要拦截目标API的时候,只要修改原函数头5个字节的机器为一个JMP _func就行了。 然后把原来的5字节保存。在跳入原函数时,恢复那5个字节即可。 Hook KiReadyThread检测系统中的进程: 在线程调度抢占的的时候会调用KiReadyThread,它的原型为 VOID FASTCALL KiReadyThread (IN PRKTHREAD Thread) 在进入KiReadyThread时,ecx指向Thread。 所以完全可以Hook KiReadyThread 然后用ecx的值得到但前线程的进程信息。 KiReadyThread没被ntosknrl.exe导出,所以通过硬编码来。在2000Sp4中地址为0x8043141f 具体实现: // 1.cpp #ifdef __cplusplus extern "C" { #endif #include "ntddk.h" #include "string.h" #include "ntifs.h" #include "stdio.h" #define FILE_DEVICE_EVENT  0x8000 #define IOCTL_PASSBUF /     CTL_CODE(FILE_DEVICE_EVENT, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) void DriverUnload (IN PDRIVER_OBJECT pDriverObject); NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath); void cfunc (); void HookDestFunction(); NTSTATUS DeviceIoControlDispatch(IN  PDEVICE_OBJECT  DeviceObject,                                  IN  PIRP            pIrp); extern void func(); void ResumeDestFunction(); const WCHAR devLink[]  = L"//??//MyEvent"; const WCHAR devName[]  = L"//Device//MyEvent"; UNICODE_STRING          devNameUnicd; UNICODE_STRING          devLinkUnicd;     ULONG OrgDestFunction = (ULONG)0x8043141f; //KiReadyThread char JmpMyCode [] = {0xE9,0x00,0x00,0x00,0x00}; char OrgCode [5]; char OutBuf[128][16]; int Count = 0; ULONG orgcr0; #ifdef __cplusplus } #endif VOID DisableWriteProtect( PULONG pOldAttr) {      ULONG uAttr;      _asm     {           push eax;           mov  eax, cr0;           mov  uAttr, eax;           and  eax, 0FFFEFFFFh; // CR0 16 BIT = 0           mov  cr0, eax;           pop  eax;     };      *pOldAttr = uAttr; //保存原有的 CRO 属性 } VOID EnableWriteProtect( ULONG uOldAttr ) {   _asm   {        push eax;        mov  eax, uOldAttr; //恢复原有 CR0 属性        mov  cr0, eax;        pop  eax;   }; } NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING RegistryPath) {     NTSTATUS                Status;     PDEVICE_OBJECT            pDevice;     DbgPrint("DriverEntry called!/n");     RtlInitUnicodeString (&devNameUnicd, devName );     RtlInitUnicodeString (&devLinkUnicd, devLink );     Status = IoCreateDevice ( pDriverObject,     0,          &devNameUnicd,     FILE_DEVICE_UNKNOWN,        0,        TRUE,        &pDevice );         if( !NT_SUCCESS(Status))         {         DbgPrint(("Can not create device./n"));         return Status;     }        Status = IoCreateSymbolicLink (&devLinkUnicd, &devNameUnicd);        if( !NT_SUCCESS(Status))        {            DbgPrint(("Cannot create link./n"));            return Status;        }        pDriverObject->DriverUnload  = DriverUnload;        pDriverObject->MajorFunction[IRP_MJ_CREATE] =     pDriverObject->MajorFunction[IRP_MJ_CLOSE] =     pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =    DeviceIoControlDispatch;            pDriverObject->DriverUnload = DriverUnload;     * ( (ULONG*) (JmpMyCode+1) ) = (ULONG)func - (ULONG)OrgDestFunction - 5;     memcpy(OrgCode,(char*)OrgDestFunction,5);     HookDestFunction();          return STATUS_SUCCESS; } void DriverUnload (IN PDRIVER_OBJECT pDriverObject) {     NTSTATUS            status;     ResumeDestFunction();     if(pDriverObject->DeviceObject != NULL)         {            status=IoDeleteSymbolicLink( &devLinkUnicd );         if ( !NT_SUCCESS( status ) )             {                     DbgPrint((  "IoDeleteSymbolicLink() failed/n" ));             }             IoDeleteDevice( pDriverObject->DeviceObject );         } } void DisplayName(PKTHREAD Thread) {     PKPROCESS Process = Thread->ApcState.Process;     PEPROCESS pEprocess = (PEPROCESS)Process;     DbgPrint("ImageFileName = %s /n",pEprocess->ImageFileName);     sprintf(OutBuf[Count++],"%s",pEprocess->ImageFileName); } void cfunc (void) {     ULONG PKHeader=0;     __asm     {         mov PKHeader,ecx  //ecx寄存器是KiReadyThread中的PRKTHREAD参数     }     ResumeDestFunction();          if ( PKHeader != 0 && Count < 128 )     {         DisplayName((PKTHREAD)PKHeader);         }     } void HookDestFunction() {     DisableWriteProtect(&orgcr0);     memcpy((char*)OrgDestFunction,JmpMyCode,5);     EnableWriteProtect(orgcr0);     } void ResumeDestFunction() {     DisableWriteProtect(&orgcr0);     memcpy((char*)OrgDestFunction,OrgCode,5);     EnableWriteProtect(orgcr0); } NTSTATUS DeviceIoControlDispatch(                                  IN  PDEVICE_OBJECT  DeviceObject,                                  IN  PIRP            pIrp                                  ) {     PIO_STACK_LOCATION              irpStack;     NTSTATUS                        status;     PVOID                           inputBuffer;     ULONG                           inputLength;     PVOID                           outputBuffer;     ULONG                           outputLength;     OBJECT_HANDLE_INFORMATION       objHandleInfo;     status = STATUS_SUCCESS;     // 取出IOCTL请求代码     irpStack = IoGetCurrentIrpStackLocation(pIrp);     switch (irpStack->MajorFunction)     {     case IRP_MJ_CREATE :         DbgPrint("Call IRP_MJ_CREATE/n");         break;     case IRP_MJ_CLOSE:         DbgPrint("Call IRP_MJ_CLOSE/n");         break;     case IRP_MJ_DEVICE_CONTROL:         DbgPrint("IRP_MJ_DEVICE_CONTROL/n");         inputLength=irpStack->Parameters.DeviceIoControl.InputBufferLength;         outputLength=irpStack->Parameters.DeviceIoControl.OutputBufferLength;         switch (irpStack->Parameters.DeviceIoControl.IoControlCode)         {             case    IOCTL_PASSBUF:             {                 RtlCopyMemory(pIrp->UserBuffer, OutBuf, 20*16);                                  memset(OutBuf,0,128*16);                 Count = 0;                 break;             }             default:                 break;         }     default:         DbgPrint("Call IRP_MJ_UNKNOWN/n");         break;     }     pIrp->IoStatus.Status = status;     pIrp->IoStatus.Information = 0;     IoCompleteRequest (pIrp, IO_NO_INCREMENT);     return status; } // 1.asm .386 .model small .data _OrgRet dd 0 .code public _func@0 extrn _cfunc@0:near extrn _HookDestFunction@0:near extrn _OrgDestFunction:DWORD _func@0 proc     pushad     call _cfunc@0     popad     push eax     mov eax,[esp+4]     mov ds:_OrgRet,eax     pop eax     mov [esp],retaddr     jmp _OrgDestFunction retaddr:     pushad     call _HookDestFunction@0     popad     jmp ds:_OrgRet _func@0 endp END // // app.cpp // #include <windows.h> #include <stdio.h> #define FILE_DEVICE_EVENT  0x8000 #define CTL_CODE( DeviceType, Function, Method, Access ) (                 /     ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) / ) #define FILE_ANY_ACCESS                 0 #define METHOD_BUFFERED                 0 #define FILE_DEVICE_UNKNOWN             0x00000022 #define IOCTL_PASSBUF /     CTL_CODE(FILE_DEVICE_EVENT, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) int main() {        HANDLE      hDevice;             bool        status;        ULONG       dwReturn;         char        outbuf[129][16];         hDevice = NULL;         m_hCommEvent = NULL;         hDevice = CreateFile( ".//MyEvent",                     GENERIC_READ|GENERIC_WRITE,                     FILE_SHARE_READ | FILE_SHARE_WRITE,                     NULL,                     OPEN_EXISTING,                     FILE_ATTRIBUTE_NORMAL,                     NULL);         if(hDevice == INVALID_HANDLE_VALUE)         {            printf("createfile wrong/n");            getchar();            return 0;         }     while(1)     {         memset(outbuf,0,129*16);         status =DeviceIoControl(hDevice,                     IOCTL_PASSBUF,                     NULL,                     0,                     &outbuf,                     128*16,                     &dwReturn,NULL);         if( !status)         {             printf("IO wrong+%d/n", GetLastError());             getchar();             return 0;         }         int c=0;         while( *((char*)(&outbuf)+c*16) )         {             //把csrss.exe和自身进程信息跳过,因为会产生有大量的信息。             if ( strcmp((char*)(&outbuf)+c*16,"app.exe") && /                  strcmp((char*)(&outbuf)+c*16,"csrss.exe")  )                 printf("%s/n",(char*)(&outbuf)+c*16);             c++;         }         Sleep(1);     } } 试验结果: ...... TTPlayer.exe System TTPlayer.exe vrvmon.exe TTPlayer.exe System System Explorer.EXE Explorer.EXE Explorer.EXE ...... 测试,编译环境 2000 Sp4 2000 DDK

    最新回复(0)