IAT Hook 本质就是将PE的导入表中的IAT中指定函数的地址进行替换,从而实现Hook。
我的IAT Hook 是配合CreateRemoteThread进行注入Hook的。关于CreateRemoteThread请参照:CreateRemoteThread
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <tlhelp32.h>
#include <imagehlp.h>
#pragma comment (lib, "imagehlp")
#include <tchar.h>
typedef int (WINAPI *PfnMsgW)(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType);
PfnMsgW __OldPfnMsgW = nullptr;
BOOL HookAPI(LPCSTR HookModule, LPCSTR HookFuncName, PfnMsgW HookFuncs);
int WINAPI MyMessageBox(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType)
{
if (__OldPfnMsgW != nullptr)
{
return __OldPfnMsgW(hWnd, L"HookSuccess", lpCaption, uType);//调用以前的
}
return 0;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
HookAPI("user32.dll", "MessageBoxW", MyMessageBox);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
BOOL HookAPI(LPCSTR HookModule, LPCSTR HookFuncName, PfnMsgW HookFuncs)
{
//HookAddress = user32.dll!0x766a2530 (加载符号以获取其他信息)
LPVOID HookAddress = GetProcAddress(GetModuleHandleA(HookModule), HookFuncName);
__OldPfnMsgW = (PfnMsgW)HookAddress; //保存旧的函数指针.
//在DLL内部调用GetModuleHandle(NULL),获取的是主模块(EXE)基址
//ModuleHandle = test.exe!0x00380000 {unused = 0x00905a4d }
HMODULE ModuleHandle = GetModuleHandle(NULL);
ULONG ModuleSize = 0;
PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(ModuleHandle,
TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT,
&ModuleSize);
DWORD Temp;
PIMAGE_IMPORT_DESCRIPTOR CurrentImportTable = pImport;
DWORD *FirstThunk; //导入表子表,也就是IAT,存储函数地址的表.
//遍历导入表
while (CurrentImportTable->Characteristics && CurrentImportTable->FirstThunk != NULL)
{
Temp = CurrentImportTable->FirstThunk + (DWORD)GetModuleHandle(NULL);
FirstThunk = (DWORD *)Temp;
while (*FirstThunk != NULL)
{
//遍历子表
if (*FirstThunk == (DWORD)__OldPfnMsgW)
{
//找到要修改的导入表了//修改内存保护属性.写入我们新的函数地址.
DWORD oldProtected;
VirtualProtect(FirstThunk, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected);
Temp = (DWORD)MyMessageBox;
memcpy(FirstThunk, (DWORD *)&Temp, 4); //将变量中保存的函数地址拷贝到导入表中.
VirtualProtect(FirstThunk, 0x1000, oldProtected, &oldProtected);
}
FirstThunk++; //继续遍历.
}
CurrentImportTable++; //每次是加一个导入表结构.
}
return TRUE;
}
写的过程中遇到以下一些问题。
1.ImageDirectoryEntryToData的头文件和链接库
2.在DLL内部调用GetModuleHandle(NULL),获取的是主模块(EXE)基址
最开始我还用模块快照的方式获得的基址,想想都觉得hhh。
3.在遍历IAT时,注意指针的转换。