1. Introduction to the PE Format
The Portable Executable (PE) format is like a blueprint that Windows uses to run programs. Every .exe, .dll, or .sys file in Windows follows this format. Think of it as a well-organized container that holds everything the operating system needs to load and execute a program safely.
The Portable Executable (PE) format is the standard file format used in Windows for:
- Executable files →
.exe - Dynamic libraries →
.dll - System drivers →
.sys .NET executables (with additional layers)
The PE format contains all the information the Windows loader needs to:
- load the program into memory,
- map sections to the correct addresses,
- resolve imported libraries,
- run the program safely and correctly.
Think of PE as a “complete instruction book” that Windows reads before running an application.
2. Why Should We Study the PE Format?
Because it helps us understand:
- How Windows loads and runs programs
- How malware hides and executes
- How debuggers parse binaries
- How packers and protectors work
- How reverse engineering tools (IDA, Ghidra, x64dbg) interpret executables
- How digital forensics analysts examine suspicious files
Understanding the PE format is a foundational skill for cybersecurity roles.
3. High-Level Structure of a PE File
A Windows PE file is made of several layers stacked one after another.
Here’s a simplified overview:
4. IMAGE_DOS_HEADER (The DOS Header)
This is the very first structure in a PE file.
Purpose:
- Compatibility with very old DOS systems
- Allows DOS to display:
- "This program cannot be run in DOS mode."
Important Field:
- e_lfanew → offset to the actual PE header
This value tells Windows where to find
"PE\0\0".
You can think of this as:
“Start reading the real PE data from this location.”
5. DOS Stub Program
A tiny piece of 16-bit code.
If someone tries to run the EXE in DOS, it prints the classic message.
Not useful today, but required by the PE standard.
6. PE Signature ("PE\0\0")
At the offset given by e_lfanew, Windows expects the bytes:
50 45 00 00
Which corresponds to “PE\0\0”.
This confirms the file is a valid PE executable.
7. COFF File Header (IMAGE_FILE_HEADER)
This is a short header providing basic information about the file.
Key Fields:
- Machine → CPU architecture (e.g., x86, x64, ARM)
- NumberOfSections → how many sections follow
- TimeDateStamp → compilation timestamp
- Characteristics → flags (executable, DLL, etc.)
This header helps Windows prepare memory structures for loading.
8. Optional Header (IMAGE_OPTIONAL_HEADER)
Despite the name, this header is mandatory for executables.
It contains crucial loading information.
Important Fields:
- AddressOfEntryPoint → where execution begins
- ImageBase → preferred memory address for loading
- SectionAlignment → how sections are aligned in memory
- FileAlignment → how sections are aligned in the file
- SizeOfImage → total memory footprint
- Subsystem → console app or GUI app
- Data Directories → pointers to import table, export table, resources, relocations, etc.
The Optional Header is the heart of the PE file.
It tells Windows exactly how to prepare memory for the program.
9. Section Headers (IMAGE_SECTION_HEADER)
Immediately after the Optional Header comes an array of section headers.
Each section header contains:
- name (e.g.,
.text,.data) - size in file
- size in memory
- permissions (Read/Write/Execute)
- file offset
- virtual memory address
These headers tell Windows how to load each section into memory.
10. Common PE Sections (Beginner-Friendly Overview)
1. .text
- Contains machine code (instructions)
- Usually Read + Execute
- Most critical part of the program
2. .data
- Contains initialized global variables
- Read + Write
- Example:
int x = 10;
3. .rdata (Read-Only Data)
- Contains constants and string literals
- Also contains IMPORT and EXPORT tables
4. .bss
- Contains uninitialized global variables
- Does not take space in file
- Allocated during runtime
5. .rsrc (Resource Section)
- Icons, menus, dialogs, manifest, version info
6. .reloc
- Contains relocation information
- Needed when the program cannot load at its preferred ImageBase
11. Data Directories (Inside Optional Header)
These are pointers to various tables.
Important ones:
- Import Table → functions the program needs (
printf,CreateFileW, etc.)
- Export Table → functions the DLL exposes
- Resource Table → icons, dialogs
- Exception Table
- Relocation Table
- Security Table (Digital Signature)
Think of them as “index cards” pointing deeper into the file.
12. PE Loading Process (Simplified)
When you double-click an EXE:
- Windows reads
IMAGE_DOS_HEADER
- Jumps to PE header using
e_lfanew
- Reads COFF + Optional Header
- Loads sections into memory based on Section Headers
- Performs relocations if needed
- Resolves imports (links to Windows DLLs)
- Sets up the stack, heap, TLS
- Finally jumps to AddressOfEntryPoint
This is similar in concept to ELF loading but with Windows-specific structures.
13. Why Does Windows Use PE Format?
- Supports backward compatibility with DOS
- Works across CPU architectures
- Efficient for dynamic linking
- Flexible for resources (icons, dialogs, forms)
- Easy integration with .NET and COM
- Security features (ASLR, DEP, signatures)
14. PE vs ELF (Simple Comparison)
| Feature | PE (Windows) | ELF (Linux) |
|---|---|---|
| Linking style | Import tables | Dynamic linker + sections |
| Resources | Built into file | Stored externally |
| Starter header | DOS header | ELF header |
| Relocations | Required for ASLR | Required for PIE |
| Tools | PEview, CFF, x64dbg | readelf, objdump, gdb |
15. Summary
If you strip away the scary names and big tables, PE format comes down to:goog_1810305548
- DOS Header → tells Windows where the PE header starts
- PE Header → identifies file as a Windows executable
- File Header → describes section count & architecture
- Optional Header → tells Windows how to map program into memory
- Section Headers → map raw data into virtual memory
- Sections → actual program data and code
That’s it.
