Windows逆向工程提升之IMAGE_EXPORT_DIRECTORY

目录

[什么是 IMAGE_EXPORT_DIRECTORY?](#什么是 IMAGE_EXPORT_DIRECTORY?)

[PE 文件与 Export Table 的关系](#PE 文件与 Export Table 的关系)

[PE 文件的整体视角](#PE 文件的整体视角)

[Export Table 在 PE 中的定位](#Export Table 在 PE 中的定位)

[IMAGE_EXPORT_DIRECTORY 结构](#IMAGE_EXPORT_DIRECTORY 结构)

数据结构定义

字段详解

Characteristics

TimeDateStamp

[MajorVersion 和 MinorVersion](#MajorVersion 和 MinorVersion)

Name

Base

NumberOfFunctions

NumberOfNames

AddressOfFunctions

AddressOfNames

AddressOfNameOrdinals

[Export Table 的三个主要数组的关系](#Export Table 的三个主要数组的关系)

AddressOfFunctions(函数地址表)

AddressOfNames(名称指针表)

AddressOfNameOrdinals(序号表)

导出表的工作流程

导出表在攻击中的应用

[API Hook](#API Hook)

[恶意 Shellcode 的注入](#恶意 Shellcode 的注入)

导出表在防御中的实际应用

完整性验证

内存防护机制


什么是 IMAGE_EXPORT_DIRECTORY?

概述

  • 在 Windows PE 文件结构中,IMAGE_EXPORT_DIRECTORY 是用于描述模块 (DLL 或 EXE) 所导出(函数或变量)信息的核心结构。
  • 通过 Export Directory,其他模块可以访问当前模块公开的符号,如动态函数链接调用的函数地址。

PE 文件与 Export Table 的关系

PE 文件的整体视角

PE 文件是一种模块化执行文件格式。它包含以下部分:

  • Headers 部分:包括 DOS Header、PE Header,用来描述文件结构和入口点等。
  • Data Directories 部分:包含导出表(Export Table)、导入表(Import Table)、重定位表(Relocation Table)等指针。

Export Table 在 PE 中的定位

  • Export Table 是 Data Directories 的一项,位于 PE 可选头部中的 IMAGE_DATA_DIRECTORY 中。
  • 它的作用是描述该模块导出的所有符号(函数或变量),并支持函数按名称或序号的调用。
  • 常用于动态链接库 (DLL) 的导出 API。

IMAGE_EXPORT_DIRECTORY 结构

数据结构定义

在 Windows SDK 的 winnt.h 文件中,IMAGEEXPORTDIRECTORY 的结构定义如下:

cpp 复制代码
typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;        // 保留字段(总为0)
    DWORD   TimeDateStamp;          // 时间戳(编译器生成时间)
    WORD    MajorVersion;           // 主版本号(通常为0)
    WORD    MinorVersion;           // 次版本号(通常为0)
    DWORD   Name;                   // DLL名称的RVA(如"kernel32.dll")
    DWORD   Base;                   // 导出函数序号的基值(实际序号=索引+Base)
    DWORD   NumberOfFunctions;      // 导出函数总数(最大的导出序号 - 最小的导出序号 + 1)
    DWORD   NumberOfNames;          // 按名称导出的函数数量(可能小于总数)
    DWORD   AddressOfFunctions;     // 函数地址数组的RVA(每个元素为函数RVA)
    DWORD   AddressOfNames;         // 函数名称数组的RVA(每个元素为名称RVA)
    DWORD   AddressOfNameOrdinals;  // 函数序号数组的RVA(每个元素为索引)
} IMAGE_EXPORT_DIRECTORY;

字段详解

Characteristics

  • 保留字段,通常为 0。

TimeDateStamp

  • 用于表示导出表生成的时间戳。
  • 用于验证导出表的有效性。

MajorVersion 和 MinorVersion

  • 保留字段,表示模块的主次版本号。实际很少使用。

Name

  • 模块名称(DLL 文件名)的 RVA,例如 "kernel32.dll"。

Base

  • 起始导出序号值。默认是 1,但可以自定义为其它值。

NumberOfFunctions

  • 导出函数地址表中条目数量。
  • 即模块实际可以导出的符号总量。

NumberOfNames

  • 导出名称表中的名称数量。
  • 注意: 这可能小于 NumberOfFunctions,因为不是所有函数都有名称(某些只通过序号导出)。

AddressOfFunctions

  • 一个指向 RVA 的数组,每个条目是导出函数地址。

AddressOfNames

  • 一个指向 RVA 的数组,每个条目是导出函数名称字符串的 RVA。

AddressOfNameOrdinals

  • 一个指向数组的 RVA,每个条目对应导出名称表中名称的序号(以 Base 为基数)。

Export Table 的三个主要数组的关系

AddressOfFunctions(函数地址表)

  • 储存实际导出函数的入口地址(RVA)。
  • 大小等于 NumberOfFunctions * sizeof(DWORD)。

AddressOfNames(名称指针表)

  • 储存名称的 RVA,仅包含按名称导出的符号。
  • 大小等于 NumberOfNames * sizeof(DWORD)。

AddressOfNameOrdinals(序号表)

  • 每个名称对应的函数序号。
  • 这些序号用来索引函数地址表中的指定条目。
  • 大小等于 NumberOfNames * sizeof(WORD)。

导出表的工作流程

  1. PE 加载器读取 Data Directory,定位到 IMAGE_EXPORT_DIRECTORY 的 RVA。
  2. 通过 AddressOfFunctions、AddressOfNames 和 AddressOfNameOrdinals 解析导出符号。
    1. 如果按照函数名导出,从名称表和序号表定位到函数地址。
    2. 如果按照函数序号导出,直接用序号索引函数地址表。
  3. 动态生成外部模块可以调用的函数地址。

导出表在攻击中的应用

API Hook

攻击者通过修改导出表(尤其是导出地址表,即 Export Address Table, EAT)中函数地址,将正常的函数调用重定向到恶意函数,进而拦截数据或执行恶意代码。

  • 功能篡改:
    • 攻击者拦截导出的关键函数(如 OpenFile、ReadFile),窃取用户数据或操作文件。
  • 隐藏恶意行为:
    • 将监控函数(如 NtQuerySystemInformation)指向伪造的函数,隐藏自身的进程和对象。

恶意 Shellcode 的注入

  • 添加自定义导出函数,伪装成合法的 DLL。
  • 使用恶意 Shellcode 替代导出函数实现远程控制或蠕虫传播。

导出表在防御中的实际应用

完整性验证

导出表是 PE 文件结构的核心,可以作为完整性校验的依据:

  • 验证导出地址是否指向合法的函数地址。
  • 验证所有导出函数的序号和名称是否匹配。
  • 针对 DLL 劫持攻击的防御:通过比对导出表内容和原始文件的导出表,检测是否被篡改。
  • 防止 Hook 或 API 替换攻击:验证导出表指向的内存区域是否合法。

内存防护机制

Windows 的现代内存防护技术可以用来保护导出表免受修改。

  • DEP(数据执行保护):
    • 防止攻击者直接修改导出表的函数地址指向恶意代码。
  • ASLR(地址空间布局随机化):
    • 随机化模块加载地址,增加攻击者定位导出表的难度。
相关推荐
androidwork3 分钟前
Android 内存溢出(OOM)的 Kotlin 排查与优化指南
android·开发语言·kotlin
androidwork4 分钟前
Kotlin与Flutter:跨平台开发的互补之道与实战指南
开发语言·flutter·kotlin
@我漫长的孤独流浪6 分钟前
程序设计实践--排序(1)
数据结构·算法·排序算法
明月看潮生36 分钟前
青少年编程与数学 02-020 C#程序设计基础 02课题、开发环境
开发语言·青少年编程·c#·开发环境·编程与数学
明月看潮生39 分钟前
青少年编程与数学 02-020 C#程序设计基础 03课题、开始编程
开发语言·青少年编程·c#·编程与数学
Tee xm43 分钟前
算法修仙传 第一章 灵根觉醒:数组基础与遍历
java·数据结构·算法·数组·遍历
Cherl.1 小时前
C语言 贪吃蛇小游戏的实现
c语言·开发语言·链表·贪吃蛇
Susea&1 小时前
初识C++:模版
c语言·开发语言·c++
广州创科水利1 小时前
案例分享——福建洋柄水库大桥智慧桥梁安全监测
物联网·安全·数据分析·自动化
V文宝1 小时前
R语言速查表
开发语言·r语言