PE文件结构解析 Part2 DOS Header, DOS Stub and Rich Header
https://0xrick.github.io/win-internals/pe3/
简介
上一篇文章我们简单地看了一下PE文件结构,这篇文章我们会讨论PE文件结构中的前两部分,DOS Header以及DOS Stub。
这一系列文章中,我会使用PE-Bear作为工具,它有很多特性,以及一个不错的UI。
DOS Header
概览
DOS Header(也被称为MS-DOS header)是一个64字节的结构,位于PE文件开始的部分。
这部分对于PE文件在现代Windows操作系统上的功能不太重要,它的存在主要是用于前向兼容。
这个头部信息使得文件成为MS-DOS可执行文件,当它被MS-DOS操作系统加载时,DOS stub会代替实际的应用程序被执行。
如果没有这个头部信息,并且你尝试在MS-DOS上执行该文件,它不会被加载而是会产生一个通用的错误提升。
结构
正如之前提到的,它是64字节的结构体,我们可以通过观察来自winnt.h
的IMAGE_DOS_HEADER
结构体来了解其中的内容。
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
这个结构对于DOS操作系统的PE加载器很重要,但对于Windows系统的PE加载器,只有一部分成员是有意义的。所以我们这里只讲讲其中重要的成员字段。
- e_magic: 这是DOS Header的第一个成员,类型是WORD所以大小是2字节,通常被称为魔数。它的值固定是0x5A4D,ASCII码表示为MZ。
- e_lfanew: 这是DOS Header结构的最后一个成员,它位于DOS Header偏移0x3c的位置,并且它存储了NT Headers起始位置的偏移。这个成员对于Windows系统很重要,因为它能告诉加载器到哪里找File Header。
下面的图片展示了PE-Bear里DOS Header的内容:
可以看到,第一个成员是固定数字5A4D的字段。
Header最后一个成员语义是File address of new exe header,它的值是100,我们可以跳转到那个偏移,然后发现NT Header。
DOS Stub
概览
DOS Stub 就是DOS程序,用于打印错误信息,告诉我们这个应用程序不兼容DOS。
这里原作者进行了更细节的分析,但是翻译的人对DOS不感兴趣,于是给它跳过了。
Rich Header
至今为止呢,我们已经看过了DOS Header和DOS Stub,但是实际上在DOS Stub和NT Header中间有一块数据我们还没有讨论过。
由于翻译的人并不着急看,所以还没翻译。