win32相关(IAT HOOK)

发布于:2025-06-08 ⋅ 阅读:(15) ⋅ 点赞:(0)

IAT HOOK


什么是IAT Hook?

IAT Hook(Import Address Table Hook,导入地址表钩子)是一种Windows平台下的API钩取技术,通过修改目标程序的导入地址表(IAT)来拦截和重定向API调用

在我们之前学习pe文件结构的导入表时,有讲到过IMAGE_IMPORT_DESCRIPTOR这个结构体,其中有个FirstThunk参数,这个参数是指在程序运行中,存放着要执行的函数地址

在这里插入图片描述
我们在调用MessageBox这类的函数时,在程序运行时,会把函数的地址放到IAT表当中,我们就是通过修改这个执行的地址来达到我们Hook的目的

我们来代码实践一下

注入的dll模块

#include<iostream>
#include<windows.h>


#ifdef _WIN64
#define IMAGE_ORDINAL_FLAG 0x8000000000000000
#else
#define IMAGE_ORDINAL_FLAG 0x80000000
#endif

PDWORD_PTR g_pIatEntry = NULL;      // 指向IAT条目
DWORD_PTR g_origMessageBoxW = 0;    // 原始函数地址
DWORD g_dwOldProtect = 0;

// 编写我们要替换的函数(hook的函数)
int WINAPI HookMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) {
	return MessageBoxA(hWnd, "MessageBox已被Hook!", "HOOK", uType);
}

// 安装钩子
BOOL InstallHook() {

	if (!g_pIatEntry) return FALSE;

	// 保存原始地址
	g_origMessageBoxW = *g_pIatEntry;

	// 修改内存属性,改为可以读可以写,可以执行
	VirtualProtect(g_pIatEntry, sizeof(PDWORD_PTR), PAGE_EXECUTE_READWRITE, &g_dwOldProtect);
	// 这里填写我们想要替换的函数的地址
	*g_pIatEntry = (DWORD_PTR)HookMessageBoxW;
	// 还原之前的内存属性
	VirtualProtect(g_pIatEntry, sizeof(PDWORD_PTR), g_dwOldProtect, NULL);
	return TRUE;
}
// 卸载钩子
BOOL UnInstallHook() {

	if (!g_pIatEntry || !g_origMessageBoxW) return FALSE;

	// 修改内存属性,改为可以读可以写,可以执行
	VirtualProtect(g_pIatEntry, sizeof(PDWORD_PTR), PAGE_EXECUTE_READWRITE, &g_dwOldProtect);
	*g_pIatEntry = (DWORD_PTR)g_origMessageBoxW;
	// 还原之前的内存属性
	VirtualProtect(g_pIatEntry, sizeof(PDWORD_PTR), g_dwOldProtect, NULL);
	return TRUE;
}

PDWORD_PTR GetIatAddr(PCSTR dllName, PCSTR dllFunName) {
	// 获取当前进程的模块句柄
	HMODULE hModule = GetModuleHandle(0);
	DWORD_PTR dwHModule = (DWORD_PTR)hModule;
	// 获取DOS头
	PIMAGE_DOS_HEADER pDOsHeader = (PIMAGE_DOS_HEADER)dwHModule;
	// 获取NT头
	PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(dwHModule + pDOsHeader->e_lfanew);
	// 获取可选PE头
	PIMAGE_OPTIONAL_HEADER pOptHeader = (PIMAGE_OPTIONAL_HEADER)&pNtHeader->OptionalHeader;
	// 获取数据目录表
	PIMAGE_DATA_DIRECTORY pDataDir = (PIMAGE_DATA_DIRECTORY)&pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
	// 在硬盘中需要转换,在内存中不需要转换 获取导入表地址
	PIMAGE_IMPORT_DESCRIPTOR pImageImportTable = (PIMAGE_IMPORT_DESCRIPTOR)(dwHModule + pDataDir->VirtualAddress);
	// 遍历导入表获取符合条件的函数
	while (pImageImportTable->Name) {
		PCHAR iatDllName = (PCHAR)pImageImportTable->Name + dwHModule;
		// 找到了我们需要的Hook的dll
		if (_stricmp(dllName, iatDllName) == 0) {
			// 获取导入名称表 获取函数名称
			PIMAGE_THUNK_DATA pThunkINT = (PIMAGE_THUNK_DATA)(dwHModule + pImageImportTable->OriginalFirstThunk);
			// 获取导入地址表 获取函数地址
			PIMAGE_THUNK_DATA pThunkIAT = (PIMAGE_THUNK_DATA)(dwHModule + pImageImportTable->FirstThunk);
			while (pThunkINT->u1.Function) {
				// 判断是不是按名称来导入的
				if ((pThunkINT->u1.Ordinal & IMAGE_ORDINAL_FLAG) == 0) {

					PIMAGE_IMPORT_BY_NAME pImageImportByname = (PIMAGE_IMPORT_BY_NAME)(pThunkINT->u1.Function + dwHModule);

					// 忽略大小写比较方法名称
					if (strcmp(dllFunName, pImageImportByname->Name) == 0) {
						// 找到到函数了返回函数地址
						return (PDWORD_PTR)pThunkIAT;
					}
				}
				pThunkINT++;
				pThunkIAT++;
			}
		}
		pImageImportTable++;
	}
}

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwCallReason, LPVOID lpReserved) {
	if (dwCallReason == DLL_PROCESS_ATTACH) {
		// 获取ida表函数地址
		g_pIatEntry = GetIatAddr("user32.dll", "MessageBoxW");
		InstallHook();
	}
	else if (dwCallReason == DLL_PROCESS_DETACH){
		// 进程退出时卸载钩子
        UnInstallHook();
	}
	return TRUE;
}

我这边提前写好了一个小程序,就是点按钮弹出一个MessageBox消息出来

在这里插入图片描述

我们来Hook掉弹窗中的内容

用到我们之前写dll注入的程序,执行一下

在这里插入图片描述
可以看到,我们已经返了我们修改后的弹窗

注:在MFC或者其他的库中,弹窗的函数可能实际上并不是MessageBoxW,像MFC是对MessageBox又做了一层封装,导致我们Hook不到


网站公告

今日签到

点亮在社区的每一天
去签到