PE32+与PE32的PE头文件的区别
NT头
NT头的区别
64位与32位PE头最大的区别就在NT头的第三个成员,也就是可选头(IMAGE_OPTIONAL_HEADER)
PE32+的NT头
PE32的NT头
可以看出,这两个NT头的区别主要在第三个成员:可选头
另外文件头也稍有不同
主要体现在机器码Machine的值上
X64中的文件头Machine值(机器标签)为8664
X86中的文件头Machine值为014C
IA-64(不向下兼容32位的64位操作系统)中的文件头Machine值为0200
可选头的区别
PE32+与PE32最大的区别可以说就是可选头了
可以看到64位与32位PE头的可选头的区别主要在:
Magic
PE32+中的Magic值为020B
PE32中的Magic值为010B
PE装载器通过检查该字段值来判断文件是64位还是32位
BaseOfData
可以看到PE32+中删除了该字段
在PE32中该字段表示指向数据段开头的指针(RVA)
ImageBase
PE32+中该字段由4字节(DWORD)变为8字节(ULONGLONG表示8字节),这是为了适应增大的进程虚拟内存
通过该字段64位文件能加载到进程虚拟空间的任意位置(64位进程虚拟内存为16TB)
通常64位文件加载到内存,会分配给用户区域低8位8TB,内核区域高8位8TB
其他与堆栈相关的字段在PE32+中都由原来的4字节变为8字节
ITD(IMAGE_THUNK_DATA)结构体区别
这里说明一下相关结构体的位置
1.第一步,找到IDD
首先,可选头里面有一个IDD(IMAGE_DATA_DIRECTORY)结构体数组
IDD结构体定义如下:
这个结构体数组里面装的就是各个表的相关信息,IDD结构体有8个字节,前4个是相应表的RVA,后4个是相应表的大小
比如:在IDD结构体数组中,第一个元素就是Export
Table导出目录表的相关信息,包括一个4字节的RVA和一个4字节的Size
2.第二步,找到Import Table
然后我们找到IDD中的第二个元素,也就是Import Table导入目录表.
第二个元素的第一个4字节就是Import Table的RVA,通过这个RVA我们转到Import
Table的值的所在区域
例如这里的1C047F,将其转换位文件偏移1BEA7F,然后转到1BEA7F查看Import
Table的信息
图中蓝色部分即位Import Table的相关信息
注意: Import Table 一般最后一个20个字节是空的
3.第三步,找到IID
Import
Table又是由IID结构体组成的数组,每个IID都有20个字节,其实一个IID就是以一个DLL的相关信息,第一个4字节是INT(导入名称表),最后一个4字节是IAT(导入地址表)
IID(IMAGE_IMPORT_DESCROPTOR)定义如下:
typedef struct _IMAGE_IMPORT_DESCRIPTOR(
union {
DWORD Characteristics;
DWORD OriginalFirstThunk; //该字段的值就是INT的RVA
} DUMMYUNIONNAME;
DWORD TimeDateSmp;
DWORD ForwarderChain;
DWORD Name;
DWORD FirstThunk; //该字段就是IAT的RVA
} IMAGE_IMPORT_DESCRIPTOR;
4.找IID中的INT和IAT
找到IID之后,通过第一个4字节和最后一个4字节找到INT和IAT的RVA.
然后通过INT的RVA
转到相应地址
在PE32+中
这些每8个字节就是一个指向ITD(就是一个导入函数的相关信息)结构体的RVA,如:
PE32中到这里是每4个字节表示一个ITD的RVA
然后通过上面的RVA就可以找到ITD,也就可以找到导入函数所在地址.
5.回到ITD结构体
PE32+和PE32的ITD结构体区别就在一个是8字节,一个是4字节
小结
-
通过可选头找到最后一个成员,也就是IDD(IMAGE_DATA_DIRECTORY)
-
通过IDD(IMAGE_DATA_DIRECTORY)找到导入表(第二个元素)
-
通过导入表识别出IID结构体(20个字节)
-
通过IID的第一个成员和最后一个成员找到INT的RVA和IAT的RVA
-
通过INT的RVA转到相应地址就可以看到ITD结构体(导入函数的信息),64位文件中,ITD是8个字节,32位文件中ITD是4个字节
IMAGE_TLS_DIRECTORY
这个结构体就是可选头的IDD结构体数组的第10个元素
64位文件中该结构体的前4个成员由原来的4个字节变为8个字节,后两个成员不变
INT和IAT
程序加载到内存时,PE装载器会将导入函数的实际虚拟地址(VA)写入IAT中,而INT是PE文件规定的导入名称表,INT和IAT的值(RVA)有时候会相同