描述
- 拦截messagebox函数,调用自己的MyMessageBox,然后再调用原函数
原理
- 本文进行了针对程序输入表的address hook,通过GetProcAddress获取原messagebox的地址,通过比对IAT内的地址,找到存放messagebox的项,将其替换为MyMessageBox的地址
- 将MyMessageBox实现的代码放到dll中,注入到目标程序中使用,在MyMessageBox函数的最后调用了原messagebox,实现Detour
步骤
- 编写dll,这里随便加了一个导出函数MyTestFunc,用于注入
#include <windows.h>
#include <cstdio>
//创建相同函数指针.
typedef int (WINAPI* PfnMsgA)(
_In_opt_ HWND hWnd,
_In_opt_ LPCSTR lpText,
_In_opt_ LPCSTR lpCaption,
_In_ UINT uType);
PfnMsgA g_OldPfnMsgA = nullptr;
int WINAPI MyMessageBox(_In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText, _In_opt_ LPCSTR lpCaption, _In_ UINT uType)
{
char sz1[] = "检测到原来的输出为:";
char sz2[] = "\n将输出修改为:进入游戏失败哈哈!";
strcat(sz1, (char*)lpText);
strcat(sz1, sz2);
if (g_OldPfnMsgA != nullptr)
{
return g_OldPfnMsgA(hWnd, sz1, lpCaption, uType);//调用以前的
}
return 0;
}
void SetIatHook()
{
MessageBoxA(NULL, "开始进行HOOK", "提示", NULL);
PVOID pHookAddress = nullptr;
pHookAddress = GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA"); //你要HOOK的函数.
if (nullptr == pHookAddress)
{
OutputDebugString(TEXT("获取函数地址失败"));
MessageBoxA(NULL, "获取函数地址失败HOOK", NULL, NULL);
return;
}
printf("msgbox函数地址为:%llx", pHookAddress);
g_OldPfnMsgA = (PfnMsgA)pHookAddress; //保存旧的函数指针.
//解析PE头.寻找IAT.
HMODULE hModImageBase = GetModuleHandle(NULL);//获取当前的ImagBase
PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)(DWORD_PTR)hModImageBase; //获取DOS头
DWORD_PTR dwTemp = (DWORD_PTR)pDosHead + (DWORD_PTR)pDosHead->e_lfanew;
PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)dwTemp;
PIMAGE_FILE_HEADER pFileHead = (PIMAGE_FILE_HEADER)&pNtHead->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHead = (PIMAGE_OPTIONAL_HEADER)&pNtHead->OptionalHeader;
//寻找导出表的位置.
DWORD_PTR dwExportLocal = pOptHead->DataDirectory[1].VirtualAddress; //找到导出表偏移.
//定位到导出表
dwTemp = (DWORD_PTR)GetModuleHandle(NULL) + dwExportLocal;
PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)dwTemp;
PIMAGE_IMPORT_DESCRIPTOR pCurrent = pImport;
DWORD_PTR* pFirstThunk; //导入表子表,也就是IAT存储函数地址的表.
//遍历导入表
while (pCurrent->Characteristics && pCurrent->FirstThunk != NULL)
{
dwTemp = pCurrent->FirstThunk + (DWORD_PTR)GetModuleHandle(NULL);//找到导入表
pFirstThunk = (DWORD_PTR*)dwTemp; //加上偏移才是真正的导入表.
while (*(DWORD_PTR*)pFirstThunk != NULL)
{
//遍历子表
if (*(DWORD_PTR*)pFirstThunk == (DWORD_PTR)g_OldPfnMsgA)
{
//找到要修改的导入表了//修改内存保护属性.写入我们新的函数地址.
DWORD oldProtected;
VirtualProtect(pFirstThunk, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected);
dwTemp = (DWORD_PTR)MyMessageBox;
memcpy(pFirstThunk, (DWORD_PTR*)&dwTemp, 8); //将变量中保存的函数地址拷贝到导入表中.
VirtualProtect(pFirstThunk, 0x1000, oldProtected, &oldProtected);
MessageBoxA(NULL, "修改函数完毕!", "提示", NULL);
}
pFirstThunk++; //继续遍历.
}
pCurrent++; //每次是加一个导入表结构.
}
}
void UnIatHook()
{
/*
1.遍历导入表.恢复导入表即可.
*/
MessageBoxA(NULL, "开始进行HOOK", NULL, NULL);
PVOID64 pHookAddress = nullptr;
pHookAddress = MyMessageBox;
if (nullptr == pHookAddress)
{
OutputDebugString(TEXT("获取函数地址失败"));
MessageBoxA(NULL, "恢复函数地址失败HOOK", NULL, NULL);
return;
}
//解析PE头.寻找IAT.
HMODULE hModImageBase = GetModuleHandle(NULL);//获取当前的ImagBase
PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)(DWORD)hModImageBase; //获取DOS头
DWORD dwTemp = (DWORD)pDosHead + (DWORD)pDosHead->e_lfanew;
PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)dwTemp;
PIMAGE_FILE_HEADER pFileHead = (PIMAGE_FILE_HEADER)&pNtHead->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHead = (PIMAGE_OPTIONAL_HEADER)&pNtHead->OptionalHeader;
//寻找导出表的位置.
DWORD dwExportLocal = pOptHead->DataDirectory[1].VirtualAddress; //找到导出表偏移.
//定位到导出表
dwTemp = (DWORD)GetModuleHandle(NULL) + dwExportLocal;
PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)dwTemp;
PIMAGE_IMPORT_DESCRIPTOR pCurrent = pImport;
DWORD* pFirstThunk; //导入表子表
//遍历导入表
while (pCurrent->Characteristics && pCurrent->FirstThunk != NULL)
{
dwTemp = pCurrent->FirstThunk + (DWORD)GetModuleHandle(NULL);
pFirstThunk = (DWORD*)dwTemp; //加上偏移才是真正的导入表.
while (*(DWORD*)pFirstThunk != NULL)
{
//遍历子表
if (*(DWORD*)pFirstThunk == (DWORD)MyMessageBox) //如果是我们的函数地址.则进行恢复.
{
//找到要修改的导入表了//修改内存保护属性.写入我们新的函数地址.
DWORD oldProtected;
VirtualProtect(pFirstThunk, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected);
dwTemp = (DWORD)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");
memcpy(pFirstThunk, (DWORD*)&dwTemp, 4); //将变量中保存的函数地址拷贝到导入表中.
VirtualProtect(pFirstThunk, 0x1000, oldProtected, &oldProtected);
}
pFirstThunk++; //继续遍历.
}
pCurrent++; //每次是加一个导入表结构.
}
}
extern "C" __declspec(dllexport) int MyTestFunc(int a, int b)
{
return a + b;
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
SetIatHook();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
- 通过PE Tools修改原程序输入表,注入dll
效果
- 将HookMsg.dll放到原程序目录下,运行原程序,成功拦截原messagebox调用