导出表
什么是导出,什么是导入,为什么又这两种行为?
一个程序的运行是由多个部分组成的,通常是由一个exe和多个dll组成。dll会提供函数,变量给其他模块使用。并非dll中所有的函数都能够提供给其他的模块使用,只有在编写dll的时候,函数,变量被导出了,才能提供给其他模块使用,导出表就是专门用来记录本文件导出信息的一个数据结构。
本模块使用了其他哪些模块提供的哪些函数,需要记录这些信息,记录的信息就在导入表中。
怎么找到导出表?
通常来说,dll文件提供到处的函数给其他模块使用,那么我要分析导出表,应该分析一个dll文件。
导出表的RVA:0x016CC0 FOA:0x05EC0
大小:0x162
ctrl+g转到0x5EC0就可以查看到导出表的结构
如何解析导出表
1 | typedef struct _IMAGE_EXPORT_DIRECTORY { |
导出表结构有三个非常重要的表:
- 导出函数地址表:存放的是导出函数的RVA地址
- 导出函数名称表:存放的是导出函数名称的RVA
- 导出函数序号表:存放的是导出函数的序号
名称表元素的个数和序号表元素的个数是相同的
地址表中的元素可能会比序号表和名称表元素个数要多
因为windows的PE文件支持两种导出方式
3.1 名称导出 函数既有名称又有序号
3.2 序号导出 函数只有序号,没有名称
无论哪种导出方式,肯定都有函数地址。
地址表中多出来的,就是没有名称的函数。或者是无效的函数
函数地址表的RVA:0x016CE8 FOA:0x5EE8
函数名称表的RVA:0x016CF0 FOA:0x5EF0
函数序号表的RVA:0x016CF8 FOA:0x5EF8
使用代码解析导出表
1 |
|
了解导出表的相关知识后有什么用?
能够获得一个模块任何导出函数的地址。相当于能够自己实现GetProcAddress。
如果导入地址表被破坏了,可以修复导入地址表。
可以检测IAT-HOOK,主要的思路就是获取IAT此位置原始的函数地址。
适用于不方便使用GetProcAddress而需要通过函数名或者序号获取函数地址的情况。
导入表
什么是导入表
当自己的模块需要使用其他模块提供的函数的时候,就需要在自己的模块中记录这些信息,记录这些信息的位置就是导入表。
IMAGE_THUNK_DATA 的值最高位为1时,表示函数是以序号方式输入,这时低31为被当作函数序号。当最高位是0时,表示函数是以字符串类型的函数名方式输入的。
三个重要字段:
OriginalFirstThunk:INT的RVA
FirstThunk:IAT的RVA
Name:导入的dll的名称的RVA
INT和IAT在还是文件的时候,里面存储的东西是一样的,都是函数名称的RVA。
在程序没有运行的时候,无法得到此模块会加载到什么位置,也就无法得到函数地址,所以IAT在文件中存储的是名称。
当程序运行起来之后,系统会区将IAT填充上函数的地址。
所有调用其他模块函数的代码全部都是 call ds:[IAT地址]
如何找到导入表?
通过数据目录表的第二项,得到RVA,就能够找到IMAGE_IMPORT_DESCRIPTOR结构体的数组,数组以全零元素为结尾。
导入表结构的起始RVA:0x018154 FOA:0x6554
如何解析导入表
1 | typedef struct _IMAGE_IMPORT_DESCRIPTOR { |
INT的RVA:0x0182C8 FOA:0x66C8
IAT的RVA:0x018124 FOA:0x6524
Name的RVA:0x018306 FOA:0x6706
如何用代码解析?
1 |
|
知道了导入表相关内容有什么用?
知道了模块之间是如何进行配合的。
call [0x…]
可以IAT-HOOK,替换IAT表中的内容,就可以HOOK
知道一个exe用了哪些模版的哪些函数。可以根据函数名猜测供功能,利于分析。
TLS表
1 |
|
延迟加载
1 |
|