Introduction
The Portable Executable (PE) format is an essential structure for Windows binaries such as executables (EXE) and dynamic link libraries (DLLs). It consists of a set of PE headers, each playing a crucial role in how the file loads, executes, and interacts with the operating system. This guide explores the key PE headers, their specific purposes, internal structures, and sizes, offering a comprehensive understanding for developers, reverse engineers, and cybersecurity professionals. By mastering the PE file format, you can gain deeper insights into PE file analysis and enhance your understanding of system programming.
What is the Portable Executable (PE) Format?
The Portable Executable (PE) format is a structure used by Windows binaries to ensure efficient execution on the system. From PE headers to section headers, each component is designed for a specific purpose, whether it’s managing metadata, memory mapping, or optimizing runtime behavior. Understanding the PE format structure helps in analyzing how Windows executables and DLLs operate within the system.
PE File Structure Overview
A PE file comprises several headers and sections:
- DOS Header
- PE Signature
- File Header
- Optional Header
- Data Directories
- Section Headers
- Sections
Headers and Sections in Detail
1. DOS Header
- Purpose: A legacy header from MS-DOS that contains the "MZ" magic number and a pointer to the PE header.
- Structure Name:
IMAGE_DOS_HEADER
- Size: 64 bytes
Key Fields:
e_magic
: Identifies the file as an executable with the "MZ" signature.e_lfanew
: Points to the NT headers.
typedef struct _IMAGE_DOS_HEADER {
WORD e_magic; /* 00: MZ Header signature */
WORD e_cblp; /* 02: Bytes on last page of file */
WORD e_cp; /* 04: Pages in file */
WORD e_crlc; /* 06: Relocations */
WORD e_cparhdr; /* 08: Size of header in paragraphs */
WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */
WORD e_maxalloc; /* 0c: Maximum extra paragraphs needed */
WORD e_ss; /* 0e: Initial (relative) SS value */
WORD e_sp; /* 10: Initial SP value */
WORD e_csum; /* 12: Checksum */
WORD e_ip; /* 14: Initial IP value */
WORD e_cs; /* 16: Initial (relative) CS value */
WORD e_lfarlc; /* 18: File address of relocation table */
WORD e_ovno; /* 1a: Overlay number */
WORD e_res[4]; /* 1c: Reserved words */
WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */
WORD e_oeminfo; /* 26: OEM information; e_oemid specific */
WORD e_res2[10]; /* 28: Reserved words */
DWORD e_lfanew; /* 3c: Offset to extended header */
}
1.1 DOS Stub
- Purpose: Displays a message such as "This program cannot be run in DOS mode" when executed in a DOS environment.
- Size: Variable, typically ~128 bytes.
2. PE Signature
- Purpose: Marks the file as a Portable Executable file.
- Structure Name: Not a structure but a constant value (
"PE\0\0"
). - Size: 4 bytes
3. File Header (PE Header)
- Purpose: Contains metadata about the file, such as the target machine and number of sections.
- Structure Name:
IMAGE_FILE_HEADER
- Size: 20 bytes
Key Fields:
Machine
: Specifies the target architecture (e.g., x86 or x64).NumberOfSections
: Indicates the number of sections in the file.Characteristics
: Describes file attributes, like whether it’s an executable or DLL.
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;
4. Optional Header
- Purpose: Despite its name, this header is mandatory. It provides details about the entry point, memory layout, and subsystem requirements of the file.
- Structure Name:
IMAGE_OPTIONAL_HEADER
(32-bit or 64-bit variants). - Size:
- 32-bit: 96 bytes
- 64-bit: 112 bytes
Key Fields:
AddressOfEntryPoint
: Specifies the entry point of the executable.ImageBase
: Preferred memory address for loading the file.Subsystem
: Indicates whether the file requires a console or GUI environment.
typedef struct _IMAGE_OPTIONAL_HEADER64 {
WORD Magic; /* 0x20b */
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
ULONGLONG 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;
ULONGLONG SizeOfStackReserve;
ULONGLONG SizeOfStackCommit;
ULONGLONG SizeOfHeapReserve;
ULONGLONG SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
}
5. Data Directories
- Purpose: Part of the Optional Header, these pointers direct the loader to key structures, such as imports, exports, and resources.
- Structure Name:
IMAGE_DATA_DIRECTORY
- Size: 8 bytes per entry (16 entries = 128 bytes)
Key Fields:
VirtualAddress
: Points to the table/structure in memory.Size
: Specifies the size of the table/structure.
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY;
6. Section Headers (Section Table)
- Purpose: Describe individual sections like
.text
(code),.data
(initialized data), and.rdata
(read-only data). - Structure Name:
IMAGE_SECTION_HEADER
- Size: 40 bytes per section
Key Fields:
Name
: Name of the section (e.g.,.text
,.data
).VirtualSize
: Size of the section in memory.SizeOfRawData
: Size of the section on disk.
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;
}
7. Sections
Sections store the actual content of the executable (code, data, imports, exports, etc.). The specific sections and their contents include:
Section | Purpose | Contents | Characteristics |
---|---|---|---|
.text | Code section | Executable instructions (machine code). | Execute |
.rdata | Read-only data | Import Table, Export Table, strings, constants. | Read |
.data | Initialized data | Global/static variables with initial values. | Read |
.bss | Uninitialized data | Global/static variables without initial values. | Read |
.idata | Import-related data | Import Address Table (IAT), descriptors. | Read |
.edata | Export-related data | Export Directory Table, exported symbols. | Read |
.reloc | Relocation information | Base Relocation Table. | Read |
.rsrc | Resources | Icons, dialogs, menus, etc. | Read |
7.1. .text (Code Section)
- Purpose: Contains the executable instructions (machine code) of the program.
- Structure Name:
IMAGE_SECTION_HEADER
- Contents:
- Compiled machine instructions.
- Entry point code for the program.
- Characteristics:
IMAGE_SCN_CNT_CODE
: Indicates this is a code section.IMAGE_SCN_MEM_EXECUTE
: The section is executable.IMAGE_SCN_MEM_READ
: The section is readable.
- Key Fields in Section Header:
Name
: Typically ".text".VirtualSize
: Size of the section in memory.PointerToRawData
: Offset of the section's raw data in the file.Characteristics
: Attributes for the section.
7.2. .rdata
(Read-Only Data Section)
- Purpose: Contains read-only data, such as constants, strings, and sometimes import/export-related data.
- Structure Name:
IMAGE_SECTION_HEADER
- Contents:
- Strings and constants.
- Import Table (Import Address Table, Import Lookup Table).
- Export Table (if not in
.edata
).
- Characteristics:
IMAGE_SCN_CNT_INITIALIZED_DATA
: Contains initialized data.IMAGE_SCN_MEM_READ
: Read-only data.
- Key Fields in Section Header:
Name
: Typically ".rdata".VirtualSize
: Size of the section in memory.PointerToRawData
: Offset of the section's raw data in the file.Characteristics
: Attributes for the section.
7.3. .data
(Initialized Data Section)
- Purpose: Stores global and static variables with initial values.
- Structure Name:
IMAGE_SECTION_HEADER
- Contents:
- Initialized global/static variables.
- Writable data used by the program.
- Characteristics:
IMAGE_SCN_CNT_INITIALIZED_DATA
: Contains initialized data.IMAGE_SCN_MEM_READ
: The section is readable.IMAGE_SCN_MEM_WRITE
: The section is writable.
- Key Fields in Section Header:
Name
: Typically ".data".VirtualSize
: Size of the section in memory.PointerToRawData
: Offset of the section's raw data in the file.Characteristics
: Attributes for the section.
7.4. .bss
(Uninitialized Data Section)
- Purpose: Stores uninitialized global and static variables.
- Structure Name:
IMAGE_SECTION_HEADER
- Contents:
- Uninitialized global/static variables.
- Memory is zero-initialized at runtime.
- Size:
- File size: Typically 0 (uninitialized data is not stored in the file).
- Virtual size: Rounded to
SectionAlignment
.
- Characteristics:
IMAGE_SCN_CNT_UNINITIALIZED_DATA
: Contains uninitialized data.IMAGE_SCN_MEM_READ
: The section is readable.IMAGE_SCN_MEM_WRITE
: The section is writable.
- Key Fields in Section Header:
Name
: Typically ".bss".VirtualSize
: Size of the section in memory.PointerToRawData
: Usually 0 (since no raw data is stored in the file).Characteristics
: Attributes for the section.
7.5. .idata
(Import Section)
- Purpose: Contains information about imported functions and libraries.
- Structure Name:
IMAGE_SECTION_HEADER
- Contents:
- Import Address Table (IAT).
- Import Lookup Table (ILT).
IMAGE_IMPORT_DESCRIPTOR
structures.
- Characteristics:
IMAGE_SCN_CNT_INITIALIZED_DATA
: Contains initialized data.IMAGE_SCN_MEM_READ
: Readable.
- Key Fields in Section Header:
Name
: Typically ".idata".VirtualSize
: Size of the section in memory.PointerToRawData
: Offset of the section's raw data in the file.Characteristics
: Attributes for the section.
7.6. .edata
(Export Section)
- Purpose: Contains information about exported functions and symbols.
- Structure Name:
IMAGE_SECTION_HEADER
- Contents:
IMAGE_EXPORT_DIRECTORY
structure.- Addresses of exported symbols.
- Symbol names and ordinals.
- Characteristics:
IMAGE_SCN_CNT_INITIALIZED_DATA
: Contains initialized data.IMAGE_SCN_MEM_READ
: Readable.
- Key Fields in Section Header:
Name
: Typically ".edata".VirtualSize
: Size of the section in memory.PointerToRawData
: Offset of the section's raw data in the file.Characteristics
: Attributes for the section.
7.7. .reloc
(Relocation Section)
- Purpose: Contains relocation information for fixing addresses when the PE file is loaded at a non-preferred base address.
- Structure Name:
IMAGE_SECTION_HEADER
- Contents:
IMAGE_BASE_RELOCATION
structures.- Relocation entries for specific addresses.
- Characteristics:
IMAGE_SCN_CNT_INITIALIZED_DATA
: Contains initialized data.IMAGE_SCN_MEM_READ
: Readable.
- Key Fields in Section Header:
Name
: Typically ".reloc".VirtualSize
: Size of the section in memory.PointerToRawData
: Offset of the section's raw data in the file.Characteristics
: Attributes for the section.
7.8. .rsrc
(Resource Section)
- Purpose: Stores application resources, such as icons, menus, dialogs, and strings.
- Structure Name:
IMAGE_SECTION_HEADER
- Contents:
- Resource data in a hierarchical format.
- Characteristics:
IMAGE_SCN_CNT_INITIALIZED_DATA
: Contains initialized data.IMAGE_SCN_MEM_READ
: Readable.
- Key Fields in Section Header:
Name
: Typically ".rsrc".VirtualSize
: Size of the section in memory.PointerToRawData
: Offset of the section's raw data in the file.Characteristics
: Attributes for the section.
Summary Table
Header/Section | Structure Name | Size (Bytes) | Purpose |
---|---|---|---|
DOS Header | `IMAGE_DOS_HEADER` | 64 | Legacy; points to PE header. |
PE Signature | Constant (`"PE\0\0"`) | 4 | Identifies the file as PE. |
File Header | `IMAGE_FILE_HEADER` | 20 | File metadata. |
Optional Header | `IMAGE_OPTIONAL_HEADER32`/ `IMAGE_OPTIONAL_HEADER64` |
96 / 112 | Detailed executable info. |
Section Headers | `IMAGE_SECTION_HEADER` | 40 per section | Describes file sections. |
Data Directories | `IMAGE_DATA_DIRECTORY` | 128 | Points to tables like import/export. |
Import Descriptor | `IMAGE_IMPORT_DESCRIPTOR` | 20 per entry | Details about imported DLLs/functions. |
Export Directory | `IMAGE_EXPORT_DIRECTORY` | 40 | Details about exported symbols. |
Base Relocation Table | `IMAGE_BASE_RELOCATION` | Varies | Relocation info for memory mapping. |
Resource Directory | `IMAGE_RESOURCE_DIRECTORY` | Varies | Resource data (icons, strings, etc.). |
Debug Directory | `IMAGE_DEBUG_DIRECTORY` | 28 per entry | Debugging info pointers. |
Summary
The Portable Executable (PE) format is the backbone of Windows executable files, facilitating efficient interaction between applications and the Windows operating system. Understanding its components—such as PE headers, section headers, and data directories—is essential for anyone involved in PE file analysis. From the DOS Header to the Section, each section defines the structure and behavior of the file during runtime.
Whether you're a developer optimizing your code, a reverse engineer dissecting Windows binaries, or a cybersecurity professional investigating potential threats, mastering the PE format is key to navigating and manipulating Windows executables effectively. This guide provides a foundational understanding to help you advance your skills in binary analysis, PE file analysis, and system programming.