2024/7/5 15:47:10
常说的hook一般指的是inline hook。windows系统的分几个环,inline hook是用的最广泛的在r3中。
目标:
参数:在干嘛
call正常流程代码
我们的代码:
拦截内容
修改内容
还原进来时的代码
原封不动的返回
可以在od中进行测试,比如定位到我们需要拦截指令,对需要重写的那几行指令选中,右键-标签-用nop填充。在空出来的字节中,添加指令jmp到自定义的函数。自定义的函数在jmp回拦截指令后续需要执行的指令。
代码实现
...
8d4d 0c | lea ecx,dword ptr ss:[ebp+0xc]
e8 xxx | call xxx //hook这里
xxxx | xxxx
....
相当于我们要将hook对应的机器码替换调。这里的e8对应的call, e8后面的xxx=要跳转的地址-hook的地址-(这行机器码对应的字节),例如这个的xxx=d34d2900, 那么字节就应该是5=xxx的字节(4)+e8的字节(1)。
//核心代码,hookA要hook的地址偏移,funAdd自定义函数的地址
void startHook(DWORD hookA, LPVOID funAdd){
DWORD winAdd = ...;//模块地址
DWORD hookAdd = winAdd+hookA;//通过偏移计算出实际地址
//组装指令
BYTE jmpCode[5]={0};
jmpCode[0]=0xe9;//e9对应jmp
*(DWORD*)&jmpCode[1]=(DWORD)funAdd-hookAdd-5;
//获取当前的进程句柄,因为使用inline hook,那么这里就是运行程序的句柄
HANDLE hWHND = OpenProcess(...);
//备份hook地址的数据,就是要将替换前的指令保存
ReadProcessMemory(...,backCode,...);
//写入组好的指令
WriteProcessMemory(...,jmpCode,...);
}
DWORD pEax=0;
...
//需要将该函数声明为裸函数,不然调用这个函数时会多许多其他操作
void __declspec(naked) test(){
//备份寄存器
__asm{
mov pEax, eax
...
}
//自定义的操作,注意这里的操作是不能声明变量的
//恢复寄存器
__asm{
mov eax,pEax
...
jmp 返回地址(e8 xxx后续需要执行的指令地址)
}
}
调用
startHook(xxx, test);