inline hook 驱动框架.doc_第1页
inline hook 驱动框架.doc_第2页
inline hook 驱动框架.doc_第3页
inline hook 驱动框架.doc_第4页
inline hook 驱动框架.doc_第5页
已阅读5页,还剩2页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

这段代码是针对KiInsertQueueApc函数。那么inline hook的流程是什么呢?我们知道,inline hook的目的就是修改内核函数的代码。为什么要修改呢?因为原始函数的代码我不是很满意,或者说不符合我的想法。我们还知道,函数的代码的处理对象其实就是传进来的参数。如果说我修改KiInsertQueueApc函数的开头几个字节,使其原来的代码变成一个跳转指令,跳到我自己的函数地址上并且执行我自己构建的函数,执行完成之后再跳回到原函数代码的下条指令。那么inline hook技术就实现了。而我自己构建的函数就可以事先验证参数信息。举个例子或许就非常容易理解。现在很多杀毒软件具有自我保护能力(比如保护自身进程),他会inline hook NtTerminateProcess()。具体原理是一样的,杀毒软件会修改这个函数开头的几个字节使其变为一个跳转指令,跳到杀毒软件作者自己写的函数地址上,之后这个自定义函数开始分析传进来的参数,如果发现是自己进程,那么返回失败,如果是其他进程,那么不做任何反映直接跳回去执行原始函数以后的代码。这样杀毒软件的进程就不会被关闭。现在分析代码。一开始肯定是驱动程序的入口函数NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )DbgPrint(My Driver Loaded!);theDriverObject-DriverUnload = OnUnload;g_KiInsertQueueApc = FindKiInsertQueueApcAddress();DetourFunctionKiInsertQueueApc();return STATUS_SUCCESS;没啥特别的地方,和普通的驱动程序一样。由于不用处理IRP,那么分发函数就没有必要去定义。需要注意的是,驱动程序不一定必须要创建设备。你可以发现,这个驱动程序就没有创建设备对象,因为此驱动程序不跟应用程序打交道。读者要正确理解驱动程序的概念我们来看看FindKiInsertQueueApcAddress();ULONG FindKiInsertQueueApcAddress()char * Addr_KeInsertQueueApc = 0; (1)int i = 0;char Findcode = 0xE8, 0xcc, 0x29, 0x00, 0x00 ; (2)ULONG Addr_KiInsertQueueApc = 0; Addr_KeInsertQueueApc = (char *) GetFunctionAddr(LKeInsertQueueApc); (3)for(i = 0; i 100; i +) (4)if( Addr_KeInsertQueueApc = Findcode0 &Addr_KeInsertQueueApci + 1 = Findcode1 &Addr_KeInsertQueueApci + 2 = Findcode2 &Addr_KeInsertQueueApci + 3 = Findcode3 &Addr_KeInsertQueueApci + 4 = Findcode4 )Addr_KiInsertQueueApc = (ULONG)&Addr_KeInsertQueueApc + 0x29cc + 5; (5)break;return Addr_KiInsertQueueApc;具体分析:这个函数的作用是找到KiInsertQueueApc()的首地址。具体看代码:(1)定义一个指针变量。此指针的跳跃数为1字节。(2)你必须用windbg分析KeInsertQueueApc()函数,由于这个函数必定调用KiInsertQueueApc(),那么“调用代码”必定会出现在函数中。那么我们选出这个“调用代码”作为特征值就可以定位到KiInsertQueueApc()的首地址。具体是这样的: 0xE8, 0xcc, 0x29, 0x00, 0x00 这是在内存中的样子。而从程序的角度来讲是:000029ccE8,那么这样的机器码对应的汇编代码是 ADD BYTE PTR DS:EAX,ALSUB ESP,ECXCALLCALL对应的机器码是0xE8.那么既然CALL出现了,后面跟的东西肯定为一个地址值。通过用windbg分析可知,这个地址就是KiInsertQueueApc()的首地址。不过需要注意的是,汇编代码和机器码并不是呆板的一一对应的关系,这点千万要注意!(3)调用一个自定义函数。ULONG GetFunctionAddr( IN PCWSTR FunctionName)UNICODE_STRING UniCodeFunctionName;RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName ); 这个函数会调用MmGetSystemRoutineAddress()内核函数,其目的是得到KeInsertQueueApc()的首地址。需要注意的是KeInsertQueueApc()是导出函数,那么可以用MmGetSystemRoutineAddress()得到其首地址。KiInsertQueueApc()为非导出函数,因此不能通过调用MmGetSystemRoutineAddress()直接得到其首地址。(4)通过循环的方式查找特征码从哪个地方开始出现。(5)Addr_KiInsertQueueApc = (ULONG)&Addr_KeInsertQueueApc + 0x29cc + 5。这句话我感觉有点错误,我把它改成Addr_KiInsertQueueApc = (ULONG)&Addr_KeInsertQueueApc + 5。(其实这样表达是错误的) 0xE8, 0xcc, 0x29, 0x00, 0x00 后面是偏移量 CALL 后面真实的地址是 偏移量+偏移量后面的真实地址=call真实地址举个例子吧:004011FC |. E8 CF000000 CALL chapter1.004012D000401201 |. 83C4 04 ADD ESP,4CALL chapter1.004012D0=是E8后面的 000000CF+00401201=004012D0 大家可以算下Addr_KiInsertQueueApc = (ULONG)&Addr_KeInsertQueueApc + 0x29cc + 5 是正确的 相当于(ULONG)&Addr_KeInsertQueueApc+5=上面call下一句的地址(就好比:00401201)0x29cc=000000CF 所以Addr_KiInsertQueueApc = (ULONG)&Addr_KeInsertQueueApc + 0x29cc + 5就是CALL的真实地址个人理解 有错误的地方 欢迎大家仍鸡蛋这句话中有个指针的高级用法,请看(ULONG)&Addr_KeInsertQueueApc 。它的组合顺序是这样的:(ULONG)(&(Addr_KeInsertQueueApc )其中Addr_KeInsertQueueApc代表一个跳跃数为1字节的指针。Addr_KeInsertQueueApc表示这个指针跳跃i次后所指向的内存空间对应的变量。(死记)&(Addr_KeInsertQueueApc 变量再次加上&之后又变成了地址值。(ULONG)(&(Addr_KeInsertQueueApc )最后加上ULONG强制转换类型。为4字节(32位地址)为什么最后要+5呢?因为这5个字节特征码必须跳过才能真正定位到函数的地址值。你好好分析上面的循环代码,仔细算下就会知道必须+5。这个问题不难理解。关于上面指针的用法,估计有些读者还是很晕,其实是这样的,指针的表示方式很多,上面这个表示方式是其中的一种,你如果不能理解,那么好好去理解,如果实在理解不了,那么死记。请看下面我的例子,或许能帮助你理解:int * p;int a=5;p=&a;上面这个3行代码很好理解,很基础。其实那样写麻烦,可以这样:int *p =(int *)&(5)哈哈,具体如何理解笔者不打算去讲解,靠读者自己去领悟。反正这样方法有些书上会用到。并且将来的代码都会涉及。再来看看我们的自定义函数:_declspec(naked) my_function_detour_KiInsertQueueApc() (1)_asm mov edi,edi (2)push ebp (2)mov ebp, esp (2)push ecxmov eax,ecx_emit 0xEA (5)_emit 0xAA (3)_emit 0xAA (3)_emit 0xAA (3)_emit 0xAA (3)_emit 0x08 (4)_emit 0x00 (4)这个函数为自定义函数,将来运行kiInsertQueueApc()函数之后会立刻跳转到这个函数上来。(1)(2)和函数堆栈框架有关,请读者仔细研究天书夜读这本书。我们知道这个自定义函数执行完之后还必须跳回原来的kiInsertQueueApc(),那么(3)这个地方就是跳回去的地址。这里的_emit的意思是强制产生一个字节的数据作为代码,因此在mov eax,ecx 后面就多出了一段代码:EA,AA,AA,AA,AA,08,00。这7个字节的数据作为机器码而存在,那么翻译成汇编代码就是JMP FAR 0008:AAAAAAAA。其中0008是选择子。AAAAAAAA正好32位,为一个地址值。那么为什么必须这样做呢?为什么不能直接用JMP FAR指令呢?因为我们现在编写的是驱动程序,那么最后必须通过DDK编译器来编译,而DDK编译器压根没有指出段间跳转的指令语法,既然人家语法都没有去定义,那么你怎么能用呢。总之在DDK编译器眼里,它根本不认识JMP FAR这个指令。关于选择子的介绍等我考试好了再说,你现在只要知道:大多数内核代码用的都是08选择子。(4)就是选择子,以后重点会讲到以上这个函数的作用仅仅只是跳回去。你可以在这个函数里写入自己想要写入的代码。之后驱动程序调用DetourFunctionKiInsertQueueApc();VOID DetourFunctionKiInsertQueueApc()char *actual_function = (char *)g_KiInsertQueueApc; (1)unsigned long detour_address; unsigned long reentry_address; /从自定义函数条跳到原函数的偏移地址。KIRQL oldIrql;int i = 0;char newcode = 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00, 0x90 ;reentry_address = (unsigned long)g_KiInsertQueueApc) + 8; non_paged_memory = ExAllocatePool(NonPagedPool, 256);for(i=0;i256;i+)(unsigned char *)non_paged_memory) = (unsigned char *)my_function_detour_KiInsertQueueApc);detour_address = (unsigned long)non_paged_memory;*( (unsigned long *)(&newcode1) ) = detour_address;for(i=0;i200;i+)if( (0xAA = (unsigned char *)non_paged_memory) &(0xAA = (unsigned char *)non_paged_memory)i+1) &(0xAA = (unsigned char *)non_paged_memory)i+2) &(0xAA = (unsigned char *)non_paged_memory)i+3)*( (unsigned long *)(&non_paged_memory) ) = reentry_address;break;oldIrql = KeRaiseIrqlToDpcLevel();for(i=0;i 8;i+)g_oricode = actual_function;actual_function = newcode;KeLowerIrql(oldIrql);哈哈,如果你对上面指针用法理解了。那么这段代码很容易理解。当然,如果你对指针的用法还是不理解,那么你通过这个函数的代码继续来理解。笔者不再解释。笔者用红字表示的部分非常之重要。这是inline hook的关键。还是句老话,代码理解很容易,前提是你理解指针的原理和表示手段。自己去好好思考吧,一定要理解透了。void WPOFF()ULONG uAttr;_asm cli /阻止任何中断响应。push eax;mov eax, cr0;mov uAttr, eax;and eax, 0FFFEFFFFh; / CR0 16 BIT = 0mov cr0, eax;pop eax;s

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论