如题,算不得什么高深的技术了。刚好在弄一个玩意,拿起久违的钩子代码在用,顺便发个帖子,或许有些刚接触钩子的朋友用的着。限32位程序,因为64位的跳转就不是这么玩了。
钩子是啥意思,以及钩子能干嘛就不多说了吧。选好下钩点,做好保护现场就好,就能干活啦!
直接上代码了。代码中略做解释
分4块:
1.下钩函数
[C++] 纯文本查看 复制代码 void Hook::HookFun()//hook
{
DWORD dwHookAddr = HOOK_ORIADDR; //要HOOK的地址
DWORD dwOffset = 0;
DWORD dwOld = 0;
//当前 + 5 + OFFSET = target //此为公式,jmp 后面跟的4字节数据是偏移数据,略懂汇编就能理解之
dwOffset = (DWORD)HookFunc - 5 - HOOK_ORIADDR; // HookFunc就是要跳至的目标地址,也就是函数地址啦,套用公式就得到了偏移
memcpy(g_szOldCode,(char*)(dwHookAddr + 1), 4); //保存原始的字节码 为卸载钩子准备,正常需保存5个,因为jmp指令5字节 覆盖5个就得保存5个不是?我在某个call下的钩子,所以4就行,第一个为e8就不保存了
::VirtualProtect((LPVOID)HOOK_ORIADDR, 5, PAGE_EXECUTE_READWRITE, &dwOld); //修改内存属性,准备写入
*(byte*)dwHookAddr = 0xe9; //改e9 jmp == e9,这个不难
memcpy((char*)(dwHookAddr + 1), (char*)&dwOffset,4); //改成hook函数偏移 呼呼,写入成功就能跳到hook函数咯 换成汇编就是写入了jmp xxxx
::VirtualProtect((LPVOID)HOOK_ORIADDR, 5, dwOld, &dwOld); //恢复内存属性
}
2.恢复函数 卸载掉钩子
[C++] 纯文本查看 复制代码 void Hook::UnHook()//Unhook
{
DWORD dwOld = 0;
DWORD dwHookAddr = HOOK_ORIADDR; //被hook的地址
::VirtualProtect((LPVOID)HOOK_ORIADDR, 5, PAGE_EXECUTE_READWRITE, &dwOld);//修改内存属性,准备写入原始字节码
*(byte*)dwHookAddr = 0xe8; //改e8 call == e8
memcpy((char*)(dwHookAddr + 1), g_szOldCode, 4); //改成原始字节码 累积改了5个字节,完美恢复原始字节码哈哈
::VirtualProtect((LPVOID)HOOK_ORIADDR, 5, dwOld, &dwOld); //恢复内存属性
}
3.钩子函数
[C++] 纯文本查看 复制代码 __declspec(naked)
void HookFunc() //裸函数 裸函数里可以call过滤函数,干更多的活
{
__asm
{
xxx
xxx
xxx //实现具体钩子功能,代码看需求,这里xxx表示咯
jmp g_dwCallBack //跳回下钩的下一句代码,
}
}
4.过滤函数
钩子函数里面call 过滤函数,过滤函数要以stdcall的调用约定较好,不用自己平栈了。如果不用stdcall,自己的代码里要平栈哦
写不写过滤函数也是看需求,钩子函数能把活干了,也就用不着过滤函数了
|