What is Inline Hook ?
就是一个函数钩子而已,把程序原本要调用的函数改成另一个函数,就是对原函数的一个挂钩(hook) 。
How did this work ?
让我们看看调用一个函数控制流的跳转图:
fun_b 调用 fun_a
如果我们需要修改、截获对fun_a 函数调用的参数该怎么做呢?
Definitely 对 fun_a 的调用进行Hook操作,看看Hook后的控制流跳转图:
虽然在fun_hook函数中没有修改、截获fun_a 的参数,但是我们演示了Hook一个函数
的实质。就是修改指令call fun_a 的跳转地址,把它改成我们的Hook函数的地址。
Hook函数想做啥就做啥,可以对原函数调用,也可以不对原函数进行调用,如果要
保证程序在Hook函数调用后能正常继续运行,最好保存下调用Hook函数时的Context现场。
用pushad 和 popad 指令就可以完成咯。
进行Inline Hook并调用原函数需要两个关键地址:
1. 调用原函数的指令位置 。以修改指令跳转到钩子函数.
2.原函数的地址。钩子函数处理完后,调用原函数,保证程序继续正常运行。
下面以Hook某程序中的某个函数调用为例,实战下:
目标:用我的 evil.dll 中的导出函数 Hook_fun 勾住某程序的某个函数调用。
DWORD jmpAddr; //hook 函数结束后跳转的原函数的地址
//获取目标指令地址 和 原函数的地址
DWORD GetHookAddr(void)
{
HMODULE hDll = GetModuleHandle(L"xxnetwork.dll");
jmpAddr = (DWORD)hDll + 0x581C; //hook 函数结束后跳转的原函数的地址
return (DWORD)hDll + 0x42855; //要 Hook 的指令的地址
}
//安装 Inline hook
bool MakeInlineHook(void)
{
//1.获取 hook 地址
DWORD targetAddr = GetHookAddr();
//2.计算相对跳转偏移
HMODULE hDll1 = GetModuleHandle(L"evil.dll");
DWORD HookFunAddr = (DWORD)GetProcAddress(hDll1, "HookFun")+6 - targetAddr - 5; //注意,这里+6是为了跳过 vs2015 为函数生成的保护现场的指令(push ebp,mov ebp,esp)
//-5 是因为call 指令的偏移计算是按照下一条指令的首地址计算的
//3.修改内存属性,并写入hook 代码
DWORD oldP,tmp;
unsigned char code[5];
if (VirtualProtect((LPVOID)targetAddr, 5, PAGE_EXECUTE_READWRITE, &oldP))
{
code[0] = 0xe8; //call 指令opcode
memcpy(&code[1], &HookFunAddr,4); //addr
memcpy((void*)targetAddr, (void*)code, sizeof(code)); //修改代码
VirtualProtect((LPVOID)targetAddr, 5, oldP, &tmp); //还原保护属性
return true;
}
return false;
}
//DLL 导出钩子函数
DLLEXPORT void HookFun(void)
{
_asm {
pushad
//在这里可以截获原函数的参数,修改……
//用你的想象力,随意发挥……
hookRet :
popad
//跳转到原来的函数执行
jmp jmpAddr
}
}
//DLL main 函数,当载入程序的时候按照 Inline Hook
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
MakeInlineHook();
break;
}
}
OK,以上就是Inline hook 的基本介绍,是不是很简单呢~~~