《Windows PE》5.1 导出表

导出表(Export Table)是一个在可执行文件或动态链接库(DLL)中的数据结构,用于描述该文件中导出的函数、变量和其他符号。导出表通常位于DLL动态链接库中。

本节必须掌握的知识点:

        导入表数据结构

        PE中的导入表

        IAT函数地址表

        手工重构导入表

5.1.1 导出表数据结构

导出表由以下三个主要部分组成:

●导出地址表(Export Address Table,EAT):导出地址表是一个指向导出函数地址的指针数组。每个导出函数在导出地址表中有一个对应的指针。在运行时,当其他模块调用这个DLL中的导出函数时,将使用该表中的指针来定位和调用函数。

●导出名称表(Export Name Table,ENT):导出名称表是一个字符串数组,包含了所有导出函数的名称。每个导出函数名称在导出名称表中都有一个对应的字符串。导出地址表中的指针与导出名称表中的字符串是一一对应的。

●导出函数序号表(Export Function Ordinal Table)是PE文件中导出表的一部分,用于映射导出函数的序号和地址。导出函数序号表是一个由WORD类型的数组组成,每个元素对应一个导出函数。序号表的长度等于导出函数的数量。

导出表的结构和内容由编译器和链接器在构建可执行文件或DLL时生成。导出表允许其他模块(可执行文件、DLL或其他)通过导入表来引用和调用这些导出的函数和符号。

在Windows平台上,您可以使用一些工具来查看PE文件的导出表,例如Dependency Walker、dumpbin工具或PE浏览器等。

 注意

导出表只包含被明确定义为导出的符号。如果某个符号未被明确导出,它将不会出现在导出表中。您可以使用关键字 __declspec(dllexport) 或者通过.def文件来指定哪些符号应该被导出。

导出表数据结构

导入表描述符IMAGE_IMPORT_DESCRIPTOR的个数与调用的动态链接库个数相等,而导出表描述符IMAGE_EXPORT_DIRECTORY的个数只有一个。

typedef struct _IMAGE_EXPORT_DIRECTORY {

    DWORD   Characteristics;               // 导出表的特征标志

    DWORD   TimeDateStamp;              // 时间戳

    WORD    MajorVersion;               // 主版本号

    WORD    MinorVersion;               // 次版本号

    DWORD   Name;                       // 模块名称的RVA

    DWORD   Base;                     // 导出函数序号的基准值

    DWORD   NumberOfFunctions;          // 导出函数的数量

    DWORD   NumberOfNames;             // 导出函数名称的数量

    DWORD   AddressOfFunctions;         // 导出函数地址表的RVA

    DWORD   AddressOfNames;              // 导出函数名称表的RVA

    DWORD   AddressOfNameOrdinals;      // 导出函数序号表的RVA

} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

这个结构用于描述PE文件中的导出表。下面是对各个成员的注释:

Characteristics:导出表的特征标志,例如是否按序号导出。

TimeDateStamp:导出表的时间戳,表示导出表生成的时间。

MajorVersion 和 MinorVersion:导出表的版本号,用于指示导出表的版本信息。

Name:指向导出模块名称的指针(RVA)。

Base:导出函数的序号基准值。导出函数编号的起始值。DLL中的第一个导出函数并不是从0开始的,某导出函数的编号等于从AddressOfFunctions开始的顺序号加上这个值。

NumberOfFunctions:导出函数的数量。

NumberOfNames:导出函数名称的数量。

AddressOfFunctions:导出函数地址表的指针(RVA),包含导出函数的地址。该指针指向了全部导出函数的入口地址的起始。从入口地址开始为双字数组,数组的个数由字段IMAGE_EXPORT_DIRECTORY.NumberOfFimctions决定。导出函数的每一个地址按函数的编号顺序依次往后排开。在内存中,我们可以通过函数编号来定位某个函数的地址。

AddressOfNames:导出函数名称表的指针(RVA),包含导出函数的名称。该指针指向的位置是一连串的双字值,这些双字值均指向了对应的定义了函数名的函数的字符串地址。这一连串的双字个数为 NumberOfNames。

AddressOfNameOrdinals:导出函数序号表的指针(RVA),用于匹配导出函数的名称和地址。该值也是一个指针,与AddressOfNames是一一对应关系,所不同的是,AddressOfNames指向的是字符串的指针数组,而AddressOfNameOrdinals则指向了该函数在AddressOfFunctions中的索引值。

 注意

索引值是一个字,而非双字。该值与函数编号是两个不同的概念,两者之间的关系为:

索引值=编号 - nBase

导入表描述各个字段之间的关系可以用下图来描述:

                                         图5-1 PE导出表结构

5.1.2 定位导出表

导出表位于PE文件的数据目录第0项中,位于导入表之前。接下来我们通过一个实例具体分析导出表的结构。

首先我们要写一个包含导出表的DLL动态链接库,然后再写一个EXE执行文件调用导出函数。

实验三十三:延迟加载版本2示例

       以下是一个使用延迟加载版本2的C语言示例代码:

       ●源代码:

winResult.h

/*

; winResult.dll 导出函数:

; 1、AnimateOpen(DWORD)

;   窗口抖动进入效果

; 2、AnimateClose(DWORD)

;   窗口抖动退出效果

; 3、FadeInOpen(DWORD)

;   窗口淡入效果,仅运行在2000/XP以上操作系统

; 4、FadeOutClose(DWORD)

;   窗口淡出效果,仅运行在2000/XP以上操作系统

; ******************************************************************** /

*/

#pragma once

#include <windows.h>

#ifdef _cplusplus //如果C++模式编译

    #ifdef API_EXPORT

        #define EXPORT   extern "C" __declspec(dllexport)  

    #else

        #define EXPORT    extern "C" __declspec(dllimport

    #endif

#else

    #ifdef API_EXPORT

        #define EXPORT   __declspec(dllexport

    #else

        #define EXPORT   __declspec(dllimport

    #endif

#endif

EXPORT  void AnimateOpen(HWND);

EXPORT  void AnimateClose(HWND);

EXPORT  void FadeInOpen(HWND);

EXPORT  void FadeOutClose(HWND);

winResult.c

/*------------------------------------------------------------------------

 FileName:winResult.c

 实验33:一个简单的动态链接库例子

 (c) bcdaren, 2024

-----------------------------------------------------------------------*/

#include <windows.h>

#define API_EXPORT

#include "winResult.h"

#define MAX_XYSTEPS     50

#define DELAY_VALUE     50  //动画效果使用的步长

#define X_STEP_SIZE     10

#define Y_STEP_SIZE     9

#define X_START_SIZE    20

#define Y_START_SIZE    10

#define LMA_ALPHA       2

#define LMA_COLORKEY    1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值