// 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 是对显示内容进行更改。
拿到 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参数对调即可。