什么是PE?

可执行文件格式:
Windows平台:
PE(Portable Executable可移植可执行)文件结构
Linux平台:
ELF(Executable and Linking Format可执行和链接格式)文件结构

什么是可执行文件?

一个进程,在操作系统上运行之前,记录着即将要运行的代码,以及各种相关数据的文件,按照某种约定存储在磁盘上。这种约定就是可执行文件的格式。这个格式要记录一个进程创建所必须的各种信息。因为他是为进程创建所服务的。

操作系统要装载一个进程,要有代码、数据、堆栈描述等等,这些东西都会在可执行文件中详细记录。

PE大致结构(缩进描述包含关系)

  • IMAGE_DOS_HEADER(DOS头)
  • IMAGE_NT_HEADERS(NT头)
    • IMAGE_FILE_HEADER(文件头)
    • IMAGE_OPTIONAL_HEADER(选项头、可选头)(变体)
  • IMAGE_SECTION_HEADER(数据节区描述)(多个)
  • SECTION_DATA(各节数据)

PE指纹

如何确定一个文件是否为PE文件呢?
需要用到一个十六进制编辑工具,如Ultraedit,WinHex等等
我在这使用的是Ultraedit
把一个正常的.exe后缀的文件拖入编辑工具内
可以看到前四个字节为4D 5A 所对应的ASCII为MZ
这就是PE文件的第一个特征

img

第二个特征在3C的位置
可以看到在3C的位置写着一个C0

img

那么继续往下找C0的位置
这里就是PE头的起始位置

img

如果这两个地方的特征都正确 那么基本可以确定 这个是一个PE文件

PE结构体

img

DOS部分

DOS MZ文件头

img
这个这部分是一个IMAGE_DOS_HEADER结构 大小为64个字节
在Ultraedit的16进制编辑模式中 每一行有16个字节 那么DOS MZ文件头的大小刚好就是四行
img
DOS MZ文件头的结构体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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块

img
DOS Stub这部分并没有确定的大小 并且在32位系统之后已经被废弃

那么如何确定DOS Stub的大小呢?
在上面已经提到IMAGE_DOS_HEADER结构为64个字节 而通过PE特征可以得到PE头的位置 那么这两个中间的大小即为DOS Stub的大小
img

PE头

结构体:

1
2
3
4
5
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

PE文件头标志

img
50 45 00 00这4个字节为PE文件头标志
img
这里所对应结构体中的

1
DWORD Signature;

PE文件表头(标准PE头)

img
PE文件表头大小为20 个字节
在PE文件头标志后往后数20个字节即为PE文件表头的范围
img
这里所对应结构体中的

1
IMAGE_FILE_HEADER FileHeader;

标准PE头的声明:

1
2
3
4
5
6
7
8
9
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;

PE文件头可选部分(扩展PE头)

img
扩展PE头在32位PE程序中的大小为224个字节 16进制标识为E0
扩展PE头在64位PE程序中的大小为240个字节 16进制标识为F0
(此大小可被修改)
在上面的标准PE头的声明中可以看到这样一个成员:

1
WORD    SizeOfOptionalHeader;

此成员就是用来标识扩展PE头大小的 修改此值即可改变扩展PE头的大小
在文件中的位置:
img
扩展PE头在文件中的范围:
img
拓展PE头所对应结构体中的

1
IMAGE_OPTIONAL_HEADER32 OptionalHeader;

节表

img
每个节表中的数据为40个字节

(待续。。)
(待续。。)
(待续。。)