第一个钩子程序: inline hook

最近研究沙箱优化,发现需要学习一下 hook API 的方法,于是去啃了cuckoo的源码,发现基本原理是一种叫做inline hook的hook方法,于是去专门查了一下inline hook,看到了luoyesiqiu的文章,让我明白了很多之前不懂的地方。(文章链接https://www.cnblogs.com/luoyesiqiu/p/12306336.html)

于是我就把例子代码copy回来,稍微改动一下,想运行一下看看情况。 

StartHook和UnHook都没动,就改了一下调用和回调函数:

先不在意其他细节,总体逻辑就是hook GetSystemInfo,然后调用GetSystem,再解hook

第一个钩子程序: inline hook_第1张图片

回调函数就是在GetSystemInfo 被调用的时候输出“Im hook!!!”

第一个钩子程序: inline hook_第2张图片

编译,运行


问题出现了,程序确实跳到回调了,可是没跳回来。

反复翻看大哥的文章原文,发现大哥的例子其实只是单纯的讲述了Inline hook的原理,而不是用inline 来hook API的,因此例子代码仅在hook地址是一个5字节call 的时候,才能顺利跳到回调函数再跳回来。

如果hook一个系统函数,函数体头部几乎不可能是一个call指令,所以还要多考虑一些事情。

于是我脑袋里设想了一下大概的思路,就是替换5字节之后,要把原有的第一条指令进行备份,并记录下第二条指令的起始位置,在hook 跳转到回调函数后,执行完附加的工作之后,还要执行一下备份第一条指令的原有操作,然后再jmp回函数体的第二条指令继续执行,这样才能保证程序正常执行。

第一个钩子程序: inline hook_第3张图片

于是,我明白了调用了反编译器的lde函数在计算什么,它应该是想得到一条完整指令的长度。

我也明白了一件事,想轻松HookAPI 不是一件轻松的事,所以我打算站在巨人的肩膀上,使用cuckoo的代码(毕竟后面优化沙箱也会用到)

为便于理解,我打算先以自己的方式完成这个hook

先把所有和hook相关的部分删掉调试一下,观察GetSystemInfo的函数体,记住这个地址。

第一个钩子程序: inline hook_第4张图片

然后,再编译一个有hook的版本,再观察这个位置的变化,checkCPU入口(0x00d26dd0)下断点,发现跟我想的不一样,改的不是GetSystemInfo的函数体,而是一个6字节的jmp,想想也是,这里是kernel32.dll的一个函数列表,为什么不是直接走函数体,我也不理解,可能是出于安全考虑。

第一个钩子程序: inline hook_第5张图片

这样的话事情似乎变得简单了,和大哥的例子就很像了。

可以看到 我们覆盖的位置(0x775d9f80)5个字节,就是一条jmp(FF 25)指令的前五个字节,跳转地址00186477,这个地址应该是不变的。

执行过starthook函数,看一下,我们的确成功替换了5个字节,代码执行到这的时候会跳转到我们的hook函数上:

第一个钩子程序: inline hook_第6张图片

但我们做的不够好,第一,我们落下一个0x77没有替换,让他变成了一个ja 指令。第二,我们没有让程序回到00186477(0x77641800)

我们先不管第一个问题,先让hook函数做完想做的事后,继续去执行GetSystemInfo函数。

第一个钩子程序: inline hook_第7张图片

编译运行,程序又又又崩了,是没跳回去吗?调试!

和前面的步骤,执行到GetSystemInfo跟进去,跳进hook函数,可以看到,做完想做的事之后,会call getsysteminfo(那为什么崩了呢?)

第一个钩子程序: inline hook_第8张图片

call进来之后,这崩了……

这里搞错了,这里原来的指令应该是 jmp [0x77641800] 的地址 0x7648f370。

再修改一次代码:

第一个钩子程序: inline hook_第9张图片

编译执行:

bingo!!!

你可能感兴趣的:(第一个钩子程序: inline hook)