当PE 文件被执行的时候,Windows 加载器将文件装入内存并将导出表(Export Table) 登记的动态链接库(一般是DLL 格式)文件一并装入地址空间,再根据DLL 文件中的函数导出信息对被执行文件的IAT 进行修正。
有一个重要的概念需要记住:动态链接库是被映射到其他应用程序的地址空间中执行的,它和应用程序可以看成是“一体”的。
动态链接库可以使用应用程序的资源,它所拥有的资源也可以被应用程序使用,它的任何操作都是代表应用程序进行的。
当动态链接库进行打开文件、分配内存和创建窗口等操作后,这些文件、内存和窗口都是为应用程序所拥有的。
那导出表是干啥用的呢?
导出表就是记载着动态链接库的一些导出信息。
通过导出表,DLL 文件可以向系统提供导出函数的名称、序号和入口地址等信息,比便Windows 加载器通过这些信息来完成动态连接的整个过程。
友情提示:
扩展名为.exe 的PE 文件中一般不存在导出表,而大部分的.dll 文件中都包含导出表。但注意,这并不是绝对的。
例如纯粹用作资源的.dll 文件就不需要导出函数啦,另外有些特殊功能的.exe 文件也会存在导出函数。
所以,世事无绝对……好了,我们接下来就对导出表的结构进行分析。
导出表结构
导出表(Export Table)中的主要成分是一个表格,内含函数名称、输出序数等。
序数是指定DLL 中某个函数的16位数字,在所指向的DLL 文件中是独一无二的。
在此我们不提倡仅仅通过序数来索引函数的方法,这样会给DLL 文件的维护带来问题。
例如当DLL 文件一旦升级或修改就可能导致调用改DLL 的程序无法加载到需要的函数。
数据目录表的第一个成员指向导出表,是一个IMAGE_EXPORT_DIRECTORY(以后简称IED)结构,IED 结构的定义如下:
IMAGE_EXPORT_DIRECTORY STRUCT
Characteristics DWORD ? ; 未使用,总是定义为0
TimeDateStamp DWORD ? ; 文件生成时间
MajorVersion WORD ? ; 未使用,总是定义为0
MinorVersion WORD ? ; 未使用,总是定义为0
Name DWORD ? ; 模块的真实名称(有用)
Base DWORD ? ; 基数,加上序数就是函数地址数组的索引值(重要)
NumberOfFunctions DWORD ? ; 导出函数的