windows通用pe ()

1.1、PE中有关的基本概念

1.1.1、地址:

PE中涉及的地址有四类,分别是

1>虚拟内存地址(VA)

2>相对虚拟内存地址(RVA)

3>文件偏移地址(FOA)

4>特殊地址

1.1.2、指针

PE数据结构中某个字段储存的值是一个地址,这个字段就是指针

1.1.3、数据目录

为了使PE文件包含的各种数据可扩展,提供稳定的兼容性,所以引入了数据目录

PE中有一个数据结构称为数据目录,其中记录了所有可能的数据类型。

这些类型中,目前已定义的有15中,导出表,导入表,资源表,异常表,属性证书表,重定位表,调试数据,Architecture,Global Ptr,线程局部储存,加载配置表,绑定导入表,IAT,EAT,延迟导入表,和CLR运行时头部

1.1.4、节

为了程序中各种不同数据的相互独立、安全,Windows操作系统在加载可执行程序时,会为这些具有不同属性的数据分别分配标记有不同属性的页面(相同属性的数据可能会被放到同一个页面中),以确保程序运行时的安全。正式基于这个原因,PE中才出现了所谓的节的概念。

就是存放不同类型数据(代码、数据、常量、资源等)的地方,不同的节具有不同的访问权限。节是PE文件中存代码或数据的基本单元。增加节的数目会增加文件开销,但连接器在连接代码时会有更大的选择余地。一个接中的所有原始数据必须被加载到连续的内存空间中。

从操作系统加载角度来看,节是相同属性的组合。与数据目录不同的事,尽管数据类型不同,分别数据不同的数据目录,但是由于访问属性相同,便被归类到同一个节中。无论这个节最终占用多少个页面,所有页面均会被赋予相同的页面属性(只写,只写,可写,可读,可执行,不可执行等)

1.1.5、对齐

PE中规定了三类对齐:数据在内存中的对齐、数据在文件中的对齐、资源文件中资源数据的对齐

1>内存对齐

由于Windows操作系统对内存属性的设计以页为单位,所以通常节在内存中的对齐单位必须至少是一个页的大小。对32位的WindowsXP来说,此值是4KB(1000h),而对于64位System来说,此值位8KB(2000h)

2>文件对齐

相对于内存对齐,文件对齐没有那么严格,为了提高磁盘利用率,通常,定义的节在文件中的对齐单位要远小于内存对齐的单位;通常以一个物理扇区的大小作为对齐粒度的值,即512byte,HEX表示为200h。(所以数据段、代码段等起始位置都是200h的倍数)

出于节约资源的考虑,操作系统允许节在内存和文件中的对齐尺寸不一致,这就直接造成了PE在文件中和在内存中的大小也会不一致。通常PE在内存中的尺寸要比在文件中的尺寸大。用户可以自己定义这些对齐的值

[注意:如果内存对齐被定义为小鱼操作系统页的大小,则文件对齐和内存对齐的值必须一致!

3>资源数据对齐

资源文件中,资源字节码部分一般要求以汉字(4个byte)方式对齐

1.1.6、Unicode字符串

汇编语言中,Unicode字符串被定义为一个结构体

typedef struct _UNICODE_STRING{

USHORT Length;

USHORT MAximumLength;

PWSTR Buffer;

} UNICODE_STRING, *PUNICODE_STRING;


1.2、PE文件结构

1.2.1、16位系统下的PE结构

在16位系统下,PE结构可以大致划分为两部分:DOS头和冗余数据

16位系统下,PE的四部分内容被重新组合成两部分——可以在16位系统下运行的DOS头和冗余数据。把Windows下的PE文件存储到DOS系统并运行,他就是DOS系统下的一个EXE文件。

DOS头分为两部分,DOS MZ头和DOS Stud(即执行字节码)。大部分情况下,这些指令实现功能都非常简单,不会涉及重定位信息。在往后的PE头和PE数据可以看做是16位系统下的可执行文件的冗余数据。

1>DOS MZ头

从m_res字段开始包括以下的字段在16位系统上是没有定义的。由于其开始的标志字为“MZ”(Mark Zbikowski,DOS系统的开发者之一),所以称它位“DOS MZ头”(总共64字节)

2>DOS Stub

由于DOS Stub的大小不固定,因此DOS头的大小也是不固定的。DOS Stub部分是该程序在DOS系统下运行的指令字节码。

40-4d处执行以下指令

1.2.2、32位系统下的PE结构

在16位系统中,PE头和PE数据部分被当成是冗余数据;在32位系统中,刚好相反,即DOS头成为冗余数据。在32位系统中尽管DOS头为冗余数据,但也不能把这部分数据从PE结构中除去。因为DOS MZ头中有一个字段非常重要,即IMAGE_DOS_HEADER.elfanew没有它操作系统就定位不到标准的PE头部,可执行程序也就会被操作系统认为是非法的PE映像。

1>定位标准PE头

PE_start = DOS MZ基地址 + IMAGE_DOS_HEADER.e_lfanew。可以看到该位置是以ASCII字符"PE"开头的

2>PE文件结构

在32位系统中,最重要的部分就是PE头和PE数据区

32位系统下的PE被划分为五个部分,DOS MZ头、DOS Stub、PE头、节表、节内容;

DOS MZ头:64个byte

PE头:456个byte(准确的说是不确定的,该结构的实际大小是由字段IMAGE_FILE_HEADER.SizeOfOptionalHeader来确定)

节表:每个节的表述信息是个固定值,共40个byte,节表是由不确定数量的节描述信息组成的,其大小等于节的数量×40,节的数量由IMAGE_FILE_HEADER.NumberOfsections来定义

DOS Stub、节内容:都是大小不确定的

节表是PE中所有节的目录

1.2.3、程序员眼中的PE结构

在程序员眼中,PE文件格式是由许多数据结构组成的

一个标准PE文件一般由四大部分组成

DOS头(IMAGE_DOS_HEADER) PE头(IMAGE_NT_HEADERS) 节表(多个IMAGE_SECTION_HEADER结构) 节内容

其中,PE头的结构最为复杂。简单说,PE头包含:

4个字节的标识符号(Signature)

20个字节的基本头信息(IMAGE_FILE_HEADER)

216个字节的扩展头信息(IMAGE_OPTIONAL_HEADER32)

PE文件头部 = DOS头 + PE头 + 节表

PE文件身体 = 节内容


3、PE文件头部解析

1.3.1、DOS MZ头和IMAGE_DOS_HEADER

DOS MZ头的下面是DOS Stub,整个DOS Stub是一个字节快,没有对应的数据结构(注释后的偏移是基于IMAGE_DOS_HEADER头的)

1.3.2、PE头标识Signature

DOS Stub头后紧跟PE头标识符Signature,该标识位于指针IMAGE_DOS_HEADER.e_lfanew指向的位置。内容固定,对应于ASCII码的字符电脑串"PE\0\0"

1.3.3、标准PE头IMAGE_FILE_HEADER

标准PE头紧跟IMAGE_FILE_HEADER(标准PE头),IMAGE_FILE_HEADER = IMAGE_DOS_HEADER.lfanew + 4

1.3.4、扩展PE头IMAGE_OPTIONAL_HEADER32

1.3.5、PE头IMAGE_NT_HEADERS

1.3.6、数据目录项IMAGE_DATA_DIRECTORY电脑

IMAGE_OPTIONAL_HEADER32结构的最后一个字段为DataDirectory,改字段定义了PE文件中出现的所有不同类型的数据的目录信息

总共有16个这样的结构连续排列在一起组成数据目录,数据目录存放了各种类型数据的起始地址和尺寸

1.3.7、节表项IMAGE_SECTION_HEADER

PE头IMAGE_NT_HEADERS后紧跟着节表。

节表由多个节表项(IMAGE_SECTION_HEADER)组成,每个节表项记录了PE中与某个特定的节有关的信息,如节的属性、节的大小、在文件和内存中的起始位置等。

电脑

节表后面就是节的内容。截至节表,PE文件头就结束了。


4、数据结构字段详解

1.4.1、PE头IMAGE_NT_HEADER的字段


OffsetSizeValueInformationIMAGE_NT_HRADER.Signature+0000hDWORD00004550hPE文件标识符,如果修改会导致PE无法加载IMAGE_NT_HRADER.FileHeader+0004hsizeof(IMAGE_FILE_HEADER)IMAGE_FILE_HEADER由于PE扩展自通用COFF规范,所以,改字段在官方文档中称为标准COFF头IMAGE_NT_HRADER.OptionalHeader+0018hsizeof(IMAGE_OPTIONAL_HEADER32)IMAGE_OPTIONAL_HEADER32Windows加载PE文件的大部分特性均在这个结构里呈现。分为两部分,前10个字段属于COFF,用来加载和运行一个可执行文件;后21个字段则通过连接器追加的

1.4.2 标准PE头IMAGE_FILE_HEADER的字段


电脑