#pragma once
/* PreHook stmdb sp!, {r3} ; 盢 lr 秈 PostHook ず琵 PostHook 笵赣ê mov r3, pc add r3, r3, #0x1C str lr, [r3] ldmia sp, {r3} add sp, sp, #4 ; call Hook procedure mov lr, pc ldr pc, [pc, #0x8] ; ldr lr, [pc, #0] mov pc, lr */ extern "C" { DWORD SetKMode(DWORD); DWORD SetProcPermissions(DWORD); } namespace stools { namespace hook { struct HookSturct { // PreHook int codePrehook[10]; int addrRet; int addrHookProc; // Original API int codeBegin[4]; int codeNop; int addrBackAPI; }; void* HookFunction(void* funcOriginal, void* funcHook) { int codePreHook[10] = { 0xe92d0008, 0xe1a0300f, 0xe283301c, 0xe583e000, 0xe89d0008, 0xe28dd004, 0xe1a0e00f, 0xe59ff008, 0xe59fe000, 0xe1a0f00e }; int codeHook[3] = {0xe59ff000, 0xe1a08008, 0}; HookSturct* hookObj = new HookSturct; CopyMemory(hookObj, codePreHook, 10 * sizeof(int)); hookObj->addrHookProc = (int) funcHook; hookObj->addrBackAPI = (int) ((int*)funcOriginal + 3); hookObj->codeBegin[0] = *(int*)funcOriginal; hookObj->codeBegin[1] = *((int*)funcOriginal + 1); hookObj->codeBegin[2] = *((int*)funcOriginal + 2); hookObj->codeBegin[3] = 0xe59ff000; hookObj->codeNop = 0xe1a08008; codeHook[2] = (int) hookObj; SetKMode(TRUE); if (!SetKMode(TRUE)) OutputDebugString(L"Failed\n"); MEMORY_BASIC_INFORMATION mbi = {0}; VirtualQuery(funcOriginal, &mbi, sizeof(mbi)); DWORD nProtect = 0; VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &nProtect); ((int*)funcOriginal)[0] = codeHook[0]; ((int*)funcOriginal)[1] = codeHook[1]; ((int*)funcOriginal)[2] = codeHook[2]; VirtualProtect(mbi.BaseAddress, mbi.RegionSize, nProtect, &nProtect); SetKMode(FALSE); return (void*)((int*)hookObj + 12); } void UnhookFunction(void* funcHandler) { HookSturct* hookObj = (HookSturct*)((int*)funcHandler - 12); int* pFunctionBegin = (int*) (hookObj->addrBackAPI - 12); MEMORY_BASIC_INFORMATION mbi = {0}; VirtualQuery(pFunctionBegin, &mbi, sizeof(mbi)); DWORD nProtect = 0; VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &nProtect); pFunctionBegin[0] = hookObj->codeBegin[0]; pFunctionBegin[1] = hookObj->codeBegin[1]; pFunctionBegin[2] = hookObj->codeBegin[2]; VirtualProtect(mbi.BaseAddress, mbi.RegionSize, nProtect, &nProtect); delete hookObj; } } } 将原函数funcOriginal起始地址起3条ARM指令给替换了,替换成codeHook[0],codeHook[1];codeHook[2]; 如此,执行原函数时,其实会从codeHook[0]的地址处开始执行我们修改过的代码,codeHook[0]的3条ARM指令分别是: 第一步: 0xe59ff000, ldr pc, [pc, #0] ; 跳转到hookobj处开始执行 ; (ARM模式下,由于采用多级流水线结构,PC实际值为当前指令地址+8, ; 后边用pc寻址的指令都是这样计算的) 0xe1a08008, 同 nop hookObj --> 起始10*4存放了10条指令(codePrehook[10]) 第二步: 1. stmdb sp!, {r3} ; 将r3压入栈中,保存r3因为后边要修改r3,栈顶指针-1; 2. mov r3, pc ; 将4指令所在地址赋给r3 3. add r3, r3, #0x1C ; 将r3加上0x1c即从4指令所在地址往下7条指令,即就是hookObj->addrRet赋给r3 4. str lr, [r3] ; 将调用原函数的返回地址存入hookObj->adRet中 5. ldmia sp, {r3} ; 从栈中取出之前保存的r3 6. add sp, sp, #4 ; 平衡调用栈,还原调用栈更好听 ; call Hook procedure 7. mov lr, pc ; 将返回地址存入lr中 8. ldr pc, [pc, #0x8]; 将10指令所在地址往下2条指令处的内容赋给pc, ; !!!@@@@ 即PC跳到hookObj->addrHookProc-->我们自定义的hook函数 9. ldr lr, [pc, #0] ; 执行完我们自定的hook函数后就会返回到这了, ; 此处将当前指令往下2条指令出的内容即hookObj->addrRet取出赋给lr,即还原原先调用者的返回地址 10. mov pc, lr ; 跳到原调用者的返回地址去 把后边的内存也列出来方便大家看 11. hookObj->addrRet 12. hookObj->addrHookProc 上边 !!!@@@@ 处的执行也提一下: HookFunction的返回地址是(void*)((int*)hookObj + 12);-->即hookObj->codeBegin[4]这个地址; 跳转到我们自定义的hook函数中,例子中的代码执行的是g_proc,即hookObj->codeBegin处的指令; hookObj->codeBegin[0] = *(int*)funcOriginal; hookObj->codeBegin[1] = *((int*)funcOriginal + 1); hookObj->codeBegin[2] = *((int*)funcOriginal + 2); hookObj->codeBegin[3] = 0xe59ff000; --> ldr pc, [pc, #0] hookObj->codeNop = 0xe1a08008; --> 类似nop 即执行的是之前备份的原函数的前3条指令,执行完这3条后,hookObj->codeBegin[3]处的指令其实就是跳到后边第二条 指令开始执行,如此就相当于完整地执行了原函数。 至于 UnhookFunction 函数其实就是将原先保存的3条指令还原回去。