PE format
TL;DR: Portable Executable is the Windows container for EXE/DLL/SYS/OBJ files — a DOS stub, a PE header, an optional header, section table, and sections. Understanding the data directories (IAT, EAT, reloc, TLS) is the entry point for reflective loading, hooking, packing, and shellcode analysis.
What it is
PE is the on-disk and in-memory format produced by the MS link.exe linker (derived from COFF). Loaders use it both to map the file into a process and to perform import resolution and base-relocation fix-ups. Almost every offensive technique on Windows that involves “load this thing without touching disk” is in some way a manual implementation of what LdrLoadDll would do — so PE literacy is a prerequisite for windows-api-and-syscalls tradecraft, EDR hook hunting, and binary patching.
Preconditions / where it applies
- Any time you parse, modify, or hand-craft Windows binaries (loaders, shellcode runners, malware analysis)
- Reflective DLL injection, manual mapping, module stomping
- Indirect-syscall and import-hashing tradecraft that walks the PEB loader list (windows-processes-and-threads)
- IAT/EAT hooking by EDRs — knowing the layout tells you what to bypass
Technique
Walk the structure top to bottom:
IMAGE_DOS_HEADERat offset 0 —e_magic == "MZ",e_lfanewis the offset to the NT headers.IMAGE_NT_HEADERS—Signature == "PE\0\0", thenFileHeader(machine, section count, characteristics) andOptionalHeader(entry point RVA, image base, subsystem, data directories).DataDirectory[16]— RVA/size pairs. The interesting ones:IMAGE_DIRECTORY_ENTRY_EXPORT— Export Address Table; howGetProcAddressresolves names.IMAGE_DIRECTORY_ENTRY_IMPORT— Import descriptors; an array ofIMAGE_IMPORT_DESCRIPTOReach pointing at an INT (names) and IAT (resolved pointers).IMAGE_DIRECTORY_ENTRY_BASERELOC— base relocations; needed when the image cannot load at its preferred base.IMAGE_DIRECTORY_ENTRY_TLS— TLS callbacks fire beforeAddressOfEntryPointand are a classic execution-stealth primitive.IMAGE_DIRECTORY_ENTRY_EXCEPTION— function tables used for SEH/x64 unwind.
- Section table —
IMAGE_SECTION_HEADERarray, one per section..text(RX),.data(RW),.rdata(R),.rsrc(R),.reloc(R).VirtualAddressis the in-memory RVA,PointerToRawDatais the file offset.
Manual map pseudo-flow:
1
2
3
4
5
6
7
buf = ReadFile(dll)
base = VirtualAlloc(preferredBase, SizeOfImage, MEM_COMMIT|RESERVE, PAGE_READWRITE)
copy headers + sections at their RVAs
walk BASERELOC, patch all absolute addresses by (base - ImageBase)
walk IMPORT, LoadLibrary each, GetProcAddress each thunk → write IAT
apply per-section page protections (VirtualProtect)
invoke TLS callbacks, then DllMain(DLL_PROCESS_ATTACH)
Quick triage with dumpbin /headers, pe-bear, CFF Explorer, or radare2 -A.
Relocation patching detail: each IMAGE_BASE_RELOCATION block is followed by an array of 16-bit entries where the top 4 bits encode the type (IMAGE_REL_BASED_DIR64 = 0xA on x64, IMAGE_REL_BASED_HIGHLOW = 3 on x86) and the bottom 12 bits encode the offset into the page named by VirtualAddress. Compute delta = actualBase - OptionalHeader.ImageBase once, then for every entry add delta to the QWORD/DWORD at base + block->VirtualAddress + (entry & 0xFFF). Stop iterating the block list when SizeOfBlock == 0. Skip entries of type IMAGE_REL_BASED_ABSOLUTE (0) — they exist purely as 8-byte alignment padding and patching them corrupts the next code page.
Detection and defence
- EDRs hash known-good
.textof ntdll/kernel32 and detect tampering — module stomping that overwrites sections shows up here - Loaded modules absent from the PEB
InLoadOrderModuleList(manual map) are flagged by tools like Moneta / Pe-Sieve - TLS callbacks executing before entry-point are a known evasion — modern AV inspects them
- Unbacked RX memory regions (no
MappedFilebacking) are the cleanest manual-map IoC - Hardening: enforce code-signing, Arbitrary Code Guard, CIG (Code Integrity Guard), and “block unsigned DLLs” mitigation policies per process
References
- Microsoft — PE Format spec — authoritative field-by-field reference
- HackTricks — PE binaries — offensive-lens summary
- Corkami PE poster — one-page visual map of the format
- ired.team — PE Injection: Executing PEs inside Remote Processes — manual map walkthrough with IMAGE_BASE_RELOCATION block iteration and delta patching