我不使用 detours(我实际上讨厌它!),但是可以以通用方式绕过任何非热补丁功能,如下所示:
第1步:在函数开头插入a JMP <your code>
,占用5个字节,可能要多一点以对齐最近的指令。举个例子
要挂钩的函数的开始:
SUB ESP,3C
PUSH EDI
PUSH ESI
//more code
会成为:
JMP MyFunction
//more code
0xE9
可以通过在第一个字节写入然后将值写入(function_addr - patch_addr + sizeof(INT_PTR))
下一个 DWORD来做到这一点。写入应该WriteProcessMemory
在设置读/写/执行权限之后使用VirtualProtectEx
第二步:接下来,我们创建一个汇编接口:
void __declspec(naked) MyFunc()
{
__asm
{
call Check ;call out filter func
test eax,eax ; test if we let the call through
je _EXIT
sub esp,3c ; its gone through, so we replicate what we overwrote
push edi
push esi
jmp NextExecutionAddress ; now we jump back to the location just after our jump
_EXIT:
retn ; note, this must have the correct stack cleanup
}
}
NextExecutionAddress 需要在运行时使用ModuleBase + RVA
.
老实说,仅 EAT(导出地址表)挂钩 dll 的导出表,或者 IAT(导入地址表)挂钩您要过滤的调用函数的导入表,其方式更简单、更好(!)。Detours 应该具有这些类型的钩子的功能,如果没有,还有其他免费可用的库可以做到这一点。
另一种方法是使用 detour 来挂钩应用程序中的每个调用,使用 dll 将它们重新路由到您自己代码中的代理函数,这具有允许仅过滤某些调用的优点,而不是二进制文件中的所有内容(可以使用 来做同样的事情_ReturnAddress
,但工作量更大),缺点是捕获要修补的位置(我使用 ollydbg + 自定义修补引擎)并且它不适用于非常规调用约定函数(比如那些#pragma aux
Watcom 或 VC7+ 生成的优化调用)。
需要注意的一件重要事情:如果您挂钩多线程应用程序,您的补丁需要在应用程序暂停的情况下完成,或者使用原子完成InterlockedExchange
,InterlockExchange64
并且InterlockedExchangePointer
(我将后者用于所有 IAT/EAT 挂钩,尤其是从“第三个”挂钩时党的过程')
看看你链接到的帖子,我认为那里的方法很糟糕,主要是由于汇编 :P 但是,你是如何调用你获得的这个指针的,它是如何获得的?