今天讲解PE文件格式的DOS头文件格式
首先我们要理解,什么是文件格式,我们常说的EXE可执行程序,就是一个文件格式,那么我们要了解它里面到底存了什么内容
简短的说明.
我们要知道,PE文件格式,是微软半公开的,因为微软并没有说明这个文件格式.但是微软有定义的结构体.
文件格式,是记录文件加载到内存中执行的位置,和偏移
在DOS16位年代下,主要记录分段等等的信息.
在32位年代下,主要记录分区位置,代码位置,各种表等等..
PE总体格式:
+-------------------+
| DOS-stub | --DOS-头
+-------------------+
| file-header | --文件头
+-------------------+
| optional header | --可选头
|- - - - - - - - - -|
| |
| data directories | --数据目录
| |
+-------------------+
| |
| section headers | --节头
| |
+-------------------+
| |
| section 1 | --节1
| |
+-------------------+
| |
| section 2 | --节2
| |
+-------------------+
| |
| ... |
| |
+-------------------+
| |
| section n | --节n
| |
+-------------------+
一丶DOS头文件格式
我们看下结构体.
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[]; // Reserved words WORD e_oemid; // OEM identifier (for e_oeminfo) WORD e_oeminfo; // OEM information; e_oemid specific WORD e_res2[]; // Reserved words LONG e_lfanew; // File address of new exe header } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
可以看出,这个结构体中已经明确定义了各种DOS(16位年代的)头了.
我们在32位年代下,主要要知道第一个成员和最后一个成员
第一个成员: 标志MZ,记录了MZ,占两个字节,这个是DOS系统作者的名字
最后一个成员: 这个成员主要记录了新的文件开始执行的地址位置.
因为微软为了兼容16位程序,所以还保留DOS头,但是32位程序,是不会执行DOS头了,重要的就是这两个成员.
二丶WinHex对比
第一个成员,对应4D 5A两个字节
最后一个成员,对应 00 00 00 D0 (小尾方式) 最后一个成员是保存了新的文件格式地址.所以我们看到D0的位置,正好是PE
那么我们如果不是在16位程序下使用,那么上面除了最后一个成员,其余的位置都可以随便改.
正常运行
三丶DOS头的代码区
我们上面看到了,DOS头就一个结构体大小,到了最后一个成员位置,则是这个结构体结束,那么在这个结构体结束的后面,一直到PE的位置的二进制到底是什么?
可以看出,在DOS头的位置,也就是成员 WORD e_lfarlc; 记录的是DOS的代码执行位置,这块区域属于DOS的代码执行区域
主要作用是,在16位系统下,不能运行32位程序,如果运行,则利用中断,显示 This is Program cannot be run in Dos Mode (这个程序不能运行在DOS系统)
如果在32位系统下使用,那么这一段是没有任何作用的.DOS头只需要知道 第一个成员,和最后一个成员你的指向即可.
如果是16位系统下,那么你这个DOS头记录的信息就有用了(保存了页大小,页的个数,SS段.IP执行位置,校验和等等)
四丶NT头,PE头,以及可选头(第一讲介绍,不讲解具体作用)
到了PE位置,那么我们要了解一下NT头,PE头,可选头的结构到底是什么.新的格式是怎么样子的.
NT头:
typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
NT头分为32和64位版本的,这里说下32的,
第一个成员: 4个字节,也就是和4D 5A 一样,都是固定的标志,而这个标志则是
也就是我们说的PE头.
下面还有两个结构体,分别是文件头,还有可选头.
文件头:
typedef struct _IMAGE_FILE_HEADER { WORD Machine; WORD NumberOfSections; DWORD TimeDateStamp; DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
可选头:
<em id="__mceDel"> 可选头: typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; // // NT additional fields. // DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; </em>
最后一个成员是数据目录
typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
节头:
typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
可以看出,一个PE文件,主要是结构体套结构体,里面的每个成员都代表什么意义,结构体就怎么多.
五丶大体的PE结构分布图
DOS头
NT头
{
文件头
可选头
数据目录
}
节头
今天主要是要了解PE的DOS头,以及PE结构的分布图.具体作用以后慢慢讲,主要了解大体框架,随着框架深入.
参考于: