第一个钩子程序: 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

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

编译,运行


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

call进来之后,这崩了……

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

再修改一次代码:

编译执行:

bingo!!!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 渐变的面目拼图要我怎么拼? 我是疲乏了还是投降了? 不是不允许自己坠落, 我没有滴水不进的保护膜。 就是害怕变得面...
    闷热当乘凉阅读 4,349评论 0 13
  • 夜莺2517阅读 127,761评论 1 9
  • 版本:ios 1.2.1 亮点: 1.app角标可以实时更新天气温度或选择空气质量,建议处女座就不要选了,不然老想...
    我就是沉沉阅读 6,961评论 1 6
  • 我是一名过去式的高三狗,很可悲,在这三年里我没有恋爱,看着同龄的小伙伴们一对儿一对儿的,我的心不好受。怎么说呢,高...
    小娘纸阅读 3,417评论 4 7
  • 那一年,我选择了独立远行,火车带着我在前进的轨道上爬行了超过23个小时; 那一年,我走过泥泞的柏油路,在那个远离故...
    木芽阅读 1,661评论 4 5