HOOK IAT 代码示例

// include
#include "stdio.h"
#include "wchar.h"
#include "windows.h"


// typedef
typedef BOOL(WINAPI* PFSETWINDOWTEXTW)(HWND hWnd, LPWSTR lpString);


// globals
FARPROC g_pOrgFunc = NULL;


// 
BOOL WINAPI MySetWindowTextW(HWND hWnd, LPWSTR lpString)
{
	wchar_t* pNum = (wchar_t*)L"零一二三四五六七八九";
	wchar_t temp[2] = { 0, };
	int i = 0, nLen = 0, nIndex = 0;

	nLen = wcslen(lpString);
	for (i = 0; i < nLen; i++)
	{
		// 将阿拉伯数字转换为中文数字
		//   lpString 是 wide-character (2 byte) 字符串
		if (L'0' <= lpString[i] && lpString[i] <= L'9')
		{
			temp[0] = lpString[i];
			nIndex = _wtoi(temp);
			lpString[i] = pNum[nIndex];
		}
	}

	// 调用user32!SetWindowTextW() API 
	//   (修改 lpString 缓冲区中的内容)
	return ((PFSETWINDOWTEXTW)g_pOrgFunc)(hWnd, lpString);
}


// hook_iat
// 
//  
BOOL hook_iat(LPCSTR szDllName, PROC pfnOrg, PROC pfnNew)
{
	HMODULE hMod;
	LPCSTR szLibName;
	PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
	PIMAGE_THUNK_DATA pThunk;
	DWORD dwOldProtect, dwRVA;
	PBYTE pAddr;

	// hMod, pAddr = ImageBase of calc.exe
	//             = VA to MZ signature (IMAGE_DOS_HEADER)
	hMod = GetModuleHandle(NULL);
	pAddr = (PBYTE)hMod;

	// pAddr = VA to PE signature (IMAGE_NT_HEADERS)
	pAddr += *((DWORD*)& pAddr[0x3C]);

	// dwRVA = RVA to IMAGE_IMPORT_DESCRIPTOR Table
	dwRVA = *((DWORD*)& pAddr[0x80]);

	// pImportDesc = VA to IMAGE_IMPORT_DESCRIPTOR Table
	pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)hMod + dwRVA);

	for (; pImportDesc->Name; pImportDesc++)
	{
		// szLibName = VA to IMAGE_IMPORT_DESCRIPTOR.Name
		szLibName = (LPCSTR)((DWORD)hMod + pImportDesc->Name);
		if (!_stricmp(szLibName, szDllName))
		{
			// pThunk = IMAGE_IMPORT_DESCRIPTOR.FirstThunk
			//        = VA to IAT(Import Address Table)
			pThunk = (PIMAGE_THUNK_DATA)((DWORD)hMod +
				pImportDesc->FirstThunk);

			// pThunk->u1.Function = VA to API
			for (; pThunk->u1.Function; pThunk++)
			{
				if (pThunk->u1.Function == (DWORD)pfnOrg)
				{
					// 更改内存属性为 E/R/W 
					VirtualProtect((LPVOID)& pThunk->u1.Function,
						4,
						PAGE_EXECUTE_READWRITE,
						&dwOldProtect);

					// 修改 IAT (钩取)
					pThunk->u1.Function = (DWORD)pfnNew;

					// 恢复内存属性
					VirtualProtect((LPVOID)& pThunk->u1.Function,
						4,
						dwOldProtect,
						&dwOldProtect);

					return TRUE;
				}
			}
		}
	}

	return FALSE;
}



BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
	switch (fdwReason)
	{
	case DLL_PROCESS_ATTACH:
		// 保存原始API地址
		g_pOrgFunc = GetProcAddress(GetModuleHandle(L"user32.dll"),
			"SetWindowTextW");

		// # hook
		//   用hookiat!MySetWindowText()钩取 user32!SetWindowTextW()
		hook_iat("user32.dll", g_pOrgFunc, (PROC)MySetWindowTextW);
		break;

	case DLL_PROCESS_DETACH:
		// # unhook
		//   calc.exe 的IAT恢复原值
		hook_iat("user32.dll", (PROC)MySetWindowTextW, g_pOrgFunc);
		break;
	}

	return TRUE;
}

  DllMain 判断。  

  存储SetWindowTextW的地址

  hookiat钩取和恢复

  MySetWindowTextW 是对显示内容进行更改。

  为了知道一个可执行文件或DLL文件被加载到进程地址空间的什么位置,可以用GetModuleHandle函数来返回一个句柄/基地址:
  HMODULE GetModuleHandle(PCTSTR pszModule);
 
  调用这个函数时,要传递一个以0为终止的字符串,它指定了已在主调进程的地址空间中加载的一个可执行文件或DLL文件的名称。如果系统找到了指定的可执行文件或DLL文件名称,GetModuleHandle就会返回可执行文件/DLL文件映像加载到的基地址。如果参数为NULL,这样可以返回主调进程的可执行文件的基地址,也就是说即使调用GetModuleHandle(NULL)的代码是在一个DLL文件中,返回值仍是可执行文件的基地址,而非DLL文件的基地址。
 
 代码中很多结构体类型,通过VS2019 可以很方便查看结构体中的具体情况,非常方便,以前排除VS 现在的2019版不可谓不强大啊。
 
这里主要说一下怎么查找到SetWindowWextW的。
  首先 hMod拿到程序的基地址,就是DOS文件开头,然后传给pAddr ,偏移0x3C处的数据就是PE头的位置,也就是0XF0。
再便宜0x80 就是 0x170 ,然后取数据,再次偏移。

拿到 01012B80 看看此处,正好是IDT的开头。

找到这个地址我们将它定义为IDT结构体PIMAGE_IMPORT_DESCRIPTOR。

然后遍历找到user32.dll这个名称,并且拿到IAT的地址,也就是FirstThunk。

给它定义为另一个结构体PIMAGE_THUNK_DATA。这个结构体也就是为IAT而生的。。。

然后遍历寻找Function和我们传进来的参数(也就是SetWindowTextW的地址)相等,这样就找到了这个API。




然后将Function 的值改为MySetWindowText的地址。

修改前要保证有可写权限,

VirtualProtect((LPVOID)& pThunk->u1.Function,
						4,
						PAGE_EXECUTE_READWRITE,
						&dwOldProtect);

BOOL VirtualProtect(
LPVOID lpAddress,
DWORD dwSize,
DWORD flNewProtect,
PDWORD lpflOldProtect
);

各参数的意义为:

lpAddress,要改变属性的内存起始地址。

dwSize,要改变属性的内存区域大小。

flNewProtect,内存新的属性类型,设置为PAGE_EXECUTE_READWRITE(0x40)时该内存页为可读可写可执行。

pflOldProtect,内存原始属性类型保存地址。

修改内存属性成功时函数返回非0,修改失败时返回0。

到此,IAT钩取成功。

如果要恢复的话,将hookiat参数对调即可。

 
原文地址:https://www.cnblogs.com/whitehawk/p/11169227.html