IAT HOOK

13 篇文章 2 订阅

最近需要用到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);
}

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

效果截图:














  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

friendan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值