首页 > 编程语言 > C/C++ > [转]理解Inline Hook,HookApi通信
2015
02-03

[转]理解Inline Hook,HookApi通信

Inline hook通俗的说就是对函数执行流程进行修改,达到控制函数过滤操作的目的。理论上我们可以在函数任何地方把原来指令替换成我们的跳转指令,也确实有些人在inline的时候做的很深,来躲避inline 的检测,前提是必须对函数的流程和指令非常熟悉,且这种深层次的inlline 不具有通用性,稳定性也是问题。

Inline hook原理:解析函数开头的几条指令,把他们Copy到数组保存起来,然后用一个调用我们的函数的几条指令来替换,如果要执行原函数,则在我们函数处理完毕,再执行我们保存起来的开头几条指令,然后调回我们取指令之后的地址执行。用下图来解释:

wpsFE0C.tmp

整个Inline hook的过程就大体这样。

我们来说一个简单的实例可能会更好理解一些。

既然上面讲到了Inline Hook的原理,那我们就来实践一下,就拿应用层和驱动层的通信来实践一下吧。

前面不是说应用层和驱动层通信是通过DeviceIoControl传递控制码来实现通信的吗?

当然不止这一个方法啊,只要是带有输入输出参数的函数,我们在输入参数传入不同的标识,相当于IO_CTL宏一样的标识。然后在内核拦截这个函数,看看传入的是不是应用层发来的通信请求,如果是的话,那么我们进行请求处理,然后把结果copy到输出参数中,这样不就不实现了应用层与驱动层的通信了吗?

那我们应该怎么拦截呢?正好应用上面提到的Inline Hook的方法吧。选择哪个函数呢?就用ReadFile,这个函数传入文件句柄,返回读到的数据缓冲区。

首先通过函数名得到函数的地址:

解析函数开头的几条指令,把他们Copy到另一个地方保存起来,然后用一个调用我们的函数的几条指令来替换。


则在我们函数处理完毕,再执行我们保存起来的开头几条指令,然后调回我们取指令之后的地址执行。前面我们把原始函数的前几条汇编指令保存在下面的结构:


_declspec(naked)

就是告诉编译器,在编译的时候,不要优化代码,通俗的说就是:没代码,完全要自己写

注意最后会跳到我们替换成jmp指令的几条指令的后一条。

下面是我们自己的定义的函数:


我们发现我们自己的处理函数又调用回了NtReadFileHookZone这个函数。

到此Inline Hook ReadFile就基本完成了。

通信的时候我们在应用定义唯一的句柄号,然后驱动层根据不同的自定义文件句柄来进行不同的处理。

我们使用WinDbg分析一下会更加清晰。

好吧,我们先来看看没进行inline hook前NtReadFile的反汇编代码:

image

可以看出NtReadFile的索引号我4Ch。

执行到这句:

*(DWORD*)&jmpCode[1] = NewFunctionAddress – (oldFunctionAddrss + 5);

这里是计算jmp后面的地址=目标地址-当前地址-5

让NtReadFileRet指向第一条未进行替换的汇编语句。

*lpRet = (PVOID)(oldFunctionAddrss + *patchCodeLen);

未拷贝前:

image未拷贝前和我们定义的是一样的,注意最后一句直接jmp到NtReadFileRet所指的地址,继续执行原函数的汇编语句。

memcpy((PVOID)HookZone, (PVOID)oldFunctionAddrss, *patchCodeLen);

然后我们把前面几条需要替换的汇编代码拷贝到NtReadFileHookZone。下面是拷贝后NtReadFileHookZone的反汇编。

image

注意看画框中的汇编语句,就是原NtReadFile的前两句汇编。

memset((PVOID)oldFunctionAddrss, 0×90, *patchCodeLen);

memcpy((PVOID)oldFunctionAddrss, jmpCode, 5);

然后我们把原NtReadFile前面的汇编语句给替换掉,直接jmp到我们自己实现的函数中。

我们再来看看原始的NtReadFile函数:

image直接跳到我们自定义的函数当中了。

然后可以看到上面在自定义函数NewNtReadFile中,在执行自己的处理,我们又调回NtReadFileHookZone部分执行了。

反汇编NewNtReadFile:

82240048 c745fc80012482  mov     dword ptr [ebp-4],offset Security!NtReadFileHookZone (82240180)

这里把NtReadFileHookZone 的地址赋给指针 dword ptr [ebp-4]

最后返回的时候,我们看到直接call  NtReadFileHookZone

82240164 ff55fc          call    dword ptr [ebp-4]

而在NtReadFileHookZone 中,我们执行完原NtReadFile的前两句汇编之后又jmp到了NtReadFileRet所指的地址。反汇编这个地址:

image

是不是继续接着原NtReadFile函数来执行的。

到现在应该明白inline hook其实就是改变原函数的执行流程这句话的含义了吧。

至于恢复inline hook,只要把修改的前几句汇编语句写回去即可。

最后编辑:
作者:Carmen
这个作者貌似有点懒,什么都没有留下。

留下一个回复

你的email不会被公开。