IAT HOOK
首先IAT(Import Address Table)是一个表,叫导入地址表表,也是就是一个存放导入函数地址的表,dll文件中需要使用的函数地址都会存放到这个表里面,PE文件在硬盘中存储的时候,也就是在没有加载到内存的时候,这个表和INT表的内容一样都是存放的一个需要用到的函数的名称,当被加载进内存时是一个可执行状态时,IAT表会被修复,IAT表会根据函数名称转换成真正的函数地址
IAT HOOK就是通过修改IAT表的地址,来实现HOOK,也就是把这个函数地址改为自己写的函数的地址
实现IAT HOOK的流程
1 通过PE文件格式,得到INT和IAT,然后利用IAT的函数名称对比得到函数地址
2 写自己的函数
3 设置钩子把函数地址的地址改为自己函数的地址
4 卸载钩子把函数地址还原
代码实现IAT HOOK
#include<Windows.h>
#include<iostream>
using namespace std;
DWORD* g_IatAddr = NULL;
DWORD* g_unHookAddr = NULL;
int WINAPI HookMessageBoxW(
HWND hWnd,
LPCWSTR lpText,
LPCWSTR lpCaption,
UINT uType
);
BOOL InstallHook();
BOOL unInstallHook();
DWORD* GetIatAddr(const char* DllName, const char* FuncName);
int WINAPI HookMessageBoxW(
HWND hWnd,
LPCWSTR lpText,
LPCWSTR lpCaption,
UINT uType
)
{
int result = MessageBoxA(NULL, "IAT HOOK成功", "IAT HOOK", MB_OK);
return result;
}
//解析导入表函数
//安装钩子
BOOL InstallHook()
{
//修改内存属性为可写
DWORD dwOldProtect = 0;
VirtualProtect(g_IatAddr, 4, PAGE_EXECUTE_READWRITE,&dwOldProtect);
//修改函数地址
*g_IatAddr = (DWORD)HookMessageBoxW;
//修改内存属性为原属性
VirtualProtect(g_IatAddr, 4, dwOldProtect, &dwOldProtect);
return TRUE;
}
//卸载钩子
BOOL unInstallHook()
{
//修改内存属性为可写
DWORD dwOldProtect = 0;
VirtualProtect(g_IatAddr, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect);
//还原修改函数地址
g_IatAddr = g_unHookAddr;
//修改内存属性为原属性
VirtualProtect(g_IatAddr, 4, dwOldProtect, &dwOldProtect);
return TRUE;
}
//第一步获取要替换的函数的地址
DWORD* GetIatAddr(const char* DllName,const char *FuncName)
{
HMODULE hModule = GetModuleHandleA(0);//获取进程EXE模块句柄
DWORD dwhModule = (DWORD)hModule;//把hModule转为DWORD类型的地址
//首先要解析PE文件得到导入表
//拿到DOS头
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)dwhModule;
//拿到PE头
PIMAGE_NT_HEADERS pNtHeader= PIMAGE_NT_HEADERS((DWORD)pDosHeader->e_lfanew + dwhModule);
//拿到可选PE头
PIMAGE_OPTIONAL_HEADER pOptionalHeader=&(pNtHeader->OptionalHeader);
//拿到数据目录表的结构体
IMAGE_DATA_DIRECTORY directory = pOptionalHeader->DataDirectory[1];
//获取导入表结构体
PIMAGE_IMPORT_DESCRIPTOR pImportTable = PIMAGE_IMPORT_DESCRIPTOR(directory.VirtualAddress + dwhModule);
//首先需要匹配dll文件,因为导入表是有多个的,如果要处理的话可以用偏移是否为0来处理
while (pImportTable->Name)
{
char* IatDllName = (char *)pImportTable->Name + dwhModule;
if (IatDllName == DllName)
{
//如果有说明在这里有这个dll文件
//那么就得到IAT和INT的地址
//获取导入名称表
PIMAGE_THUNK_DATA pInt = PIMAGE_THUNK_DATA(pImportTable->OriginalFirstThunk + dwhModule);
//获取导入地址表
PIMAGE_THUNK_DATA pIat = (PIMAGE_THUNK_DATA)pImportTable->FirstThunk + dwhModule;
//遍历表,比对函数名称
while (pInt->u1.Function)
{
//判断是否是按名称导入的
if (pInt->u1.Ordinal & 0x80000000)
{
//获取函数名称
PIMAGE_IMPORT_BY_NAME pImportName =
(PIMAGE_IMPORT_BY_NAME)(pInt->u1.Function + dwhModule);
if (strcmp(pImportName->Name, FuncName) == 0)
{
//表示找到了这个函数PIMAGE_THUNK_DATA结构体
return (DWORD*)pIat;
}
}
pInt++;
pIat++;
}
}
pImportTable++;
}
}
BOOL WINAPI DllMain(HINSTANCE hInstance,DWORD CallReason,LPVOID lpReserve)
{
if (CallReason == DLL_PROCESS_ATTACH)
{
//获取要替换的函数的地址
g_IatAddr = GetIatAddr("user32.dll", "MessageBoxW");
//保存要HOOK的函数地址
g_unHookAddr = g_IatAddr;
//安装钩子
InstallHook();
}
else if(CallReason == DLL_PROCESS_DETACH)
{
//卸载钩子
unInstallHook();
}
return TRUE;
}