函数hook注意事项

函数hook,简单地说就是把目标函数替换我们的函数,用比较技术的语言描述就是:

(1) Target函数:要拦截的函数,通常为Windows的API。

(2) Trampoline函数:Target函数的复制品。因为Detours将会改写Target函数,所以先把Target函数复制保存好,一方面仍然保存Target函数的过程调用语义,另一方面便于以后的恢复。

(3) Detour函数:用来替代Target函数的函数(往往是我们自己写的函数)。

一 般进行函数hook的原理是在Target函数的开头加入JMP Address_of_ Detour_Function指令(共5个字节)把对Target函数的调用引导到自己的Detour函数, 把Target函数的开头的5个字节加上 JMP Address_of_Target _ Function + 5作为Trampoline函数地址。

         其实关于函数hook方法的资料已经汗牛充栋,而且微软也早就推出了官方的库来辅助这一过程,无需我再赘述,我在这里只想谈下面一个话题:如何写好Detour函数,这是我们总结了前人和自身实践经验得出的。

         进 行过函数hook实践的同学是否有过这种经历,注入我们的代码或dll,对目标函数进行hook后,执行到我们的函数或者执行过我们的函数后,程序会出错 或崩溃(甚至蓝屏)。这是正常的,编写detour函数和普通的编程很不一样,它就像深入敌后的间谍,要考虑很多细节,稍不注意会破坏Context,影 响目标进程的正常运行。那么要注意什么呢?

1.       自己定义的detour函数和目标target函数的参数很返回值完全一致

因 为没有代码,所以对于目标函数的参数和返回值的确定是需要逆向分析的,在有pdb的情况下很嗨,直接IDA等工具能帮你准确确定。没有pdb的情况下需要 通过参数所占内存大小、特征甚至动态调试去确定,这里想强调一点是指针类型、数值类型、和引用类型的区分很关键且容易出错。另外有一种可怕的经验是返回值 是一个结构,没经验无从讲起,但愿不要遇到这种情况。

2.       函数调用方式的确定与选择

我 假设大家都知道了常见的cdecl和stdcall还有fastcall三种调用方式的异同,通常情况下碰到的函数调用都是cdecl和stdcall方 式。他们最大的区别是前者是函数调用者负责栈平衡,后者是函数内负责栈平衡。我们编写detour函数时最好明确声明函数调用方式,原则是和target 函数声明方式保持一致。Tips:就hook这种特殊情形,一般用stdcall更方便,因为我们的控制范围是函数内部,要向控制函数调用上下文要绕写弯 路,而stdcall是在函数内部控制栈平衡的,so,under control!

3.       现场保护

在 编写detour函数时要时刻有一个观念就是这段代码的正确运行是以不破坏当前进程正常运行为前提的,但一个问题是我们往往不知道进程需要用到哪些现场, 所以就是通过pushad-popad对寄存器进行完整保护。但应该在什么情况下使用pushad和popad呢?这个需要视具体情况而定,但有一个原则 是:在开始执行自己的指令前pushad,在执行原生代码前popad,这个原则不是很准确,只是想表示:不要让自己的指令执行破坏原来的 context。

4.       This:“勿忘我!”

对于hook一般的系统函 数,在detour函数中可以直接调用Trampoline函数,但在hook一些类成员函数后,不能直接调用Trampoline函数,因为进程确定对 象成员函数需要以该对象this指针为入口进行索骥。所以hook了类成员函数,又要在detour函数中调用Trampoline函数,需要在调用前将 对象的地址(this指针的内容)存入ecx中。

         就我目前的经验和水平只能总结这些,其实上述的123点背后都有一个共同的背 后灵就是“栈平衡”,函数调用的最基本规则就是要在函数调用前和函数调用结束后保证sp指在同一个地方,所以你如果碰到hook崩溃的情况,第一步想到的 调试方法就是对比查看函数执行前后的栈的情况然后就是比较寄存器的异同。

编译:函数hook注意事项

地址:http://www.07net01.com/program/34290.html

你可能感兴趣的:(函数hook注意事项)