PE 导出表

知识点:一个可执行程序是由一堆PE文件构成的!如下图可解释:

我加载的是一个.exe,但是后面还有需要的.dll文件,大家都知道.dll也有PE文件,这里也就又有一个问题了,为什么要引入这么多的.dll文件呢?

因为一个exe还需要使用这些.dll中所提供的函数,这些dll中就有相应的导出表,然后exe用LoadLibrary动态加载,最后通过GetProcAddress到获取函数的地址!

PE 导出表_第1张图片

知识点:

1、exe程序一般只有导入表,但并不是一定,有可能也有导出表
2、dll程序一般导出表和导入表都有


在扩展PE头是一个名为_IMAGE_OPTIONAL_HEADER的结构体

其中存在一个结构体数组为IMAGE_DATA_DIRECTORY,个数有16个,总占128字节

其中关于导出表的结构体的名称为:导出表IMAGE_DIRECTORY_ENTRY_EXPORT

该结构体数组中第一个成员结构体如下:

typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress; //虚拟地址,存储当前导出表的地址
    DWORD   Size; //存储 当前导出表的大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

那么蓝颜色的就是该结构体数组

PE 导出表_第2张图片

那么IMAGE_DIRECTORY_ENTRY_EXPORT的结构体就是前八个字节,如下:

存储导出表的结构体 80 AD 02 00 78 01 00 00

存储导出表的虚拟地址为:0002AD80

存储导出表的大小为:00000178

这里的文件对齐和内存对齐的大小是一样的

PE 导出表_第3张图片

如果不一样还需要先将RVA地址转换为FOA的地址

导出表的结构体如下:

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics; //未使用
    DWORD   TimeDateStamp;  //时间戳
    WORD    MajorVersion;  //未使用
    WORD    MinorVersion;  //未使用
    DWORD   Name; //指向该导出表文件名字符串
    DWORD   Base; //导出函数起始序号
    DWORD   NumberOfFunctions; //所有导出函数的个数
    DWORD   NumberOfNames; //以函数名字导出的函数个数
    DWORD   AddressOfFunctions;     // 子表:导出函数地址表RVA
    DWORD   AddressOfNames;         // 子表:导出函数名称表RVA
    DWORD   AddressOfNameOrdinals;  // 子表:导出函数序号表RVA
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

该结构体占103个字节,但是现在只看到了40字节,那还有63个字节呢?

其实这里面还有几个成员是指针,比如:

Name:指向的地址是该导出表文件的字符串
AddressOfFunctions:子表,导出函数地址表RVA
AddressOfNames:子表,导出函数名称表RVAAddressOfNameOrdinals:子表,导出函数序号表RVA

所以可以认为IMAGE_DIRECTORY_ENTRY_EXPORT中的Size可以忽视了

那么现在跟到0x0002AD80中查看_IMAGE_EXPORT_DIRECTORY导出表的结构体:

PE 导出表_第4张图片

Name为如下:CE AD 02 00

PE 导出表_第5张图片

PE 导出表_第6张图片

NumberOfFunctions:所有导出函数的个数有五个

PE 导出表_第7张图片

NumberOfNames:以函数名字导出的函数个数三个

PE 导出表_第8张图片

AddressOfFunctions:导出函数地址表RVA

PE 导出表_第9张图片

AddressOfNames:导出函数名称表RVA

PE 导出表_第10张图片

AddressOfNameOrdinals:导出函数序号表RVA

PE 导出表_第11张图片

PE 导出表_第12张图片

理解图:

PE 导出表_第13张图片

你可能感兴趣的:(PE 导出表)