讲导入函数节,就必须介绍一下Datadirectory:
Datadirectory放在可选文件头optional_header里面,有16个项,每项8字节,里面存放的是每个导入函数节,导出函数节等节的信息。
可选文件头optional_header:
例如:
14 20 00 00 3c 00 00 00
前4位:代表该节的RVA,14 20 00 00RVA=0002014
后4位:代表该节的大小,0x0000003c=60
下面介绍导入函数节里面存放的具体内容:
下面按rdata中存放的顺序介绍,注意此表中的地址是文件地址:
- IAT/IMPORT Address Table 引入地址表
- 在文件中的位置:(通过datadirectory第13项定位)
其RVA(内存)=0x00002000
其RVA(文件)=0x00000600
【内存地址->文件地址:y=x/1000*200+200+x%1000】
- 存放内容:
在文件中,放有所有导入函数的名字或序号,与INT一样
在内存中,放有所有导入函数的地址
- 求引入函数的个数:
引入API函数个数=IAT大小/4字节-(dll的个数-1)
IAT大小在dataDirectory中,一个IAT表项4字节,-(dll的个数-1)是减去每个dll后面都有一个全0的表项。
- IDT/IMPORT Directory Table 引入目录表
- 在文件中的位置:(通过datadirectory第2项定位)
其RVA(内存)=0x00002014
其RVA(文件)=0x00000614
- 存放内容:
引入目录表由一系列IMAGE_IMPORT_DESCRIPTION结构组成,每个表项即为一个IMAGE_IMPORT_DESCRIPTION结构,每个结构(20字节)对应一个DLL文件。最后一项全0表示结束。
所以可以得到,kernel32引入的第一个函数:即INT/NAME/IAT的首地址
INT: RVA(内存)=0x00002050 RVA(文件)=0x00000650 序号
NAME: RVA(内存)=0x00002072 RVA(文件)=0x00000672 名字
IAT:RVA(内存)=0x00002000 RVA(文件)=0x00000600 地址
INT的0x650指向了0X664,IAT的0x600在文件中又指向了0x664(内存0x2064->文件0x664),但如果在内存中会显示真实地址
- 求dll的个数?
Dll个数=IDT的大小/20字节-1
IDT大小在datadirectory中,20字节是一个表项的大小,-1是减去最后一个全0的表项。
- INT/Import Name Table
放有所有导入函数的名字或序号
最高位为0时,函数名引入的方法:
如:Data=00002064,是个RVA值(内存中)
转化为文件中的地址就是,00000664,可以看到该地址下有函数名
- IMPORT Hints/Names &DLL names