大概解释下LZ的意思吧,有ARM汇编基础比较好理解些。
------------------------------------------------------
////////////////////// 将LZ源码列出,方便读者理解,LZ见谅 /////////////////////////////////////////
#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条指令还原回去。
NetSniffer 09/02/07