yaoyao7 发表于 2019-1-16 11:34

IAT简单分析(以notepad.exe为例)

本帖最后由 yaoyao7 于 2019-1-16 14:33 编辑

IAT(Import Address Table,导入地址表)是刚开始学习PE文件头时比较难的一个部分,但是由于它保存的内容与Windows操作系统的核心进程、内存、DLL结构等有关,又特别重要,是必须要过的一关。
本文就主要根据IAT的结构和notepad.exe为例,来手动分析一下IAT,帮助大家尽快理解这个难题。

首先来理解一下IAT,在加载DLL时,加载方式有两种:一种是“显示链接”,层出使用DLL时机在,使用完毕后释放内存;一种是“隐式链接”,程序开始时即一同加载DLL,程序终止时再释放内存。IAT提供的机制就与隐式链接有关。
程序在调用DLL中的一个函数时,并不是直接调用,而是通过一个地址进行获取,地址中保存着所需要调用的函数的地址,这种设计机制主要是为了实现多环境的DLL加载。
需要注意的是在实际操作中无法保证DLL一定会被加载到PE头内制定的ImageBase处,但是EXE文件却能准确加载到自身的ImageBase中,这是由于exe拥有自己的虚拟空间。

然后,开始分析IMAGE_IMPORT_DESCRIPTOR(IID)
这个结构体中记录着PE文件要导入哪些库文件,导入多少个库就存在多少个IMAGE_IMPORT_DESCRIPTOR,这些结构体组成了数组,且结构体数组最后以NULL结构体结束。
IMAGE_IMPORT_DESCRIPTOR中重要的几个成员是OriginaleFirstThunk,这是INT的地址,是RVA;Name,这是库名称字符串的地址,RVA;FirstThunk,这是IAT的地址,RVA。
说一下PE装载器把导入函数输入至IAT的顺序:
1,读取IID的Name成员,获取库名称字符串
2,装载响应的库
3,读取IID的OriginalFirstThunk成员,获取INT地址
4,逐一读取INT中数组的值,获取相应的IMAGE_IMPORT_BY_NAME地址(RVA)

5,使用IMAGE_IMPORT_BY_NAMEDE 的Hint或Name选项,获取相应函数的起始地址
6,读取IID的FirstThunk(IAT)成员,获取IAT地址
7,将上面的函数地址输入相应IAT数组值
8,重复以上步骤4~7,直到INT结束(遇到NULL)


下面以notepad.exe为例进行一下简单的分析:
首先定位IMAGE_IMPORT_DESCRIPTOR的位置,其位置信息在PE头中,IMAGE_OPTIONAL_HEADER32.DataDirectory.VirtualAddress的值即是IMAGE_IMPORT_DESCRIPTOR结构体数组的起始地址(RVA)
IMAGE_OPTIONAL_HEADER32.DataDirectory结构体的值如图所示(第一个4直接为虚拟地址,第二个4直接为Size成员):



RVA为7604,所以RAW = 7604h - 1000h(假设VA为1000h) + 400h(PointerToRawData) = 6A04h,在文件中查看6A04:



选中部分为全部的IMAGE_IMPORT_DESCRIPTOR结构体数组(最后一个为NULL),且横线部分为数组的第一个元素(最后也是NULL)。
解释一下横线部分各成员:
0000 7990:OriginaelFirstThunk(INT),RAW = 0000 6D90
FFFF FFFF: TimeDateStamp
FFFF FFFF: ForwarderChain
0000 7AAC: Name, RAW = 0000 6EAC
0000 12C4: FirstThunk, RAW = 0000 06C4


下面分别在notepad.exe中看一下这几个成员:

1,Name:库名称,指向导入函数所属的库文件名称,去6EAC处查看:



我们可以看到字符串cmdlg32.dll。
2,OriginalFirstThunk (INT),这是一个包含导入函数信息(Ordinal,Name)的结构体指针数组,只有获得了这些信息才能在加载到进程内存的库中准确求得相应函数的起始地址,去6D90处查看:



INT是由地址数组形式组成(尾部以NULL结束),每个地址值分别指向IMAGE_IMPORT_BY_NAME结构体。
3,IMAGE_IMPORT_BY_NAME,根据INT查看的内容,我们到第一个数组地址查看(RVA:7A7A->RAW:6E7A):



INT是IMAGE_IMPORT_BY_NAME结构体指针数组,数组的第一个元素指向函数的最初的两个字节(000F)为Ordinal,是库中函数的固有编号,Ordinal的后面为函数名称字符串PageSetupDlgW.
4,FirstThunk(IAT),IAT的RAW为0000 06C4,查看:



选中部分为IAT数组区域,对应于comdlg32.dll库,与INT类似,由结构体指针数组组成,且以NULL结尾。
IAT的第一个元素值被硬编码为76324906,没有什么实际意义,这是因为在notepad.exe文件加载到内存时,这个值会被准确的地址值取代。
我们用OD看一下IAT:



因为我是在XP SP3下查看的,notepad.exe的ImageBase是01000000,所以comdlg32.dll!PageSetupDlgW函数的IAT地址为010012C4,其值为76324906,它是准确的起始地址值。
但如果换了系统环境,或者ImageBase发生改变,这个地址有可能不一样,76324906也会被替换为正确的起始地址。


以上就是对IAT的一个简单的理解,感觉自己亲自看一下会比较有效果。
虽然现在有很多自动化分析工具,感觉原理还是要掌握了,没有工具也应该能手动找到IAT。

goldengod 发表于 2019-1-16 12:41

感谢分享


此回复获得 1*0.3 积分, 距离升级还剩 666条回复

yuexiadeyingzi 发表于 2019-1-16 13:01

谢谢 虽然还是有点看不太懂{:1_893:}

老罗791 发表于 2019-1-16 13:33

感谢分享

朱朱你堕落了 发表于 2019-1-16 13:51

麻烦把记事本程序上传到附件,方便后来人学习。

lyliucn 发表于 2019-1-16 14:26

感谢分享

胃小饱 发表于 2019-1-16 15:19

学到了,感谢

mzhsohu 发表于 2019-1-16 21:26

感谢分享~!

重九先生 发表于 2019-1-17 11:39

标记一下,先看看好不好,谢谢楼主咯!

cwz 发表于 2019-1-17 21:06

谢谢楼主。
页: [1] 2
查看完整版本: IAT简单分析(以notepad.exe为例)