4.4 EAT Hook 挂钩技术

简介: EAT(Export Address Table)用于修改动态链接库(DLL)中导出函数的调用。与`IAT Hook`不同,EAT Hook是在DLL自身中进行钩子操作,而不是修改应用程序的导入表。它的原理是通过修改DLL的导出函数地址,将原本要导出的函数指向另一个自定义的函数。这样,在应用程序调用DLL的导出函数时,实际上会执行自定义的函数。与IAT不同是EAT存放的不是函数地址,而是导出函数地址的偏移,使用时需要加上指定Dll的模块基地址,当Hook挂钩之后,所有试图通过导出表获取函数地址的行为都会受到影响,EATHook并不会直接生效,它只能影响`Hook`之后对该函数地址的获取。

EAT(Export Address Table)用于修改动态链接库(DLL)中导出函数的调用。与IAT Hook不同,EAT Hook是在DLL自身中进行钩子操作,而不是修改应用程序的导入表。它的原理是通过修改DLL的导出函数地址,将原本要导出的函数指向另一个自定义的函数。这样,在应用程序调用DLL的导出函数时,实际上会执行自定义的函数。

EAT Hook的步骤通常包括以下几个步骤:

  • 获取目标DLL的基址:通过模块加载和遍历PE文件的导出表,找到目标DLL的基址。
  • 定位导出函数:根据导出函数的名称或序号,在导出表中找到目标函数的位置。
  • 保存原始函数地址:将目标函数的地址保存下来,以便后续恢复。
  • 修改导出函数地址:将目标函数在导出表中对应的地址修改为自定义函数的地址。
  • 实现自定义函数:编写自定义的函数,该函数会在被钩子函数被调用时执行。
  • 调用原始函数:在自定义函数中,可以选择是否调用原始的被钩子函数。

与IAT不同是EAT存放的不是函数地址,而是导出函数地址的偏移,使用时需要加上指定Dll的模块基地址,当Hook挂钩之后,所有试图通过导出表获取函数地址的行为都会受到影响,EATHook并不会直接生效,它只能影响Hook之后对该函数地址的获取。

实现导出表劫持的详细流程如下所示:

  • 首先获取到DOS头,并加上偏移得到NT头,再通过Nt头得到数据目录表基地址。
  • 数据目录表DataDirectory中的第0个成员指向导出表的首地址,直接拿到导出表的虚拟地址。
  • 循环查找导出表的导出函数是否与我们的函数名称一致,一致则取出导出函数地址。
  • 设置导出函数位置读写属性,将新的导出函数地址写入到该位置

根据上述流程,读者可以很容易的写出导出表劫持代码,如下所示则是完整的代码片段,当运行EATHook时,进程内如果再次获取MessageBox函数的内存地址时则会返回MyMessageBox自定函数地址,此时功能将被替换。

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

// 导出表劫持
BOOL EATHook(LPCTSTR szDllName, LPCTSTR szFunName, LPVOID NewFun)
{
   
   
  DWORD addr = 0, index = 0, dwProtect = 0;

  // 装入模块
  HMODULE DllBase = LoadLibrary(szDllName);
  if (NULL == DllBase)
  {
   
   
    return(FALSE);
  }

  // 得到Dos头NT头数据目录表
  PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)DllBase;
  PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
  PIMAGE_OPTIONAL_HEADER pOptHeader = (PIMAGE_OPTIONAL_HEADER)(&pNtHeader->OptionalHeader);

  // 得到导出表的虚拟地址
  PIMAGE_EXPORT_DIRECTORY pExpDes = (PIMAGE_EXPORT_DIRECTORY)
    ((PBYTE)DllBase + pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

  // 获取导出表的函数地址,函数名称,函数序号
  PULONG pAddressOfFunctions = (PULONG)((PBYTE)DllBase + pExpDes->AddressOfFunctions);
  PULONG pAddressOfNames = (PULONG)((PBYTE)DllBase + pExpDes->AddressOfNames);
  PUSHORT pAddressOfNameOrdinals = (PUSHORT)((PBYTE)DllBase + pExpDes->AddressOfNameOrdinals);

  // 循环查找
  for (int i = 0; i < pExpDes->NumberOfNames; ++i)
  {
   
   
    index = pAddressOfNameOrdinals[i];

    // 得到导出函数名
    LPCTSTR pFuncName = (LPTSTR)((PBYTE)DllBase + pAddressOfNames[i]);

    // 对比函数名
    if (!_tcscmp((LPCTSTR)pFuncName, szFunName))
    {
   
   
      // 返回地址
      addr = pAddressOfFunctions[index];
      break;
    }
  }

  // 设置读写属性
  VirtualProtect(&pAddressOfFunctions[index], 0x1000, PAGE_READWRITE, &dwProtect);

  // 设置导出函数
  pAddressOfFunctions[index] = (DWORD)NewFun - (DWORD)DllBase;

  // 写出替换
  WriteProcessMemory(GetCurrentProcess(), &pAddressOfFunctions[index],
    (LPCVOID)((DWORD)NewFun - (DWORD)DllBase), sizeof(NewFun), &dwProtect);
  return(TRUE);
}

// 自定义导出函数
int __stdcall MyMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
   
   
  printf("hello lyshark \n");
  return(0);
}

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

int main(int argc, char *argv[])
{
   
   
  // 对MessageBoxA进行Eat Hook
  EATHook("USER32.dll", "MessageBoxA", MyMessageBox);

  // 模拟下次调用后就是执行我们的Hook代码
  LoadLibrary("USER32.dll");
  HMODULE hDll = GetModuleHandle("USER32.dll");

  LPFNMESSAGEBOX lpMessageBox = (LPFNMESSAGEBOX)GetProcAddress(hDll, "MessageBoxA");
  lpMessageBox(NULL, "Hello, EAT Hook", "Info", MB_OK);

  system("pause");
  return(0);
}

上述代码被运行后,针对外部调用MessageBoxA函数都会转向到MyMessageBox函数上,至此传入的参数将会失效,如下图所示;

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/b550753d.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

目录
相关文章
|
5月前
|
自然语言处理 JavaScript 开发者
生命周期钩子1
生命周期钩子1
|
5月前
|
JavaScript 开发者
生命周期钩子2
生命周期钩子2
|
5月前
|
小程序 JavaScript 开发者
小程序生命周期
小程序生命周期
30 1
|
2月前
|
前端开发 JavaScript 开发者
React生命周期方法完全指南:深入理解并高效应用每个阶段的钩子——从初始化到卸载的全方位解析
【8月更文挑战第31天】本文详细介绍了React组件生命周期方法,包括初始化、挂载、更新和卸载四个阶段的关键钩子。通过探讨每个阶段的方法,如`componentDidMount`和`componentWillUnmount`,帮助开发者在正确时机执行所需操作,提升应用性能。文章还提供了最佳实践,指导如何避免常见错误并充分利用最新钩子。
49 0
|
3月前
|
缓存 JavaScript API
vue3 生命周期(生命周期钩子 vs 生命周期选项 vs 缓存实例的生命周期)
vue3 生命周期(生命周期钩子 vs 生命周期选项 vs 缓存实例的生命周期)
35 0
|
5月前
|
弹性计算 数据库
生命周期挂钩概述
生命周期挂钩概述
47 0
|
5月前
|
前端开发 JavaScript Python
学不懂生命周期函数正常吗?
学不懂生命周期函数正常吗?
|
存储 监控 编译器
4.3 IAT Hook 挂钩技术
IAT(Import Address Table)Hook是一种针对Windows操作系统的API Hooking 技术,用于修改应用程序对动态链接库(DLL)中导入函数的调用。IAT是一个数据结构,其中包含了应用程序在运行时使用的导入函数的地址。IAT Hook的原理是通过修改IAT中的函数指针,将原本要调用的函数指向另一个自定义的函数。这样,在应用程序执行时,当调用被钩子的函数时,实际上会执行自定义的函数。通过IAT Hook,我们可以拦截和修改应用程序的函数调用,以实现一些自定义的行为,比如记录日志、修改函数参数或返回值等。
128 0
4.3 IAT Hook 挂钩技术
|
11月前
|
小程序 UED
小程序的生命周期讲解
小程序的生命周期讲解
56 0
|
存储 安全 编译器
4.2 Inline Hook 挂钩技术
InlineHook 是一种计算机安全编程技术,其原理是在计算机程序执行期间进行拦截、修改、增强现有函数功能。它使用钩子函数(也可以称为回调函数)来截获程序执行的各种事件,并在事件发生前或后进行自定义处理,从而控制或增强程序行为。Hook技术常被用于系统加速、功能增强、开发等领域。本章将重点讲解Hook是如何实现的,并手动封装实现自己的Hook挂钩模板。
80 0
4.2 Inline Hook 挂钩技术