1.什么是导出,什么是导入,为什么有这两种行为。

我们一个程序的运行,实际由多个部分组成,通常是由一个exe和多个dll组成。dll会提供函数、变量给其他模块使用。并给dll中所有的函数都能够提供给其他模块使用,只有在编写dll的时候,函数,变量被导出了,才能够提供给其他模块使用,导出表就是专门用来记录本文件导出信息的一个数据结构。
我这个模块使用了哪些模块提供的哪些函数,需要记录这些信息,记录的信息就在导入表中

2.怎么找到导出表?

通常来说,dll文件提供导出的函数给其他模块使用,那么我要分析导出表,应该分析一个dll文件。

导入表的RVA:0x00018D70 转为FOA:7370
如何找到导出表
首先在扩展表中最后一个数据的数组中,找到其virtualaddress,然后到rdata数据段中找到这个段的VirtualAddressPointerToRawData,然后就套入公式

FOA = RVA-内存中区段首地址+文件中区段首地址
FOA = (导出表的)VirtualAddress-(区段的)VirtualAddress+(区段的)PointerToRawData
FOA = 0x18D70 - 0x1700 + 0x5600
FOA = 7370

3.如何解析导出表。

导出表结构有三个非常重要的表:

导出函数地址表:存放的是导出函数的RVA地址
导出函数名称表:存放的是导出函数名称的RVA
导出函数序号表:存放的是导出函数的序号

1.名称表元素的个数和序号表元素的个数是相同的
2.地址表中的元素个数可能会比序号表和名称表元素个数要多:
3.因为windows的PE文件支持两种导出方式:
名称导出:函数既有名称又有符号
序号导出:函数只有序号没有名称
无论什么导出方式,肯定是有函数地址的
4.地址表中多出来的,就是没有名称的函数,或者是序号的函数


哪些序号表里没有的,是没有名字的函数,他们的序号就是函数地址的下标(虚序号)
我们解析导出表的时候,我们先遍历函数地址表,遍历的时候如果是无效函数就略过,如果不是无效的,我们就用函数地址表中的下标在序号表中能不能找到对应的序号,找到的就是有名字,找不到就是没有名字的。

函数地址表的RVA:0x00018D98 FOA:0x7398
函数名称表的RVA:0x00018DA0 FOA:0x73A0
函数序号表的RVA:0x00018DA8 FOA:0x73A8

4.使用代码解析导出表。

5.知道了导出表的相关知识有什么用?

用处就是能够获得一个模块任何导出函数的地址。相当于能够实现GetProcAddress。
1.如果导入表被破坏了,可以修复导入地址表
2.可以检测IAT-Hook 主要的思路就是获取IAT此位置原始的函数地址。
获取原始的函数地址,我们需要知道这个函数的名字,再去对方模块的导出表里面把地址获取到,我们获取到的是RAV需要我们加上加载基址才是虚拟地址(VA),如果不一样就说明被Hook了,如果一样就说明没有被hook,这个可以检测IAT-Hook

3.适用于不方便使用GetProcAddress而需要通过函数名或者序号获取函数地址的情况。(起始它也是使用导出表获取函数地址的)

最后修改:2020 年 08 月 26 日
如果觉得我的文章对你有用,请随意赞赏