导出表钩子之EAT HOOK解析

EAT HOOK与IAT HOOK原理是一样的,都是通过修改PE来达到HOOK的目的。只是EAT HOOK是从来源入手而IAT HOOK则是从自身入手。但有一点值得注意的就是EAT HOOK只能对后面通过动态加载进来的API有效,对原本已经在IAT表中获取的API无法产生效果。

最简单的解释是exe进程大部分都没有导出表

详细的原因在于进程被加载到内存后PE Loader就逐个将导入表的IAT表中的各项从对应dll中获取并且硬编码地址,而进程调用API就是通过查询导入表中的IAT表中的硬编码API地址。这部分是EAT无法影响的因为在进程被加载到内存时就已经决定。

试想一下,EAT HOOK的时机时必须是进程启动后才能注入并影响对应DLL中的导出表。而IAT表早就已经在Loader加载时期就查询对应dll后被硬编码。在那时候EAT HOOK的动态库根本还没有被注入进来。所以只有当用户进行动态加载API时,才有机会。

讲一下大体思路。

1. 通过IMAGE_OPTIONAL_HEADER.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress找到导出表的地址(注意这里是RVA要加上ImageBase才能得到VA,下面都是一样)。与导入表不同,导出表只有一张!

2. 遍历IMAGE_EXPORT_DESCRIPTOR.AddressOfNames(一共IMAGE_EXPORT_DESCRIPTOR.NumberOfNames个)找到被HOOK的API名称。记得与此同时要保存IMAGE_EXPORT_DESCRIPTOR.AddressOfNameOrdinals的值

3. 如果找到了API名称则把IMAGE_EXPORT_DESCRIPOTR.AddressOfFunctions[IMAGE_EXPORT_DESCRIPTOR.AddressOfNameOrdinals]即原函数的RVA地址替换成新函数地址。

#include <windows.h>
#include <cstdio>
#include <tchar.h>

BOOL EATHook(LPCTSTR szDllName, LPCTSTR szFunName, LPVOID NewFun) {
	DWORD addr = 0;
	DWORD index = 0;
	DWORD dwProtect;
	HMODULE hMod = LoadLibrary(szDllName);
	if (NULL == hMod)
		return(FALSE);
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hMod;
	PIMAGE_OPTIONAL_HEADER pOptHeader = (PIMAGE_OPTIONAL_HEADER)((PBYTE)hMod + pDosHeader->e_lfanew + 24);
	PIMAGE_EXPORT_DIRECTORY pExpDes = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)hMod + pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
	PULONG pAddressOfFunctions = (PULONG)((PBYTE)hMod + pExpDes->AddressOfFunctions);
	PULONG pAddressOfNames = (PULONG)((PBYTE)hMod + pExpDes->AddressOfNames);
	PUSHORT pAddressOfNameOrdinals = (PUSHORT)((PBYTE)hMod + pExpDes->AddressOfNameOrdinals);

	for (int i = 0; i < pExpDes->NumberOfNames; ++i) {
		index = pAddressOfNameOrdinals[i];
		LPCTSTR pFuncName = (LPTSTR)((PBYTE)hMod + pAddressOfNames[i]);
		if (!_tcscmp((LPCTSTR)pFuncName, szFunName)) {
			addr = pAddressOfFunctions[index];
			break;
		}
	}
	VirtualProtect(&pAddressOfFunctions[index], 0x1000, PAGE_READWRITE, &dwProtect);
	pAddressOfFunctions[index] = (DWORD)NewFun - (DWORD)hMod;
	WriteProcessMemory(GetCurrentProcess(), &pAddressOfFunctions[index], (LPCVOID)((DWORD)NewFun - (DWORD)hMod), sizeof(NewFun), &dwProtect);

	return(TRUE);
}

int __stdcall MyMessageBox(
	HWND    hWnd,
	LPCTSTR lpText,
	LPCTSTR lpCaption,
	UINT    uType
) {
	_tprintf("Hello, world!\n");

	return(0);
}

typedef int (WINAPI* LPFNMESSAGEBOX)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);

int _tmain() {
	EATHook("USER32.dll", "MessageBoxA", MyMessageBox);
	HMODULE hDll = GetModuleHandle("USER32.dll");
	LPFNMESSAGEBOX lpMessageBox = (LPFNMESSAGEBOX)GetProcAddress(hDll, "MessageBoxA");
	if (NULL == lpMessageBox)
		return(-1);
	lpMessageBox(NULL, "Hello, EAT Hook", "Info", MB_OK);

	return(0);
}

可以将EAT HOOK写成DLL并通过远程线程注入或者利用全局HOOK注入到目标进程中执行。

(完)

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Kiopler

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值