PE的基本概念
地址:
PE中设计的地址有四类:
1.虚拟内存地址(VA):
用户的PE文件被操作系统加载进内存后,PE对应的进程支配了自己独立的4GB虚拟空间。在这个空间中定位的地址称为虚拟和内存地址(Virtual Address VA),
所以虚拟内存地址的范围是0000 0000h ~ 0fffffffh 在PE中,进程本身的VA被解释为:进程的基地址+相对虚拟内存地址
2,相对虚拟内存(RVA):
一个进程被操作系统加载到虚拟内存空间后,其相关的动态库也会被加载,这些同时加载到进程地址空间的文件称为模块。
相对虚拟内存地址(Reverse Virtual Address,RVA)是相对于基地址的偏移,即RVA使虚拟内存中用来定位某个特定位置的地址,该地址的值是找个特定位置距离某个模块基地址的偏移量,所以说RVA是针对某个模块而存在的。
3.文件偏移地址(FOA):
文件偏移地址(File Offest Address,FOA)和内存无关,它是指某个位置距离文件头的偏移。
4.特殊地址:
在PE结构中还有一种特殊地址,其计算方法并不是从文件头算起,也不是从内存的某个模块的基地址算起,而是从某个特定的位置算起。这种地址在PE结构中很少见,如在资源表里就出现过这样的地址。
注:RVA是相对于模块而言的,VA是相对于整个内存空间而言的。
指针:
PE数据结构中的指针的定义:如果数据结构中某个字段存储的值为一个地址,那么这个字段就是一个指针。
数据目录:
PE中有一个数据结构称为数据目录,其中记录了所有可能的数据类型,这些类型中,目前定义的又15种,包括导出表,导入表,资源表,等等(在后文有介绍)。
节:
节就是存放不同数据的地方,不同的节具有不同的访问权限。
对齐:
PE中规定了三类对齐:数据在内存中的对齐、数据在文件中的对齐、资源文件中资源数据的对齐
- 内存对齐:由于Windows操作系统对内存属性的设置以页为单位,所以通常情况下,节在内存中的对齐单位必须至少是一个页的大小,4kb(1000h)
- 文件对齐:定义的节在文件中的对齐单位要远小于对齐的单位:通常会以一个物理扇区的大小作为对齐粒度的值,即512字节,十六进制表示为200h
- 资源数据对齐:资源文件中,资源字节码部分一般要求以双字(4个字节)方式对齐。
PE文件结构
PE结构大致可以分为两部分:DOS头和冗余数据
DOS文件头,有60个字节,会使用到IMAGE_DOS_HEADER结构体
PE文件头部解析
DOS MZ头 IMAGE_DOS_HEADER`
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE 头结构定义开始 文件中的位置(偏移量)
WORD e_magic; // 魔术数字 0x00000000-0x00000001
WORD e_cblp; // 文件最后页的字节数 0x00000002-0x00000003
WORD e_cp; // 文件页数 0x00000004-0x00000005
WORD e_crlc; // 重定位元素个数 0x00000006-0x00000007
WORD e_cparhdr; // 以段落为单位的头部大小 0x00000008-0x00000009
WORD e_minalloc; // 所需的最小附加段 0x0000000A-0x0000000B
WORD e_maxalloc; // 所需的最大附加段 0x0000000C-0x0000000D
WORD e_ss; // 初始的堆栈段(SS)相对偏移量值 0x0000000E-0x0000000F
WORD e_sp; // 初始的堆栈指针(SP)值 0x00000010-0x00000011
WORD e_csum; // 校验和 0x00000012-0x00000013
WORD e_ip; // 初始的指令指针(IP)值 0x00000014-0x00000015
WORD e_cs; // 初始的代码段(CS)相对偏移量值 0x00000016-0x00000017
WORD e_lfarlc; // 重定位表在文件中的偏移地址 0x00000018-0x00000019
WORD e_ovno; // 覆盖号 0x0000001A-0x0000001B
WORD e_res[4]; // 保留字(一般都是为确保对齐而预留) 0x0000001C-0x00000023 WORD e_oemid; // OEM 标识符(相对于 e_oeminfo) 0x00000024-0x00000025
WORD e_oeminfo; // OEM 信息,即 e_oemid 的细节 0x00000026-0x00000027 WORD e_res2[10]; // 保留字(一般都是为确保对齐而预留) 0x00000028-0x0000003B LONG e_lfanew; // 新 exe 头在文件中的偏移地址 0x0000003C-0x0000003F } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; //DOS .EXE 头结构定义结束;引用结构名:IMAGE_DOS_HEADER,结构指针 名:PIMAGE_DOS_HEADER
DOS头的第一个表示位,5A4D,是一个固定值,DOS头的字节数为60字节,最后4个字节存放的是相对偏移量。
NT头由一个简单的标记,如果是PE文件,标志恒为0x00004550
如下图所示,ASCII为(PE00)
在32位系统下的PE结构:
在32位系统中,刚好相反,即DOS头称为冗余,所谓冗余,针对DOS头不参与32位系统运行过程而言的。
1 定位标准头
- 定位标准PE头:
e_lfanew 即起这个作用,该字段的值是一个相对偏移量,绝对定位是需要加上DOSMZ头的基地址:
PE_start=DOSMZ基地址+
IMAGE_DOS_HANDER.e_lfanew
=000h+E0
=00E0h
PE文件结构
节表是PE中所有节的目录,每一个目录都是一个“BookStore”,其字节码就是节内容。它按照目录里的指针指向的地址,分别将节的字节码在文件空间中排列起来,从而组成了一个完整的PE文件,PE文件头部等于DOS头+PE头,PE