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

来源:互联网 发布:免费朗读软件 编辑:程序博客网 时间:2024/05/01 14:26
内核级利用通用Hook函数方法检测进程

www.hackbase.com 2007-1-5 0 黑客基地
 

介绍通用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            ......

测试、编译环境windows2000 sp4、windows2000 ddk。没写出线程的隐藏进程代码,不过基本上实现得差不多了,只需要把返回的信息,和ring3级查询得到的信息进行适时对比就能查出异常进程了。

(完)

 
原创粉丝点击