4.1 PE文件结构

PE (Portable Executable),即可移植的执行体。所有的 Windows(包括Win 9x、Win NT、 Win CE……)下的可执行文件(包括EXE、DLL、SYS、OCX、COM……)均使用PE文件结构,这些使用PE文件结构的可执行文件也成为PE文件。

作为一个普通的程序员也许没有必要掌握PE文件结构,因为普通的程序员大多都是开发服务性、决策性、辅助性的软件,比如MIS、HIS等软件。但是对于学习黑客编程,学习安全编程的程序员来说,那么掌握PE文件结构的知识就非常重要了。因此,我们要进行对 PE文件结构地学习。

4.1.1 PE文件结构全貌

Windows下的可执行程序有着复杂的文件结构,同样,PE结构是由若干个复杂的结构体组合而成的,不单单是一个结构体那么简单。就像磁盘结构体一样,磁盘结构同样是由非常多的结构体组成的。PE结构包含的结构体有DOS头、PE标识、文件头、可选头、目录结构、节表等。要掌握PE结构,必须对PE结构有一个整体上的认识,要知道PE结构分为哪些部分,这些部分大概是起什么作用的。有了宏观上的概念以后,就可以深入PE结构的各个结构体进行细致地学习了。下面给出一张图,让大家对PE结构有一个大概的了解,如图4-1所示。

4.1 PE文件结构 - 图1

图4-1 PE结构总览图

从图中可以看到,在PE文件中,真正包含代码和数据的部分是节表数据,节表数据以上的部分都是PE文件结构。

下面根据这个图给大家介绍PE文件结构的各个结构体,介绍完以后再写一个PE结构的解释器。这里不会介绍PE结构中的每个结构,只针对常用的和相对重要的结构体进行介绍。

4.1.2 MZ头部

MZ头部其实是一个DOS头部,由于其开始处的字符为“MZ”,因此叫做MZ头,也可以叫做DOS头,看个人习惯了。该部分用于在DOS下加载可执行程序,是用 IMAGE_DOS_HEADER来定义的。

DOS残留是一段简单的程序,主要用于输出“This program cannot be run in DOS mode.”类似的字符串。

为什么PE结构的最开始位置有这样一段DOS头部呢?关键是为了该可执行程序可以兼容DOS系统。通常情况下,Win32下的PE程序只是简单地输出一段字符串,提示不能运行于DOS系统下。但是这个DOS程序是可以在程序连接时修改的,不过由于不常使用也就不进行介绍了。

4.1.3 PE头部

PE头部保存Windows系统加载可执行文件的重要信息。PE头部由 IMAGE_NT_HEADERS来定义,通过该结构体的定义可以看出,IMAGE_NT_HEADERS是由多个结构体组合而成的,具体内容将在后面进行介绍。PE头部在PE文件中的位置是不确定的,PE头部的位置由DOS头部的某个字段给出。

4.1.4 节表

程序的组织按照各属性的不同而被保存在不同的节中,在PE头部之后就是一个数组结构的节表。如果PE文件中有N个节,那么节表就是由N个IMAGE_SECTION_HEADER组成的数组。节表中存储了各个节的属性、位置等相关信息。

4.1.5 节表数据

真正的程序部分就保存在节数据中。节名称最大长度为8个字节,大于8个字节将被截取。节的划分是根据各组数据的属性划分的,每个节拥有共同的属性。