Inline Hook
工作方式如下:
1.1调用GetProcAddress对内存中要拦截的函数进行定位(如Kernel32.dll的ExitProcess),得到它的内存地址。
1.2把这个函数起始的几个字节保存到我们的内存中。
1.3用CPU的JUMP汇编指令来覆盖这个函数的起始几个字节,这条JUMP指令用来跳转到我们的替换函数的内存地址。我们替换的函数需要和原函数具有完全相同的声明:参数相同,返回值相同,调用约定相同。
1.4当线程调用被拦截的函数时,跳转指令实际上会跳转到我们的替代函数,这是,我们可以执行相应的功能代码。
1.5为了撤销对函数的拦截,我们必须把步骤2中保存的字节恢复回被拦截的函数中。
1.6我们调用被拦截函数(现在已经不再拦截),让函数执行它的正常处理。
1.7当原来函数返回时,我们再次执行第2,第3步,这样我们的替代函数将来还会被调用到。
注意事项:
l JUMP指令对CPU(AMD,Intel)有依赖,在X86,X64下,更会有不同的表现。
l 由于替换汇编代码的过程,不是原子操作的,很有可能在其它线程运行到此函数的入口的时候进行了替换,导致指令异常,程序崩溃。
l 解决多线程的办法(分析来自Mhook库):
替换的过程首先上互斥锁(如EnterCriticalSection),这把锁只对替换的过程互斥, 并无法避免其它线程正在调用要替换的函数。
第二步做的就是挂起除本线程外的其它线程,并同时确保其它线程的执行点(IP)不在 我们将以替换的区域中。(参加Mhook的: SuspendOtherThreads函数)
一般情况下,API的头部都是 8B FF 55 8B EC 如图所示:
刚好5个字节的硬编码,我们修改成 jmp xxxxxxxx 时也是5个字节进行跳转到我们想要执行的代码地址。修改硬编码hook方式可以在API任意位置进行Hook并不局限于头5个字节,任意位置时需要计算好opcode码。