最近需要用到IAT HOOK,为方便自己,参考了网上的例子,自己封装成了一个类。

首先是PE头定义,文件PE.h

#ifndef _PE_H_
#define _PE_H_
#include <Windows.h>


/**************************************/
/* PE DOS头,占64个字节, */
/* 我们只关心e_magic和e_lfanew */
/**************************************/
typedef struct tagIMAGE_DOS_HEADER
{
byte e_magic[2]; // 4D(M) 5A(Z) 2字节
byte bXX[58];
int e_lfanew; // 4字节
} MY_IMAGE_DOS_HEADER;


/********************************************
/* 数据目录表结构 */
/********************************************/
typedef struct tagIMAGE_DATA_DIRECTORY
{
int VirtualAddress;
int Size;
} MY_IMAGE_DATA_DIRECTORY;


/************************************************************************/
/* PE头,占4+20+224=248个字节 */
/* 我们只关心Signature和数据目录表 */
/************************************************************************/
typedef struct tagIMAGE_PE_HEADER
{
byte Signature[4]; // 4个字节:50(P) 45(E) 00 00
byte bXXX[20]; // IMAGE_FILE_HEADER
byte bYYY[96]; // 可选头前面96个字节,我们不关心
MY_IMAGE_DATA_DIRECTORY DataDirectory[16];
} MY_IMAGE_PE_HEADER;


/************************************************************************/
/* 映像输入结构,一个这样的结构表示一个DLL */
/************************************************************************/
typedef struct tagIMAGE_IMPORT_DESCRIPTOR
{
int OriginalFirstThunk; // 原始的IAT,存放导入的API名字
int TimeDateStamp;
int ForwarderChain;
int Name; // 存放导入的DLL名字所在的内存起始RVA地址
int FirstThunk; // 导入该DLL的第一个API接口地址
} MY_IMAGE_IMPORT_DESCRIPTOR;


/************************************************************************/
/* THUNK不好翻译呀,一个这样的结构表示一个API输入信息 */
/************************************************************************/
typedef struct tagIMAGE_THUNK_DATA32
{
int AddressOfData;
} MY_IMAGE_THUNK_DATA32;



#endif // _PE_H_


----------------------------------------------------------------

我的IAT HOOK类头文件:IAT.h

#pragma once
#include "PE.h"


class CIAT
{
public:
CIAT(void);
~CIAT(void);

int Hook(int hModule, char *pszDll, char *pszApiName, int iNewApiAddr);
void UnHook(void);

private:
int GetImageImportDescriptorAddr(int hModule); // 获取指定模块的IAT表入口地址
int GetApiIatAddr(int hModule, MY_IMAGE_IMPORT_DESCRIPTOR* pIID, char *pszApiName);
private:
MY_IMAGE_DOS_HEADER m_dosHeader;
MY_IMAGE_PE_HEADER m_peHeader;
int m_iOldApiAddr;
int m_iHookAddr;
};


----------------------------------

IAT.cpp文件:

#include "StdAfx.h"
#include "IAT.h"


CIAT::CIAT(void)
{
m_iOldApiAddr = 0;
m_iHookAddr = 0;
}


CIAT::~CIAT(void)
{
UnHook();
}

/**
@Name: GetImageImportDescriptorAddr
@Brief 获取指定模块的导入表入口地址
@Param: int hModule 模块句柄,即入口地址
@Return: int
*/
int CIAT::GetImageImportDescriptorAddr(int hModule)
{
int iIatAddTableress = 0;
byte e_magic[2] = {'M', 'Z'};
byte Signature[2] = {'P', 'E'};

// 取DOS头
RtlMoveMemory((void*)&m_dosHeader, (void*)hModule, 64);
if (memcmp(e_magic, m_dosHeader.e_magic, 2) != 0)
{
return 0;
}

// 取PE头
RtlMoveMemory((void*)&m_peHeader, (void*)(hModule + m_dosHeader.e_lfanew), 248);
if (memcmp(Signature, m_peHeader.Signature, 2) != 0)
{
return 0;
}

// VirtualAddress存的是RVA,即相对虚拟地址,所以必须加上模块起始地址
iIatAddTableress = hModule + m_peHeader.DataDirectory[1].VirtualAddress;
return iIatAddTableress;
}


/**
@Name: Hook
@Brief IAT HOOK
@Param: int hModule 一个程序有很多模块,几乎每个模块都有IAT,
这里传你想要HOOK的模块句柄,即入口地址
如果hModule <= 0,则HOOK exe模块的IAT
@Param: char * pszDll 要HOOK的API所在的DLL名字,如User32.dll
@Param: char * pszApiName 要HOOK的API名字,如MessageBoxA
@Param: int iNewApiAddr 你的API地址
@Return: 成功返回旧的API地址,失败返回0
*/
int CIAT::Hook(int hModule, char *pszDll, char *pszApiName, int iNewApiAddr)
{
if (pszDll == NULL || pszApiName == NULL || iNewApiAddr <= 0)
{
return 0;
}
UnHook();

hModule = hModule > 0 ? hModule : (int)GetModuleHandle(NULL);
int iIIDAddr = GetImageImportDescriptorAddr(hModule);
if (iIIDAddr <= 0)
{
return 0;
}

MY_IMAGE_IMPORT_DESCRIPTOR *pIID = (MY_IMAGE_IMPORT_DESCRIPTOR*)iIIDAddr;
while(pIID != NULL)
{
// 最后一个IID数据全为0
static int iIIDEnd[5] = {0};
if (memcmp(pIID, iIIDEnd, 20) == 0)
{
break;
}

// 判断下是不是我们要HOOK的DLL
char* dllName = (char*)(hModule + pIID->Name);
if(dllName == NULL || stricmp(dllName, pszDll) != 0)
{
pIID++;
continue;
}

// 获取好HOOK的API地址
m_iHookAddr = GetApiIatAddr(hModule, pIID, pszApiName);
if (m_iHookAddr <= 0)
{
return 0;
}

DWORD dwOldProtect = 0;
VirtualProtect((LPVOID)m_iHookAddr, 4, PAGE_READWRITE, &dwOldProtect);
m_iOldApiAddr = *(int*)m_iHookAddr;
*(int*)m_iHookAddr = iNewApiAddr;
//WriteProcessMemory(GetCurrentProcess(), (LPVOID)m_iHookAddr, &iNewApiAddr, 4, NULL);
VirtualProtect((LPVOID)m_iHookAddr, 4, dwOldProtect, &dwOldProtect);

return m_iOldApiAddr;
}

return 0;
}

void CIAT::UnHook(void)
{
if (m_iHookAddr <= 0)
{
return;
}

DWORD dwOldProtect = 0;
VirtualProtect((LPVOID)m_iHookAddr, 4, PAGE_READWRITE, &dwOldProtect);
*(int*)m_iHookAddr = m_iOldApiAddr;
//WriteProcessMemory(GetCurrentProcess(), (LPVOID)m_iHookAddr, &m_iHookAddr, 4, NULL);
VirtualProtect((LPVOID)m_iHookAddr, 4, dwOldProtect, &dwOldProtect);
}


/**
@Name: GetApiIatAddr
@Brief 取指定API的IAT地址
@Param: int hModule
@Param: MY_IMAGE_IMPORT_DESCRIPTOR * pIID
@Param: char * pszApiName
@Return: int
*/
int CIAT::GetApiIatAddr(int hModule, MY_IMAGE_IMPORT_DESCRIPTOR* pIID, char *pszApiName)
{
if (hModule <=0 || pIID == NULL || pszApiName == NULL)
{
return 0;
}

MY_IMAGE_THUNK_DATA32 *pThunkData = NULL;
int *pIAT = NULL;
pThunkData = (MY_IMAGE_THUNK_DATA32 *)(hModule + pIID->OriginalFirstThunk);
pIAT = (int *)(hModule + pIID->FirstThunk);

while(pThunkData != NULL && pThunkData->AddressOfData != NULL)
{
// 判断是否是以函数名字的方法导入
// 0表示以名字方式导入
// 1表示已序号方式导入
if ((pThunkData->AddressOfData & 0x80000000) == 0)
{
char* functionname = (char*)(hModule+pThunkData->AddressOfData + 2);
if (stricmp(functionname, pszApiName) == 0)
{
return (int)pIAT;
}
}

pThunkData++;
pIAT++;
}
return 0;
}


----------------------------------------

类编写完毕,测试代码如下:

CIAT g_IAT;
typedef int (WINAPI *PFN_MessageBoxA)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
PFN_MessageBoxA pfnMessageBoxA = NULL;

int
WINAPI
MyMessageBoxA(
__in_opt HWND hWnd,
__in_opt LPCSTR lpText,
__in_opt LPCSTR lpCaption,
__in UINT uType)
{
return pfnMessageBoxA(hWnd, "Hello rrr", "you are xxx", uType);
}


// 导入表
void CPE_TestDlg::OnBnClickedBtnImportTable()
{
pfnMessageBoxA = (PFN_MessageBoxA)m_IAT.Hook(NULL, "User32.dll", "MessageBoxA", (int)MyMessageBoxA);
}


-------------------------------------------------

效果截图:

IAT HOOK_VC