先把用来HOOK的函数贴出来,然后逐过程解释
LPVOID DetourFunc(BYTE *src, const BYTE *dst, int len, int TYPE, PMEMORYINFO lpMemInfo) { if (lpMemInfo) { lpMemInfo->dwAddr = (DWORD)src; lpMemInfo->len = len; lpMemInfo->lpOriginCode = (PBYTE)malloc(len + 0x5); memcpy_m(lpMemInfo->lpOriginCode, src, len); lpMemInfo->IsHook = TRUE; } DWORD lpOld; VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &lpOld); switch (TYPE) { case DETOUR_TYPE_JMP: src[0] = 0xE9; break; case DETOUR_TYPE_CALL: src[0] = 0xE8; break; } *(DWORD*)(src + 1) = (DWORD)(dst - src) - 5; BYTE* Addr = src + 5; BYTE* dstination = src + len; BYTE* pCode = lpMemInfo->lpOriginCode + len; *pCode = 0xE9; *(DWORD*)(pCode + 0x1) = (DWORD)(dstination - pCode) - 5; while (Addr != dstination) { *Addr = 0x90; Addr++; } VirtualProtect(src, len, lpOld, &lpOld); VirtualProtect((LPVOID)lpMemInfo->lpOriginCode, len + 0x5, PAGE_EXECUTE_READWRITE, &lpOld); return (src+len); }
lpMemInfo是一个结构体,用来存放HOOK的一些信息,它的各属性的含义是
- dwAddr: HOOK的目标地址
- len: 覆盖的字节大小
- lpOriginCode: 一个指向一段空间的指针,这段空间用来存放目标地址处的原代码
- IsHook: 一个布尔型变量用来存放对HOOK动作的判断
接下来解释代码
结构体初始化.png绘图_刚分配后.png方框中的部分分配了一段大小为len+0x5大小的空间,并把原始数据存入
置入跳转方式.png
上面这段代码的意思就是置入跳转方式,把HOOK的地址的第一个字节改为JMP或者CALL,0xE9代表JMP,0xE8代表CALL
*(DWORD*)(src + 1) = (DWORD)(dst - src) - 5;
上面这行代码的意思是将接下来的四个字节写入要跳转的地址,因为是指向DWORD的指针,所以是4个字节。所以在CALL之前进行HOOK的话,必须保证HOOK地址与CALL之间的距离大于5个字节
BYTE* pCode = lpMemInfo->lpOriginCode + len; *pCode = 0xE9;
汇编片段.png上面代码的作用就是把lpOriginCode指向的空间的后5个字节变成一个跳转到HOOK地址加Len的地方
在上图中,如果我们的HOOK地址是0x0351C853,那么JMP语句跳转到CALL地址,0x0351C858,len为5
while (Addr != dstination) { *Addr = 0x90; Addr++; }
如果len > 5的话,将JMP语句到CALL之间的语句置为空指令nop(代码字节为0x90)
VirtualProtect函数的作用是改变一段内存区域的访问权限
最后函数的返回值为CALL的地址
下面是HOOK函数的使用方法
我的HOOK函数.png_Skin()函数作为HOOK函数的*BYTE dst参数传入,当被HOOK的地址被运行时会跳转到_Skin()函数,pushad用来保护寄存器,之后我们可以调用自己的函数(这里为_Skin_Data())作其它处理
使用popad、popfd恢复寄存器后,我们需要把上面HOOK过程中被覆盖的代码加上去之后再调用reCall(HOOK函数的返回值)
HOOK函数中被保存的原始代码和结构体的一些属性这里并没有用到,可以省略
整个HOOK过程到此结束,作者Q49909509,欢迎交流-_-.
网友评论