Skip to content

The PE File Format for Incident Responders

What matters in a Windows PE file when you triage a suspicious EXE, DLL or driver: headers, sections, imports, resources, signature and overlay.

Published on Updated on 5 min read

TL;DR. A Windows executable is a map: an MS-DOS header points to the PE header, the PE header describes how to load the file, and a table of sections says which bytes go where. Most first-triage questions — what is it, who built it, when, what can it do, is it signed, is something hidden in it — are answered by reading that map, without running anything. The PE Parser does it in your browser.

This article is the entry point of the series. It walks through the structure in the order a responder needs it, with the field names used by Microsoft's PE Format specification.

The layout at a glance

PartWhereWhat you get from it
MS-DOS headeroffset 0, starts with MZe_lfanew, the offset of the PE header; the DOS stub and, often, the Rich header
PE signature + COFF file headerat e_lfanewmachine (x86, x64, ARM64), number of sections, TimeDateStamp, characteristics (EXE or DLL)
Optional headerright afterPE32 or PE32+, entry point, image base, subsystem, checksum, DLL characteristics (ASLR, DEP, CFG), 16 data directories
Section tableafter the optional headername, virtual and raw size, file offset and permissions of each section
Data directoriesinside sectionsimports, exports, resources, certificates, debug, TLS, load config, relocations, .NET
Overlayafter the last sectionanything appended: installer payloads, archives, configuration, signatures

Everything is little-endian. Addresses inside the image are RVAs (relative virtual addresses); converting an RVA to a file offset goes through the section table, which is why a damaged section table breaks every tool at once.

Headers: identity and build

The COFF header's TimeDateStamp is the classic compile time, in Unix seconds. It can be forged, zeroed, or — in recent Microsoft and .NET builds — replaced by a hash, as explained in PE timestamps. The optional header tells you whether the file is 32-bit (magic 0x10b, PE32) or 64-bit (0x20b, PE32+), where execution starts (AddressOfEntryPoint) and which exploit mitigations were requested (DYNAMIC_BASE for ASLR, NX_COMPAT for DEP, GUARD_CF for Control Flow Guard).

The CheckSum field is ignored for ordinary executables but required for drivers. A stored checksum that no longer matches the recomputed one hints that bytes changed after linking.

Sections: where code and data live

A typical Microsoft-linked program has .text (code), .rdata (read-only data and import tables), .data, .pdata (x64 exception data), .rsrc and .reloc. Three things deserve attention:

  • Permissions. A section that is both writable and executable is unusual for compiler output and common for packers.
  • Entropy. Close to 8 bits per byte means compressed or encrypted content. In a code section it usually means packing — see detecting packed executables.
  • Names. Names are free text. UPX0/UPX1, .vmp0 or .themida are hints, not proof, and a packer can be renamed.

Imports and exports: capabilities

The import directory lists every DLL and function the loader must resolve and patches their addresses into the import address table. Imports are the fastest capability overview: WinHttpOpen means HTTP, CreateRemoteThread means code in another process, RegSetValueExW means registry writes. Very few imports plus LoadLibrary/GetProcAddress suggests the real ones are resolved at run time. The import list also gives the imphash, used to cluster samples (imphash, Rich header and TLSH).

DLLs export functions by name and ordinal; a DLL with a single export such as DllRegisterServer or ServiceMain tells you how it expects to be loaded.

Resources, debug data and signature

Resources carry the version information (CompanyName, FileDescription, OriginalFilename), the manifest (requested privilege level), icons, dialogs and string tables — and sometimes an embedded executable. OriginalFilename that differs from the name on disk is a quick masquerading check.

The debug directory usually holds a CodeView record with the PDB path, a GUID and an age. Build paths such as C:\Users\<name>\source\repos\… leak the author's environment (PDB path).

The certificate table holds the Authenticode signature. It is not mapped into memory and sits after the sections, which is why it is excluded from the file hash that gets signed. What a signature does and doesn't prove is covered in Authenticode offline.

A first-triage checklist

  1. Hash it (MD5, SHA-1, SHA-256) and search your intelligence sources; compute the imphash.
  2. Read the times: compile, debug, signature. Do they agree with each other and with the incident?
  3. Check the signature: present, matching the file, who signed, when.
  4. Scan imports and strings for capabilities and indicators (URLs, IP addresses, paths, registry keys).
  5. Look at sections: permissions, entropy, entry point location; check for an overlay.
  6. Read the version information and PDB path; compare with the file name and location.

The PE Parser runs this checklist on one file or a whole collection and explains each indicator in plain words. It is static only: it unpacks UPX and extracts executables hidden inside a file, but other packers have to be unpacked elsewhere, and nothing it shows is a verdict on its own.

FAQ

What is a PE file?

Portable Executable is the file format of Windows programs and libraries: .exe, .dll, .sys drivers, .scr, .cpl, .ocx and EFI binaries. It starts with an MS-DOS header (MZ), followed by the PE signature, a COFF file header, an optional header and a section table.

Which PE fields matter most in a first triage?

Hashes and imphash for intelligence lookups, the compile, debug and signing times, the import table, the section table with entropy and permissions, the version information, the Authenticode signature and any data appended after the last section (overlay).

Related articles

Step-by-step static triage of Windows executables with the free PE Parser: load files or a ZIP, read indicators, compare builds and export results.
Find and copy suspicious EXE, DLL and SYS files from a Windows host or image without running them: PowerShell, Velociraptor, disk images and pitfalls.
Where a Windows executable stores its times, which ones can be trusted, how reproducible builds and timestomping show up, and how to use them.