#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条指令还原回去。