PE文件结构分析

PE文件格式

1 介绍

PE文件是Windows操作系统下使用的可执行文件格式。PE文件是指32位的可执行文件,64位的可执行文件称为PE+或者PE32,是PE文件的一种扩展形式。

2 PE文件格式

PE文件种类有:EXE、SCR、DLL、OCX、CPL、DRV、SYS、VXD、OBJ,下面用记事本程序为例,进行简单的说明。(用到的工具是WinHex)  notepad.exe具有普通PE文件的基本结构,下面我们一步步详细分析。


先简单说明一下几个知识点:
1  从DOS头到节区头是PE头部分,其下的节区合称为PE体。
2  文件中使用偏移(offset),内存中使用VA(VirtualAddress 虚拟地址)来表示位置。
3  文件加载到内存中时,情况就会发生变化。文件的内容一般可以分为代码(.text)、数据(.data)、资源(.rsrc)节,分别保存。
4   PE头与各节区的尾部存在一个区域,称为NULL填充。文件/内存中节区的起始位置应该在各文件/内存最小单位的倍数位置上,空白区域将用NULL填充。
5   VA&RVA,VA是进程虚拟内存的绝对地址,RVA指的是从某个基准位置开始的相对地址。计算公式如下:
RVA+ImageBase=VA
PE头内部信息大多数都是以RVA形式存在,因为PE文件加载到进程虚拟内存的特定位置时,该位置可能已经加载了其他的PE文件,这个时候必须通过重定位来将其加载到其他空白的位置。

好了下面进入正题,分析PE结构

3 PE头

PE头由许多结构体组成,现在开始逐一的分析各个结构体。


3.1 DOS头
在PE头最前面有一个DOS头,结构体的名字叫IMAGE_DOS_HEADER,大小是40字节,其中最重要的成员是e_magic和e_lfanew,前者表示DOS签名(MZ),后者表示NT头的偏移。
 
如果修改了这些值,则PE文件无法运行。


3.2 DOS存根
在DOS 头的下方,是个可选项,且大小不固定(即没有DOS存根也不影响正常运行)。DOS存根由代码和数据混合而成。
 

40到4D是16位的汇编指令,在DOS环境下才会执行这些代码,32为的Windows中不会运行。


 
在XP下用debug看notpad.exe可以看到,程序的执行时在屏幕上输出“This program cannot be run in DOS mode”然后终止。


3.3 NT头
下面介绍NT头IMAGE_NUT_HAEADERS,在这个结构体中由三个成员组成,第一个是签名,值为50450000h(“PE 00”)。另外两个分别为文件头和可选头结构体。NT头的大小为F8。因此这里一直从E0到1D8。
 

3.4 NT头:文件头
文件头是表现文件大致属性的IMAGE_FILE_HEADER结构体。其中有4中重要成员,设置不正确会导致文件无法运行。大小20字节。
先看图,然后列出几个重要的成员。
 
(1) Machine
每个CPU都有唯一的Machine码,兼容32位Intelx86芯片的Machine码为14C。
这里是014C
(2) NumberOfSections 
PE文件把代码、数据、资源等依据属性分类到各节区中存储。这个参数用来指出文件中存在的节区数量。这个值一定要大于0,且当定义的节区数与实际节区不同时,将发生错误。
这里是0003
(3) SizeOfOptionalHeader
IMAGE_NT_HEADER结构体的最后一个成员为IMAGE_OPTIONAL_HEADER32结构体。 SizeOfOptionalHeader用来指出IMAGE_OPTIONAL_HEADER32结构体的长度。在PE32+格式的文件中使用的是IMAGE_OPTIONAL_HEADER64结构体,而不是IMAGE_OPTIONAL_HEADER32结构体,2个结构体的尺寸是不同的。所以需要用这个参数明确指出大小。
这里是00E0(中间是其他的成员)
(4) Characteristics
这个字段用于标识文件的属性,文件是否可运行的形态、是否为DLL文件等信息,以bit OR形式组合起来。
注意:0002h表示文件可执行、2000h表示文件是DLL文件。
这里是 010F 
这个值是抑或之后的值,如果想继续了解,查阅一下winnt.h中Characteristics的值就知道了。
(5) TimeDataStamp
指出了文件创建的时间,不影响文件运行。
这里是48025287


3.5 可选头
IMAGE_OPTIONAL_HEADER32是PE头结构体中最大的。在这个结构体中需要注意下列成员,这些值是文件运行必须的,设置错误将使文件无法正常运行。 大小为E0
(1) Magic 
32位的结构体,Magic为10B,64位结构体,Magic码为20B。
(2) AdressOfEntryPoint
EP的RVA值,指出程序最先执行的代码起始地址。
(3) ImageBase
指出文件的有限装入地址,一般而言,使用开发工具创建好EXE文件后,ImageBase的值为00400000,DLL文件的ImageBase值为10000000,执行PE文件时,PE装载器先创建进程,然后将文件载入内存,然后把EIP寄存器的值设置为ImageBase+AddressOfEntryPoint
(4) SectionAlignment,FileAlignment
PE文件的Body部分划分为若干个节区,这些节区存储着不同类型的数据。FileAlignment指定了节区在磁盘文件中的最小单位,而SecitonAlignment则指定了节区在内存中的最小单位,两者的值可能相同也可能不同。
(5) SizeOfImage
加载PE文件到内存中的时候,这个值指定了PE Image在内存中所占空间的大小。一般而言,文件大小和加载到内存中的大小是不同的。
(6) SizeOfHeader
用来指出整个PE头的大小,也是FileAlignment的整数倍,第一节区所在位置与SizeOfHeader距文件开始偏移的量相同。
(7) Subsystem
用来区分系统驱动文件有普通的可执行文件
(8) NumberOfRvaAndSizes
用来指明DataDirectory数组的个数。
(9) DataDirectory
这个是由IMAGE_DATA_DIRECTORY结构体组成的数组,数组的每项都有被定义的值。在这个里面要注意的是EXPORT\IMPORT\RESOURCE\TLS Direction这几个值。
 

蓝色部分是IMAGE_OPTIOIN_HEADER 


 3.6 节区头
把PE文件创建成多个节区结构的好处是,这样可以保证程序的安全性。因此需要为每个code/data/resource设置不同的特性、访问权限等。大小120字节。
节区头是由IMAGE_SECTION_HEADER结构体组成的数组,每个结构体对应一个节区。其中需要重点了解的成员有
VirtualSize 内存中节区所占大小
VirtualAddress 内存中节区起始地址
SizeOfRawData 磁盘文件中节区所占大小
PointerToRawData 磁盘文件中节区起始位置
Charateristics  节区属性
 
在这里可以看出,三个节区的数据,通过查阅相应的结构体,可以对应出各个字段的值。

注意磁盘文件中节区的大小与加载到内存中的节区大小是不同的。

要注意的一点是,PE文件加载到内存中后,需要更具节区头中定义的节区其实地址、节区大小等加载。因此,磁盘中的PE与内存中的PE具有不同形态。将装载到内存中的形态称为“映像”以示区别。

RVAtoRAW

3.7 
理解了节区头后,PE文件加载到内存时,每个节区都要能准确完成内存地址与文件偏移间的映射。这种映射一般称为RVAtoRAW.
(1) 查找RVA所在节区
(2) 使用简单的公式计算文件偏移
RAW – PointerToRawData = RVA – VirtualAddress
RAW = RVA-VirtualAddress + PointerToRawData



  • 15
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值