PE文件结构(PE文件头二)

时间:2021-11-29 10:19:46

①     Optional header Optional header

从字面上看,这个文件头是可选的,但实际上它是PE文件中必不可少的。它在winnt.h中被定义称为:

typedef struct _IMAGE_OPTIONAL_HEADER {

    WORD    Magic;

    BYTE    MajorLinkerVersion;

    BYTE    MinorLinkerVersion;

    DWORD   SizeOfCode;

    DWORD   SizeOfInitializedData;

    DWORD   SizeOfUninitializedData;

    DWORD   AddressOfEntryPoint;

    DWORD   BaseOfCode;

    DWORD   BaseOfData;

    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;

其中:

Magic:声明PE文件的状态,如果是普通的PE文件,值为0x10B;如果是只读的,值为0x107。

MajorLinkerVersion、MinorLinkerVersion:链接器的版本号,但实际上这两个值并不可靠,某些链接器不会设置这两个值。

SizeOfCode:所有代码节的大小。

SizeOfInitializedData、SizeOfUninitializedData:所有已初始化数据节、未初始化数据节的大小。

AddressOfEntryPoint:这是一个RVA。当PE文件被装载到内存中以后,第一条可执行指令的地址。对于设备驱动,这是初始化函数的地址;对于DLL,这个入口点是可选的,如果DLL没有入口点,则这个值必须为零。

BaseOfCode、BaseOfData:代码的RVA,已初始化数据的RVA。

ImageBase:PE文件的优先装载地址。比如,这个值是0x10000000,则装载器会将PE文件优先装载到虚拟内存地址0x10000000中。通常.EXE文件的这个值是0x00400000;.DLL文件的是0x10000000。

SectionAlignment:PE文件装载到内存后,节的对齐粒度,必须大于等于FileAlignment。WIN32下,一般是0x1000,WIN64下,一般是0x2000。

FileAlignment:PE文件中,节的对齐粒度。一般情况下是0x200的倍数。

MajorOperatingSystemVersion、MinorOperatingSystemVersion:期望的操作系统版本。

MajorImageVersion、MinorImageVersion:期望的PE文件版本,某些链接器不设定这个值。

MajorSubsystemVersion、MinorSubsystemVersion:期望的子系统版本。

Win32VersionValue:这个是保留的,必须是0。

SizeOfImage:PE文件装载到内存后,整个镜像的大小,必须是SectionAlignment的整数倍。

SizeOfHeaders:MS-DOS头、MS DOS 2.0 Stub Program、Magic Number、PE Header和Optional header大小之和,必须是FileAlignment的整数倍。

CheckSum:对于普通的PE文件,这个值是0。

Subsystem:声明PE文件在什么样的系统上运行,可以是下表中的值:(对于WINDOWS开发,通常选择第三项或者第四项)

Constant

Value

Description

IMAGE_SUBSYSTEM_UNKNOWN

  0

未知子系统。

IMAGE_SUBSYSTEM_NATIVE

  1

设备驱动以及WINDOWS内部程序。

IMAGE_SUBSYSTEM_WINDOWS_GUI

  2

WINDOWS GUI 程序。

IMAGE_SUBSYSTEM_WINDOWS_CUI

  3

WINDOWS控制台程序。

IMAGE_SUBSYSTEM_POSIX_CUI

  7

Posix字符子系统程序。

IMAGE_SUBSYSTEM_WINDOWS_CE_GUI

  9

Windows CE。

IMAGE_SUBSYSTEM_EFI_APPLICATION

10

可扩展固件程序。

IMAGE_SUBSYSTEM_EFI_BOOT_ SERVICE_DRIVER

11

启动服务的EFI驱动。

IMAGE_SUBSYSTEM_EFI_RUNTIME_ DRIVER

12

运行时的EFI驱动。

IMAGE_SUBSYSTEM_EFI_ROM

13

EFI只读镜像。

IMAGE_SUBSYSTEM_XBOX

14

XBOX。

DllCharacteristics:声明DLL文件的性质,可以是下表中的值:(如果没有特别需要,这个值是零)

常量

描述

 

0x0001

保留的,必须为零。

 

0x0002

保留的,必须为零。

 

0x0004

保留的,必须为零。

 

0x0008

保留的,必须为零。

IMAGE_DLL_CHARACTERISTICS_

DYNAMIC_BASE

0x0040

DLL可以在运行时被重置。

IMAGE_DLL_CHARACTERISTICS_

FORCE_INTEGRITY

0x0080

强制进行代码完整性检查。

IMAGE_DLL_CHARACTERISTICS_

NX_COMPAT

0x0100

映像是NX兼容的。

IMAGE_DLLCHARACTERISTICS_ NO_ISOLATION

0x0200

不隔离映像文件。

IMAGE_DLLCHARACTERISTICS_ NO_SEH

0x0400

不使用结构化异常处理。

IMAGE_DLLCHARACTERISTICS_ NO_BIND

0x0800

不绑定映像

 

0x1000

保留的,必须为零。

IMAGE_DLLCHARACTERISTICS_ WDM_DRIVER

0x2000

WDM驱动。

IMAGE_DLLCHARACTERISTICS_ TERMINAL_SERVER_AWARE

0x8000

终端服务器

SizeOfStackReserve:预留栈的大小,一般默认为0x10000。

SizeOfStackCommit:提交栈的大小,一般默认为0x1000。

SizeOfHeapReserve:预留堆的大小,一般默认为0x10000。

SizeOfHeapCommit:提交堆的大小,一般默认为0x1000。

LoaderFlags:保留的,必须为零。

NumberOfRvaAndSizes:之后的数据目录的数量,强烈建议使用默认的16。

DataDirectory:数据目录,每一个对应一个节,声明该节的RVA和大小。

②     Section headers

每一个节对应一个与之相关的节头,节头声明了节的大小、RVA以及的性,在winnt.h中,节头定义如下:

#define IMAGE_SIZEOF_SHORT_NAME 8

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;

其中:

Name:一个8字节长度的变量,给出节的名字。如果名字中的字符少于8字节,则用NULL填充;如果刚好等于8字节,则不需要以NULL结束。一般情况下,代码节名称为“.text”,数据节为“.data”。

Misc:这是一个联合体,在可执行映像中,使用的是VirtualSize,声明对应的节的大小。

VirtualAddress:当PE文件读入内存后,对应节的RVA。

SizeOfRawData:磁盘上,节根据FileAlignment对齐后的大小,必须是FileAlignment的倍数。

PointerToRawData:从文件开头到对应节的偏移量。

PointerToRelocations

PointerToLinenumbers

NumberOfRelocations

NumberOfLinenumbers:以上四个变量在可执行文件中用不到。

Characteristics:声明节的性质:可以是下表中的值,并可以按位或:

标志

描述

IMAGE_SCN_CNT_CODE

0x00000020

节包含可执行代码。

IMAGE_SCN_CNT_INITIALIZED_DATA

0x00000040

节包含已经初始化的数据。

IMAGE_SCN_CNT_UNINITIALIZED_ DATA

0x00000080

节包含未初始化的数据。

IMAGE_SCN_LNK_INFO

0x00000200

节包含注释或其他信息。只用于目标文件。

IMAGE_SCN_LNK_REMOVE

0x00000800

节不是映像的一部分,只用于目标文件。

IMAGE_SCN_LNK_COMDAT

0x00001000

节包含COMDAT数据。只用于目标文件。

IMAGE_SCN_GPREL

0x00008000

节包含引用全局指针的数据。

IMAGE_SCN_LNK_NRELOC_OVFL

0x01000000

节包含扩展重定位。

IMAGE_SCN_MEM_DISCARDABLE

0x02000000

根据需要,节可被废弃。

IMAGE_SCN_MEM_NOT_CACHED

0x04000000

节不可被缓存。

IMAGE_SCN_MEM_NOT_PAGED

0x08000000

节不可被分页。

IMAGE_SCN_MEM_SHARED

0x10000000

节可在内存中被共享。

IMAGE_SCN_MEM_EXECUTE

0x20000000

节可以执行。

IMAGE_SCN_MEM_READ

0x40000000

节可被读取。

IMAGE_SCN_MEM_WRITE

0x80000000

节可被写入。