当前位置: 首页 > news >正文

Windows逆向工程提升之IMAGE_EXPORT_DIRECTORY

  • 公开视频 -> 链接点击跳转公开课程
  • 博客首页 -> ​​​链接点击跳转博客主页

目录

什么是 IMAGE_EXPORT_DIRECTORY?

PE 文件与 Export Table 的关系

PE 文件的整体视角

Export Table 在 PE 中的定位

IMAGE_EXPORT_DIRECTORY 结构

数据结构定义

字段详解

Characteristics

TimeDateStamp

MajorVersion 和 MinorVersion

Name

Base

NumberOfFunctions

NumberOfNames

AddressOfFunctions

AddressOfNames

AddressOfNameOrdinals

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

AddressOfFunctions(函数地址表)

AddressOfNames(名称指针表)

AddressOfNameOrdinals(序号表)

导出表的工作流程

导出表在攻击中的应用

API Hook

恶意 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 的结构定义如下:

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(地址空间布局随机化):
    • 随机化模块加载地址,增加攻击者定位导出表的难度。
http://www.xdnf.cn/news/604585.html

相关文章:

  • Git和Gitcode交互教程
  • 85. Java Record 深入解析:构造函数、访问器、序列化与实际应用
  • 关于千兆网络变压器的详细介绍
  • 【Flutter】多语言适配-波斯语RTL从右到左
  • 基于 Vue3 与 exceljs 实现自定义导出 Excel 模板
  • 如何在Mac 上使用Python Matplotlib
  • Redis 详解
  • G1人形机器人软硬件组成
  • vite学习笔记
  • Jenkins 2.426.2配置“构建历史的显示名称,加上包名等信息“
  • 计算机网络——每一层的用到的设备及其作用
  • Spring MVC-面试题(33)
  • Python asyncio库:基本概念与使用方法
  • voc怎么转yolo,如何分割数据集为验证集,怎样检测CUDA可用性 并使用yolov8训练安全帽数据集且构建基于yolov8深度学习的安全帽检测系统
  • React+MapBox GL JS引入URL服务地址实现自定义图标标记地点、区域绘制功能
  • vue 鼠标经过时显示/隐藏其他元素
  • FPGA高效验证工具Solidify 8.0:全面重构图形用户界面
  • 游戏引擎学习第306天:图结构排序的调试
  • QT-VStudio2107加载项目,报出“元素 <LanguageStandard>只有无效值“Default“”
  • ten-vad:低延迟、轻量化且高性能的流式语音活动检测系统
  • 2025年5月网工基础知识
  • rosbridge_suit、roslibpy 源码阅读与简单测试 —— 图片编解码与传输
  • 从 Docker 到 runC
  • 小说漫画管理系统
  • FRP技术概览
  • 黑马点评--短信登录实现
  • 针对面试-java集合篇
  • Alpha shapes算法边缘点进行排序(C++)
  • 「二叉搜索树·手撕暴走篇」:用C++《一路向北》狂写指针のの死亡轮盘!
  • 初识main函数