网上大把的inline hook MessageBox的例子,看得是在蛋疼,坑太多,看再多不如自己写一遍来的实际。顺便上传完整的代码上来。
inline hook完成主要分成以下几个部分:
1.定义要HOOK的真实API函数地址类型与声明。
typedef int (WINAPI *SetClipboardData_type)
(
__in UINT uFormat,
__in_opt HANDLE hMem
);
SetClipboardData_type RealSetClipboardDate = NULL;
上面这段的意思是:定义一个名字叫SetClipboardData_type的WINAPI类型返回值是int的函数指针。
2.定义要跳转到我们自己定义的API函数
_declspec(naked) void WINAPI mySetClipboardData(
__in UINT uFormat,
__in_opt HANDLE hMem
)
{
__asm
{
PUSH ebp
mov ebp,esp
push esi
}
//要做的事
//....
//MessageBoxA(NULL,"xxxxxxxxxx!","提示",MB_ICONINFORMATION );
//结束
__asm
{
pop esi
// mov ebx,RealSetClipboardDate
// add ebx,5
// jmp ebx //调回原地址
pop ebx
pop edi
leave
ret 8
}
}
因为当我们调用真正的SetClipboardDate,我们要将之前我们换掉的头部换回来,我们要内联汇编,里面不能含有编译器自动添加的代码,所以在mySetClipboardData头部要加上 _declspec(naked)
3.定义结构体,包含跳转命令和跳转地址。
#pragma pack(1)
typedef struct _JMPCODE
{
BYTE jmp;
DWORD addr;
}JMPCODE,*PJMPCODE;
4.HOOK函数
VOID HookSetClipboardDate()
{
JMPCODE jcode;
jcode.jmp = 0xe9;
jcode.addr = (DWORD)mySetClipboardData - (DWORD)RealSetClipboardDate - 5;
::ReadProcessMemory(GetCurrentProcess(),SetClipboardData,&oldjcode,5,NULL);::WriteProcessMemory(GetCurrentProcess(),SetClipboardData,&jcode,sizeof(JMPCODE),NULL);//写入跳转语句
}
ReadProcessMemory用于保存前5个字节内容,WriteProcessMemory写入跳转语句
5.卸载HOOK的函数钩子
VOID UnHookSetClipboardDate()
{
WriteProcessMemory(GetCurrentProcess(),SetClipboardData,&oldjcode,5,NULL);
}
将原来的5个字节写入源地址
6.DllMain部分
BOOL APIENTRY DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
{
HMODULE hMod = LoadLibraryA("user32.dll");
RealSetClipboardDate = (SetClipboardData_type)GetProcAddress(hMod,"SetClipboardData");
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
hThread1 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Fun1proc,NULL,0,NULL);
CloseHandle(hThread1);
}
break;
case DLL_PROCESS_DETACH:
{
UnHookSetClipboardDate();
//MessageBox(NULL,_T("卸载成功!"),_T("提示"),MB_ICONINFORMATION );
}
break;
}
return TRUE
}