首页
社区
课程
招聘
[原创]PE学习之手工解析导出表
发表于: 2017-4-25 12:36 4974

[原创]PE学习之手工解析导出表

2017-4-25 12:36
4974

内容非常基础,希望可以帮助到有需要的同学。水平有限,文中难免有错,请见谅。


0x01 导出表结构

在开始解析前,先熟悉下导出表结构:

// 40Bytes(0x28Bytes)
typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;  // 标志, 未用
    DWORD   TimeDateStamp;    // 时间戳
    WORD    MajorVersion;     // 未用
    WORD    MinorVersion;     // 未用
    DWORD   Name;             // 指向该导出表的文件名字符串 
    DWORD   Base;             // 导出函数的起始值
    DWORD   NumberOfFunctions;       // 所有的导出函数个数
    DWORD   NumberOfNames;           // 以函数名导出的函数的个数
    DWORD   AddressOfFunctions;      // 导出函数地址表RVA(RVA from base of image)
    DWORD   AddressOfNames;          // 函数名称地址表RVA(RVA from base of image)
    DWORD   AddressOfNameOrdinals;   // 函数序号地址表   (RVA from base of image)
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

NumberOfNames: 导出表中有些函数是定义名字的,有些事没有定义名字的。该字段记录了所有定义了名字的函数的个数。如果这个值是0,则表示所有的函数都没有定义名字。NumberOfNames是小于等于NumberOfFunctions。

AddressfFunctions: 是一个函数指针,该指针指向了全部导出函数的入口地址的起始。从地址开始为双子数组,数组的个数由字段NumberOfFunctions决定。导出函数的每一个地址按函数的编号顺序依次往后排。

nBase: 导出函数的起始值,DLL中的第一个导出函数并不是从0开始的,某导出函数的编号等于从AddressOfFunctions开始的序号加上这个值,导出函数编号 = nBase + 函数顺序号(索引值),可见,nBase字段决定导出函数的编号。eg:

nBase = 200H,AddressOfFunctions指向fun1:

AddressOfNameOrdinals: 该值也是一个指针,与AddressOfNameOrdinals一 一对应, 指向了该函数在AddressOfFunctions中的索引值(注:此索引值是一个字(2Bytes))。

AddressOfNames: 该值是一个指针数组,指向的位置是一连串的双字值,这些双字值又均指向了对应的定义了函数名的函数的字符串地址。一连串的双字个数取决于NumberOfNames。

导出表结构图(取自《WindowsPE权威指南》):

                                                                          图1

下面开始手工解析导出表,以《WindowsPE权威指南》中chapter5\winResult.dll为例。

0x02 定位数据目录项

首先定位数据目录项(DataDirectory),这个比较简单,找到PE标识符,PE标识符偏移0x4Bytes是标准PE头(IMAGE_FILE_HEADER),标准PE头偏移0x14Bytes是可选PE头(IMAGE_OPTIONAL_HEADER),可选PE头再偏移0x60Bytes就是数据目录项了。

                                                                                        图2

0x03 定位导出表

我们知道DataDirectory[0]就是我们要解析的导出表,由图2可知导出表的VirtualAddress = 0x00002140

我们知道这个值是一个RVA(相对虚拟内存地址),要查看它在文件中的位置,我们需要将它转换为FOA(文件偏移地址)。从图2可知,winResult.dll中各个节的信息如图3:

图3.png

                                                                                  图3

计算RVA对应的FOA:

  • 步骤1: 由图2可知,节.rdata的真实数据的范围是0x00002000~0x000021CF,0x00002140在节.rdata中;
  • 步骤2: 计算偏移offset = 0x00002140 - 0x00002000 = 0x00000140;
  • 步骤3: 计算在文件中的偏移(FOA):0x00000800 + 0x00000140 = 0x00000940;

所以导出表在文件位于0x0000940处。

0x04 解析导出表

上边已经计算出来了,导出表在文件中的偏移是0x0000940。在文件中的此位置查看导出表各个字段的具体值,如下图4:

                                                               图4

得到以下信息:

   // FOA = PointerToRawData + (RVA - VirtualAddress)
nName = 0x00002190                 // 该导出表的文件名字符串所在偏移地址 
   /*  此RVA值所在节:.rdata
   *   转换为FOA = 0x0800 + 0x2190 - 0x2000 = 0x0990
   */
nBase = 0x01                       // 导出函数的起始值
NumberOfFunctions = 0x04           // 共有4个导出函数
NumberOfNames = 0x04               // 有4个函数是以函数名导出的   // 以下3个RVA值均位于节.rdata
AddressOfFunctions = 0x00002168    // 导出函数地址表RVA , FOA = 0x0968
AddressOfNames = 0x00002178        // 函数名称地址表RVA , FOA = 0x0978
AddressOfNameOrdinals = 0x00002188 // 函数序号地址表      FOA = 0x0988

                                                           图5

如图5,紫色部分标注的是该导出表的名称:winresult.dll

0x05 查找导出函数地址

方法一:通过函数名查找函数所在地址:

  • 第一步:将要查找的函数名与函数名称地址表(AddressOfNames, 图5橘色标注部分) 中4个地址处的字符串逐个比较,当两个字符串完全匹配时,记录此时函数名称地址表的索引为index_1
  • 第二步:用第一步得到的函数名称地址表的index_1去查看函数序号地址表(NumberOfNameOrdinals, 图5绿色标注部分)中index_1处存放的值,将该值记录下来记为index_2
  • 第三步:用第二步得到的index_2去找导出函数地址表(AddressOfFunctions, 图5红色标注部分)中index_2处存放的值,该值就是要查找的函数的地址。

操作如图6(图中数据可从图5获得):

                                                                           图6

方法二:通过函数编号查找函数所在地址,这种方法就比较简单了:

  • 第一步:函数编号 - nBase = index_2
  • 第二步:用第一步得到的index_2去找导出函数地址表(AddressOfFunctions, 图5红色标注部分)中index_2处存放的值,该值就是要查找的函数的地址。

至此,对导出表就算有个初步的认识了吧。

0x06 编程实现

运行结果:

参考

  • 《Windows PE权威指南》


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 47147
活跃值: (20455)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
2

在保留PDF基础下,能不能直接把内容编辑放到帖子里?方便搜索

2017-4-25 12:40
0
雪    币: 152
活跃值: (29)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3




kanxue

在保留PDF基础下,能不能直接把内容编辑放到帖子里?方便搜索

已编辑

2017-4-25 12:47
0
游客
登录 | 注册 方可回帖
返回
//