C++ 在Ring3下的通用API HOOK

说道API HOOK ,这已经是老掉牙的技术了,但是它的实用性却是不能忽视的。虽然在网上这类的文章很多,但大多数的实现方法是将一个函数的前5字节直接改为 jmp XXXX 。这种方法虽然简单可行,但是不通用,因为一些特殊函数的前5字节不是完整的,如果直接修改,就会截断指令,导致出错。以前在一个论坛上看到过一个用反汇编引擎实现的通用例子,感觉想法很好,于是自己也写了一个。其中用到了一个头文件LDasm.h(里面实际就是一个轻量级的反汇编引擎,网上可以下载到)。

第一个函数用于对指定API进行HOOK,并返回一个进入原函数的代理函数地址。

C++ 在Ring3下的通用API HOOKC++ 在Ring3下的通用API HOOK代码

1 PVOID HookFunction(PCHAR ModuleName,PCHAR FunctionName,PVOID pNewFunction) 2 { 3  4     UCHAR JumpCode[6] = {0x68,0x00,0x00,0x00,0x00,0xC3};     //push xxxxxxxx ret 5      UCHAR JumpBackCode[6] = {0x68,0x00,0x00,0x00,0x00,0xC3}; //push xxxxxxxx ret 6       7     PVOID pSourceFunction = GetProcAddress(GetModuleHandleA(ModuleName),FunctionName); 8     if (!pSourceFunction)return NULL; 9 10     *(ULONG *)((ULONG)JumpCode + 1) = (ULONG)pNewFunction;11 12 13     PVOID pProxyFunction = 0;14     PUCHAR pOpCode;15     ULONG BackupLength = 0;16 17     18     while (BackupLength < 6)19     {20         BackupLength += SizeOfCode((PVOID)((ULONG)pSourceFunction + BackupLength),&pOpCode);21     }22 23 24     pProxyFunction = VirtualAlloc(NULL,BackupLength + 6,MEM_RESERVE|MEM_COMMIT,PAGE_EXECUTE_READWRITE);25     if (!pProxyFunction)return NULL;26 27     *(ULONG *)((ULONG)JumpBackCode + 1) = (ULONG)pSourceFunction + BackupLength;28     29     RtlCopyMemory(pProxyFunction,pSourceFunction,BackupLength);30     RtlCopyMemory((PVOID)((ULONG)pProxyFunction + BackupLength),JumpBackCode,6);31 32     FlushInstructionCache((HANDLE)-1,pProxyFunction,BackupLength + 6);33 34     DWORD OldProtect = 0;35     VirtualProtect(pSourceFunction,6,PAGE_EXECUTE_READWRITE,&OldProtect);36 37     RtlCopyMemory(pSourceFunction,JumpCode,6);38 39     VirtualProtect(pSourceFunction,6,OldProtect,&OldProtect);40 41     FlushInstructionCache((HANDLE)-1,pSourceFunction,6);42 43     return pProxyFunction;44 45 46 }

注意,在JumpCode和JumpBackCode中,我使用的是push+ret的方式进行跳转(跟网上一牛人学的),其目的是不用计算相对偏移,也不容易被一些安全工具发现。其中还有一个重要的函数——SizeOfCode(),它就是反汇编引擎里的一个函数,用于计算一个完整指令的长度,防止指令被截断,它是实现通用性的关键。

第二个函数用于恢复被HOOK的函数,它需要HookFunction函数返回的代理函数地址作为参数。

C++ 在Ring3下的通用API HOOKC++ 在Ring3下的通用API HOOK代码

1 BOOL UnHookFunction(PCHAR ModuleName,PCHAR FunctionName,PVOID pProxyFunction) 2 { 3  4     PVOID pSourceFunction = GetProcAddress(GetModuleHandleA(ModuleName),FunctionName); 5     if (!pSourceFunction)return FALSE; 6      7     DWORD OldProtect = 0; 8     VirtualProtect(pSourceFunction,6,PAGE_EXECUTE_READWRITE,&OldProtect); 9 10     RtlCopyMemory(pSourceFunction,pProxyFunction,6);11 12     VirtualProtect(pSourceFunction,6,OldProtect,&OldProtect);13 14     FlushInstructionCache((HANDLE)-1,pSourceFunction,6);15 16     BOOL res = VirtualFree(pProxyFunction,NULL,MEM_RELEASE);17     if (!res)return FALSE;18 19     return TRUE;20 21 }

这个函数很简单,只是做一些清理工作。

最后,我还写了个函数用于检查某个函数是否被HOOK,但只能检查出两种形式的HOOK,一种jmp形式,一种push+ret形式,不过也够用了。

C++ 在Ring3下的通用API HOOKC++ 在Ring3下的通用API HOOK代码

1 BOOL IsFuncHooked(PCHAR ModuleName,PCHAR FunctionName) 2 { 3     PVOID pFunction = GetProcAddress(GetModuleHandleA(ModuleName),FunctionName); 4      5     if (!pFunction)return FALSE; 6  7     DWORD OldProtect = 0; 8     VirtualProtect(pFunction,6,PAGE_EXECUTE_READWRITE,&OldProtect); 9 10     UCHAR chas = *(UCHAR *)((ULONG)pFunction + 5);11 12     if (((*(UCHAR *)pFunction == 0x68)&&(*(UCHAR *)((ULONG)pFunction + 5) == 0xC3))||(*(UCHAR *)pFunction == 0xEB)||(*(UCHAR *)pFunction == 0xEA))13     {14         VirtualProtect(pFunction,6,OldProtect,&OldProtect);15         return TRUE;16     }17     else18     {19         VirtualProtect(pFunction,6,OldProtect,&OldProtect);20         return FALSE;21     }22     23 }

好了,以上就是主要的三个函数。在说一下,我没有采用先HOOK,到调用原函数时又恢复HOOK的方法。因为这种方法效率不高,而且还不安全(尤其在多线程环境下)。所以我将原函数的前X个字节保存到另一个地方(即返回的代理函数地址),并在其后面加上回条指令(即JumpBackCode),跳到原函数的第X个指令后继续执行,这样就避免了对原函数的反复读写。

最后,有不足之处还请高手指点。
原文链接: https://www.cnblogs.com/AniX/archive/2010/10/26/1861693.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/16572

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月7日 下午4:55
下一篇 2023年2月7日 下午4:56

相关推荐