# PE (Portable Executable) File Format Reference Reference for analyzing Windows PE files during malware static analysis. ## Overall Structure ``` +---------------------------+ | DOS Header (64 bytes) | e_magic = "MZ" (0x4D5A) | DOS Stub | "This program cannot be run in DOS mode" +---------------------------+ | PE Signature (4 bytes) | "PE\0\0" (0x50450000) +---------------------------+ | COFF File Header (20 B) | Machine, NumberOfSections, TimeDateStamp +---------------------------+ | Optional Header | EntryPoint, ImageBase, Subsystem | - Standard fields | | - Windows-specific | | - Data Directories | Import, Export, Resource, Security, etc. +---------------------------+ | Section Headers | .text, .data, .rdata, .rsrc, .reloc +---------------------------+ | Section Data | Actual code and data | .text (code) | | .rdata (read-only data) | | .data (initialized data) | | .rsrc (resources) | | .reloc (relocations) | +---------------------------+ | Overlay (optional) | Data beyond sections (packer stubs, appended data) +---------------------------+ ``` ## DOS Header (IMAGE_DOS_HEADER) | Offset | Size | Field | Description | |--------|------|-------|-------------| | 0x00 | 2 | e_magic | Magic number ("MZ" = 0x5A4D) | | 0x02 | 2 | e_cblp | Bytes on last page | | 0x3C | 4 | e_lfanew | Offset to PE header | **Malware relevance:** - e_lfanew offset manipulation to confuse parsers - Custom DOS stub with embedded payload - e_lfanew pointing to unusual locations ## COFF File Header (IMAGE_FILE_HEADER) | Offset | Size | Field | Description | |--------|------|-------|-------------| | 0x00 | 2 | Machine | Target CPU architecture | | 0x02 | 2 | NumberOfSections | Number of sections | | 0x04 | 4 | TimeDateStamp | Compilation timestamp (Unix epoch) | | 0x08 | 4 | PointerToSymbolTable | Usually 0 for executables | | 0x0C | 4 | NumberOfSymbols | Usually 0 | | 0x10 | 2 | SizeOfOptionalHeader | Size of Optional Header | | 0x12 | 2 | Characteristics | File attributes flags | **Machine values:** | Value | Architecture | |-------|-------------| | 0x014C | Intel 386 (i386) | | 0x8664 | AMD64 (x86-64) | | 0x01C0 | ARM | | 0xAA64 | ARM64 | **Characteristics flags:** | Flag | Value | Description | |------|-------|-------------| | IMAGE_FILE_EXECUTABLE_IMAGE | 0x0002 | File is executable | | IMAGE_FILE_LARGE_ADDRESS_AWARE | 0x0020 | Can handle >2GB addresses | | IMAGE_FILE_32BIT_MACHINE | 0x0100 | 32-bit word machine | | IMAGE_FILE_DLL | 0x2000 | File is a DLL | ## Optional Header ### Standard Fields | Field | Description | |-------|-------------| | Magic | 0x10B (PE32) or 0x20B (PE32+/64-bit) | | AddressOfEntryPoint | RVA of entry point | | BaseOfCode | RVA of code section start | ### Windows-Specific Fields | Field | Description | Malware Relevance | |-------|-------------|-------------------| | ImageBase | Preferred load address | Non-standard values may indicate packer | | SectionAlignment | Alignment in memory | | | FileAlignment | Alignment on disk | | | Subsystem | Required subsystem | GUI=2, CUI=3, Native=1 | | DllCharacteristics | DLL flags | ASLR, DEP, SEH settings | | SizeOfImage | Size in memory | | **DllCharacteristics (security flags):** | Flag | Value | Description | |------|-------|-------------| | DYNAMIC_BASE | 0x0040 | ASLR enabled | | FORCE_INTEGRITY | 0x0080 | Code integrity checks | | NX_COMPAT | 0x0100 | DEP enabled | | NO_SEH | 0x0400 | No SEH | | GUARD_CF | 0x4000 | Control Flow Guard | Malware often lacks ASLR and DEP flags for easier exploitation. ### Data Directories | Index | Name | Description | |-------|------|-------------| | 0 | Export Table | Exported functions (DLLs) | | 1 | Import Table | Imported functions | | 2 | Resource Table | Embedded resources | | 3 | Exception Table | Exception handler data | | 4 | Certificate Table | Digital signatures | | 5 | Base Relocation Table | Relocation entries | | 6 | Debug | Debug information | | 9 | TLS Table | Thread Local Storage | | 11 | Bound Import | Bound import descriptors | | 12 | IAT | Import Address Table | | 13 | Delay Import | Delay-loaded imports | | 14 | CLR Runtime Header | .NET metadata | ## Section Headers Each section header (40 bytes): | Offset | Size | Field | Description | |--------|------|-------|-------------| | 0x00 | 8 | Name | Section name (null-padded) | | 0x08 | 4 | VirtualSize | Size in memory | | 0x0C | 4 | VirtualAddress | RVA when loaded | | 0x10 | 4 | SizeOfRawData | Size on disk | | 0x14 | 4 | PointerToRawData | File offset of section data | | 0x24 | 4 | Characteristics | Section flags | **Section characteristics (flags):** | Flag | Value | Description | |------|-------|-------------| | IMAGE_SCN_CNT_CODE | 0x00000020 | Contains code | | IMAGE_SCN_CNT_INITIALIZED_DATA | 0x00000040 | Contains initialized data | | IMAGE_SCN_CNT_UNINITIALIZED_DATA | 0x00000080 | Contains uninitialized data | | IMAGE_SCN_MEM_EXECUTE | 0x20000000 | Executable | | IMAGE_SCN_MEM_READ | 0x40000000 | Readable | | IMAGE_SCN_MEM_WRITE | 0x80000000 | Writable | **Common sections:** | Name | Purpose | Typical Flags | |------|---------|---------------| | .text | Executable code | rx | | .rdata | Read-only data, imports | r | | .data | Read-write data | rw | | .rsrc | Resources (icons, strings, dialogs) | r | | .reloc | Relocation data | r | | .bss | Uninitialized data | rw | | .tls | Thread Local Storage | rw | | .edata | Export data | r | **Suspicious section indicators:** - Writable + Executable (WX) sections - Entry point not in .text section - Very high entropy (> 7.0) in code sections - Non-standard section names - VirtualSize >> SizeOfRawData (unpacking target) - SizeOfRawData = 0 with VirtualSize > 0 ## Import Table Structure chain: Import Directory Table -> Import Lookup Table -> Hint/Name Table Each import descriptor (20 bytes): | Offset | Size | Field | Description | |--------|------|-------|-------------| | 0x00 | 4 | OriginalFirstThunk | RVA to Import Lookup Table (ILT) | | 0x04 | 4 | TimeDateStamp | Bound import timestamp | | 0x08 | 4 | ForwarderChain | Forwarder chain index | | 0x0C | 4 | Name | RVA to DLL name string | | 0x10 | 4 | FirstThunk | RVA to Import Address Table (IAT) | **Import Hash (imphash):** Computed from ordered list of `library.function` names. Useful for clustering related samples even when code changes. ## Export Table | Field | Description | |-------|-------------| | NumberOfFunctions | Total exported functions | | NumberOfNames | Functions exported by name | | AddressOfFunctions | RVA to function address array | | AddressOfNames | RVA to name pointer array | | AddressOfNameOrdinals | RVA to ordinal array | **DLL malware indicators:** - Exports named to mimic legitimate DLLs (DLL side-loading) - Single export like `DllRegisterServer` (regsvr32 abuse) - Export names with random characters - Many ordinal-only exports (hiding function names) ## Resources Resource tree: Type -> Name/ID -> Language **Common resource types:** | ID | Type | Malware Use | |----|------|-------------| | 2 | RT_BITMAP | Icon mimicry | | 3 | RT_ICON | Fake file type appearance | | 6 | RT_STRING | Embedded strings/config | | 10 | RT_RCDATA | Custom data (payloads, configs) | | 14 | RT_GROUP_ICON | Icon resources | | 16 | RT_VERSION | Version information | | 24 | RT_MANIFEST | Application manifest | **Suspicious resource indicators:** - RT_RCDATA with high entropy (encrypted payload) - Resources with MZ/PE headers (embedded executables) - Abnormally large resources - Resources with no standard type ID (custom types) ## Overlay Data Data appended after the last section (beyond the PE structure). Offset: max(section.PointerToRawData + section.SizeOfRawData) for all sections. **Common overlay uses in malware:** - Packer stubs (UPX, ASPack append compressed data) - Configuration data - Additional encrypted payloads - Digital signature data (Authenticode) ## Rich Header Located between DOS stub and PE signature. Contains compiler/linker product IDs and build counts from Microsoft Visual Studio. **Structure:** ``` "DanS" (XOR key) | padding (XOR key) | [compid, count] pairs (XOR'd) | "Rich" | XOR key ``` **Analysis value:** - Identifies MSVC version used for compilation - Can be used to cluster related samples (same build environment) - Malware may forge or zero out Rich headers - Hash of Rich header data useful as an IOC ## TLS (Thread Local Storage) Callbacks TLS callbacks execute before the entry point, making them useful for: - Anti-debugging checks before main code runs - Unpacking stubs - Environment checks Check `IMAGE_DIRECTORY_ENTRY_TLS` for TLS directory presence. ## Quick Analysis Checklist 1. Check compilation timestamp for anomalies 2. Verify entry point is within a code section 3. Calculate section entropy (> 7.0 = likely packed) 4. Look for WX (writable+executable) sections 5. Count imports (< 10 = likely packed or API hashing) 6. Check for overlay data 7. Examine resources for embedded PE files 8. Calculate and look up imphash 9. Check for TLS callbacks 10. Verify DllCharacteristics security flags