在程序执行前,PE
中的 IAT
表中存储的是指向函数的函数名;当程序真正加载时,操作系统才会将函数地址更新并修改 IAT
表,此时的 IAT
表中存储的是函数的地址。由于 dll
程序加载时,可能存在其加载地址和 ImageBase
不同,而且并不是 dll
中所有的函数都会被使用。因此,指在函数被调用时更新其函数地址,更加高效和安全。
IAT Hook
的思想就是,将 IAT
表中的函数地址进行修改,指向我们自己编写的函数地址。我们在自己编写的函数中再调用被篡改的函数,以实现该程序功能的正常实现。我们可以在自己的函数中实现监控该程序调用被 Hook
的函数的参数、返回值,修改其参数和返回值,以达到特殊的目的。
测试代码如下:
#include <stdio.h>
#include <windows.h>
LPVOID srcFuncAddr;
LPVOID lpImageBuff;
DWORD fileSize;
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_FILE_HEADER pPEHeader;
PIMAGE_OPTIONAL_HEADER32 pOptionalHeader;
PIMAGE_SECTION_HEADER pSectionHeader;
PIMAGE_DATA_DIRECTORY dataDir;
typedef int (WINAPI *PFUNC)(HWND,LPSTR,LPSTR,UINT);
BOOL GetPEHeader(LPVOID pImageBuffer)
{
pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
//判断是否是有效的MZ标志
if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
{
printf("不是有效的PE文件!\n正在退出PE解析...\n");
// free(pImageBuffer);
return FALSE;
}
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + (DWORD)pDosHeader->e_lfanew + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pPEHeader->SizeOfOptionalHeader);
//指向首个目录表, 即导出表
dataDir = (PIMAGE_DATA_DIRECTORY)((DWORD)pOptionalHeader + 0x60);
return TRUE;
};
VOID IATHook(LPVOID srcFuncAddr, LPVOID dstFuncAddr, BOOL isSet)
{
HMODULE hModule;
PIMAGE_IMPORT_BY_NAME importByName;
//获取ImageBuffer的信息
GetPEHeader(lpImageBuff);
//指向导入表
dataDir += 1;
if (dataDir != 0x00)
{
PIMAGE_IMPORT_DESCRIPTOR importDir = (PIMAGE_IMPORT_DESCRIPTOR)(dataDir->VirtualAddress + (DWORD)lpImageBuff);
/*遍历导入表*/
while (*(DWORD*)importDir != 0x0)
{
/*遍历FirstThunk*/
DWORD* pFirstThunk = (DWORD*)(importDir->FirstThunk + (DWORD)lpImageBuff);
//判断IAT表是否已经绑定
BOOL isBind = (importDir->TimeDateStamp == 0) ? FALSE : TRUE;
while (!isBind)
{
//判断FirstThunk是否结束
if (*pFirstThunk == 0x00)
{
break;
}
//获取导入表DLL名
LPSTR lpszNameOfDll = (LPSTR)(importDir->Name + (DWORD)lpImageBuff);
//加载DLL模块
hModule = LoadLibraryA(lpszNameOfDll);
DWORD FirstThunk = *pFirstThunk;
//判断OriginalFirstThunk是否指向函数名
if (FirstThunk >> 31 != 0x01)
{
if (FirstThunk == (DWORD)srcFuncAddr || FirstThunk == (DWORD)dstFuncAddr)
{
//设置Hook
if (isSet)
{
*pFirstThunk = (DWORD)dstFuncAddr;
}
//卸载Hook
else
{
//DWORD* FirstThunkOfINT = (DWORD*)(importDir->OriginalFirstThunk + (DWORD)lpImageBuff);
//importByName = (PIMAGE_IMPORT_BY_NAME)(*FirstThunkOfINT + (DWORD)lpImageBuff);
//printf("%s\n", (CHAR*)importByName->Name);
//*pFirstThunk = (DWORD)GetProcAddress(hModule, (CHAR*)importByName->Name);
*pFirstThunk = (DWORD)srcFuncAddr;
}
}
}
pFirstThunk++;
}
importDir++;
}
}
}
int WINAPI MyFuncProc(HWND hWnd,LPSTR lpText,LPSTR lpCaption,UINT uType)
{
printf("MessageBox参数如下:\n");
printf("hWnd: %x, lpText: %s, lpCaption: %s, uType: %u\n", hWnd, lpText, lpCaption, uType);
PFUNC pfunc = (PFUNC)srcFuncAddr;
pfunc(NULL, "这是被IAT HOOK后的MessageBox!", "提示", MB_OK);
return 0;
}
int main()
{
srcFuncAddr = MessageBox;
//获取PE信息
lpImageBuff = GetModuleHandle(NULL);
//设置IAT Hook
IATHook(srcFuncAddr, MyFuncProc, TRUE);
MessageBox(NULL, "设置IAT Hook!", "提示", MB_OK);
//卸载IAT HOOk
IATHook(srcFuncAddr, MyFuncProc, FALSE);
MessageBox(NULL, "卸载IAT HOOk!", "提示", MB_OK);
return 0;
}
效果图如下: