Skip to main content

PE File Structure for Malware Analysis: A Practical Guide

PE File Structure for Malware Analysis practical guide cover

Article Metadata
  • Category: Malware Analysis
  • Topics: Portable Executable, PE Format, Windows Internals, Reverse Engineering, Static Analysis, Digital Forensics, x86, x64, AIDebug
  • Source article: Medium publication
  • Published: 2026-08-10
  • Preserved media: 34 image(s), including the cover, PE reference diagrams, AIDebug screenshots, and the Windows loader infographic.
  • Published scope: Chapters 0–20 and references, matching the public Medium edition rather than the longer working draft.

Ecosystem Fit

This guide connects the Malware Analysis knowledge base, visual guides library, TrainSec helping materials, and hands-on lab collection. Continue into Assembly for Malware Analysis after mapping the image, and use the safe malware-analysis lab guide before inspecting unknown samples.

The Portable Executable format is the structural language of native Windows software. Executables, DLLs, drivers, control-panel applets, and many .NET assemblies all use the same broad container. Before Windows can start the code, its loader must answer a series of questions encoded in that container:

  • What architecture is this image built for?
  • Where should it be mapped?
  • Which bytes contain code, initialized data, or zero-filled storage?
  • Which DLLs and functions must be resolved?
  • Where does execution begin?
  • Which addresses require relocation?
  • Does initialization code run before the nominal entry point?
  • Which security mitigations and trust metadata are present?

A malware analyst asks the same questions—but with an adversarial assumption: every field is untrusted, names may be deceptive, timestamps may be forged, and different parsers may disagree.

This guide explains PE structure from that defensive perspective. It focuses on PE32 and PE32+ image files used by 32-bit and 64-bit Windows. It does not attempt to document every COFF object-file feature or every processor-specific relocation. Instead, it teaches the structures, calculations, and evidence that matter most during static analysis and reverse engineering.

For the next layer down, use Assembly for Malware Analysis. For the environment in which to inspect unknown files safely, begin with How to Build a Safe Malware Analysis Lab.

Scope and safety: Parsing is safer than executing, but parsers also contain vulnerabilities. Inspect untrusted PE files in an isolated analysis VM, keep tools patched, disable preview handlers and shell extensions, and never double-click a sample. All commands in this guide read metadata; none intentionally executes the target.

0. Using AIDebug for PE analysis

AIDebug provides a read-only PE structure workspace alongside hexadecimal inspection, disassembly, optional Ghidra reconstruction, and hash-indexed analysis history.

Install it inside the isolated analysis VM:

git clone https://github.com/anpa1200/AIDebug.git
cd AIDebug
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e .

Open a PE without executing it or transmitting evidence to a remote AI provider:

aidebug --binary /path/to/suspicious.exe --offline

Press X in the main interface. AIDebug recognizes the PE and presents:

  • complete file hex with offsets and ASCII;
  • DOS, NT, COFF, and optional headers;
  • sections with RVA, VA, raw ranges, entropy, and characteristics;
  • data-directory addresses and sizes;
  • normal and delay-loaded imports;
  • exports, ordinals, and forwarders;
  • image base, entry point, SHA-256, and overlay boundaries.

Use PageUp and PageDown to navigate paged evidence, Home and End to jump to its boundaries, and Escape to return to function analysis. P is an additional shortcut for the PE workspace.

For C-like Ghidra reconstruction, restart with:

aidebug --binary /path/to/suspicious.exe --offline --decompile

The reconstruction is not original source. Verify its inferred types, addresses, imports, and control flow against the PE map and real instructions. AIDebug is a first-pass analysis environment, not the sole authority for every resource, relocation, TLS, certificate, load-configuration, exception, or CLR record; corroborate important findings with another parser.

Table of contents

  1. Using AIDebug for PE analysis
  2. Why PE structure matters
  3. The two views: file on disk and image in memory
  4. The address vocabulary: file offsets, RVAs, and VAs
  5. The high-level PE layout
  6. The DOS header, DOS stub, and PE signature
  7. The COFF file header
  8. The optional header: the loader's map
  9. Data directories: routes to important structures
  10. The section table and section data
  11. Imports, thunks, and the IAT
  12. Exports and forwarded functions
  13. Resources
  14. Base relocations and ASLR
  15. TLS data and callbacks
  16. Exception and unwind information
  17. Load configuration and exploit mitigations
  18. Authenticode certificates and signatures
  19. Debug data, the Rich header, and overlays
  20. .NET assemblies inside PE files
  21. How the Windows loader uses the image
  22. References

1. Why PE structure matters

PE metadata gives an analyst a fast, execution-free first model of a sample. It can reveal:

  • architecture, subsystem, and image type;
  • preferred base address and entry-point RVA;
  • code and data regions with their intended memory permissions;
  • imported modules and functions;
  • exported entry points;
  • embedded icons, manifests, version records, dialogs, strings, and binary resources;
  • relocation, TLS, exception, and load-configuration data;
  • digital signatures and debug artifacts;
  • indicators of managed .NET code;
  • inconsistencies associated with packing, corruption, or deliberate parser evasion.

The word can matters. A header describes how the image wants to be treated; it does not prove what executes. Imports suggest possible capabilities, section names suggest intended roles, and a signature reports a trust relationship. Runtime behavior still depends on code paths, arguments, environment, loader decisions, and data that may be decoded only after startup.

A strong PE analysis therefore has three layers:

  1. Structural observation: what the file declares and where the relevant bytes are.
  2. Behavioral inference: what those structures and referenced APIs suggest.
  3. Validation: what disassembly, decompilation, or controlled runtime evidence confirms.

The 1200km Malware Analysis knowledge base uses the same evidence-first discipline.

2. The two views: file on disk and image in memory

The most important PE concept is that a file's disk layout is not identical to its loaded memory layout.

On disk, the file is arranged for storage:

headers
section 1 raw bytes
section 2 raw bytes
section 3 raw bytes
optional certificate data
optional overlay

In memory, the loader creates an image organized by relative virtual addresses:

image base + headers
image base + section 1 RVA
image base + section 2 RVA
image base + section 3 RVA
zero-filled virtual tails

Two alignment rules drive the difference:

  • FileAlignment aligns section data in the file.
  • SectionAlignment aligns sections in virtual memory.

A typical PE might use a file alignment of 0x200 bytes and a section alignment of 0x1000 bytes. Consequently, bytes found at file offset 0x600 might be mapped at RVA 0x2000. Copying a file offset directly into a debugger address will often land in the wrong place.

What is not necessarily mapped

Not every byte in a PE file becomes part of the image:

  • the certificate table is addressed by file offset and is not mapped as an ordinary image directory;
  • arbitrary overlay data after the mapped section content is normally not mapped;
  • debug information may be stored outside mapped sections;
  • file-alignment padding and some section slack may have no meaningful loaded representation.

Conversely, memory can contain bytes that do not exist in the file. If a section's virtual size exceeds its raw size, the remaining memory is zero-filled.

This distinction explains why a disk scanner, a PE parser, a debugger, and a process-memory dumper can report different offsets and sizes without any of them necessarily being wrong.

3. The address vocabulary: file offsets, RVAs, and VAs

PE analysis becomes much easier when three address forms are kept separate.

TermMeaningExample
File offsetPosition from the first byte of the file0x640
RVARelative virtual address from the image base0x1234
VAVirtual address in a loaded process0x0000000140001234

File offsets, relative virtual addresses, and virtual addresses compared

The basic relationship is:

VA = actual image base + RVA

If the image is loaded at its preferred base:

VA = OptionalHeader.ImageBase + RVA

ASLR may choose a different actual base, so an address copied from one process run may not be valid in the next.

Converting an RVA to a file offset

For an RVA inside a section:

delta = RVA - section.VirtualAddress
file offset = section.PointerToRawData + delta

The calculation is valid only when the delta points to bytes actually present in the section's raw file data. If delta >= SizeOfRawData but the RVA is still inside the section's virtual range, the address refers to zero-filled memory rather than a byte stored in the file.

For an RVA inside the headers, the RVA often equals the file offset, subject to a valid SizeOfHeaders and file bounds.

Analyst rule: Never convert an RVA with one global subtraction. Select the containing section first, then apply that section's mapping.

4. The high-level PE layout

A normal PE image follows this broad order:

Portable Executable file structure from DOS header through overlay data

+-------------------------------+ file offset 0
| IMAGE_DOS_HEADER | "MZ"
+-------------------------------+
| DOS stub / linker data |
+-------------------------------+ e_lfanew points here
| PE signature | "PE\0\0"
+-------------------------------+
| IMAGE_FILE_HEADER | COFF file header
+-------------------------------+
| IMAGE_OPTIONAL_HEADER | PE32 or PE32+
| standard fields |
| Windows-specific fields |
| data-directory entries |
+-------------------------------+
| IMAGE_SECTION_HEADER[] | one per declared section
+-------------------------------+ SizeOfHeaders
| section raw data |
| .text / .rdata / .data / ... |
+-------------------------------+
| certificate / debug / overlay |
+-------------------------------+ end of file

The format is navigated through offsets and counts, not by assuming that every compiler emits an identical layout.

AIDebug whole-file hexadecimal PE view

AIDebug PE headers overview

Important consequences:

  • the PE header does not have to begin at a fixed offset;
  • the optional header has a size recorded in the file header;
  • the number of data directories must be read before indexing one;
  • the section table location depends on the optional-header size;
  • section names are labels, not authoritative types;
  • directory structures can live in sections with unexpected names.

5. The DOS header, DOS stub, and PE signature

IMAGE_DOS_HEADER

The first two bytes of a conventional PE image are:

4D 5A MZ

This is the e_magic field of IMAGE_DOS_HEADER. The legacy header exists because PE evolved from DOS-compatible executable conventions.

The field that matters most to a modern analyst is e_lfanew at file offset 0x3c. It contains the file offset of the PE signature.

Conceptually:

pe_offset = dos_header.e_lfanew;

AIDebug hexadecimal view of a PE DOS header

Before following it, a parser must validate that:

  • the file is large enough to contain e_lfanew;
  • the value does not point before required DOS-header data;
  • the target offset and subsequent headers fit inside the file;
  • arithmetic used to calculate later structures does not overflow.

The MZ magic alone does not prove that the file contains a valid PE image.

DOS stub

The region between the DOS header and the PE signature often contains a small DOS-mode program that prints:

This program cannot be run in DOS mode.

Typical PE DOS stub bytes and message

Modern linkers may also place toolchain-specific data in this area. Malware can overwrite, expand, encrypt, or repurpose it. Treat unusual stub content as evidence to investigate, not an automatic verdict.

PE signature

At the offset given by e_lfanew, an image normally contains:

50 45 00 00 PE\0\0

The 4-byte signature is followed immediately by the 20-byte COFF file header.

6. The COFF file header

The IMAGE_FILE_HEADER describes the target machine and the tables that follow.

FieldAnalyst meaning
MachineTarget architecture
NumberOfSectionsNumber of section-table entries
TimeDateStampLinker-supplied timestamp-like value
PointerToSymbolTableCOFF symbol-table pointer; normally zero in images
NumberOfSymbolsCOFF symbol count; normally zero in images
SizeOfOptionalHeaderExact byte size of the optional header
CharacteristicsImage-wide flags

IMAGE_FILE_HEADER fields and their analyst meaning

AIDebug COFF file header presentation

Machine types

Common values include:

ValueConstantMeaning
0x014cIMAGE_FILE_MACHINE_I386Intel 386-compatible 32-bit x86
0x8664IMAGE_FILE_MACHINE_AMD64x86-64
0x01c4IMAGE_FILE_MACHINE_ARMNTARM Thumb-2
0xaa64IMAGE_FILE_MACHINE_ARM64ARM64

Do not infer architecture from the filename or MZ signature. Use Machine together with the optional-header magic.

Number of sections

NumberOfSections tells a parser how many 40-byte section headers follow the optional header. Validate the resulting table against the file size:

section table offset
= e_lfanew
+ 4 # PE signature
+ 20 # IMAGE_FILE_HEADER
+ SizeOfOptionalHeader

Then confirm:

section table offset + NumberOfSections × 40 <= file size

An absurd section count can be corruption, parser fuzzing, or deliberate evasion.

TimeDateStamp

Historically, TimeDateStamp was interpreted as seconds since 1 January 1970 UTC. In real investigations it may be:

  • a plausible linker time;
  • zero;
  • copied from another sample;
  • intentionally backdated or future-dated;
  • transformed for a reproducible build;
  • modified by a packer or post-processing tool.

Record it as a claimed or tool-generated value—not as proof of compilation time or attribution.

Characteristics

Useful flags include:

  • IMAGE_FILE_EXECUTABLE_IMAGE;
  • IMAGE_FILE_DLL;
  • IMAGE_FILE_SYSTEM;
  • IMAGE_FILE_LARGE_ADDRESS_AWARE;
  • IMAGE_FILE_RELOCS_STRIPPED;
  • IMAGE_FILE_32BIT_MACHINE.

These bits should be interpreted with Machine, the optional header, and the actual directory content. Contradictions are worth documenting.

7. The optional header: the loader's map

The optional header is optional for COFF object files but required for executable images. Its first field, Magic, selects the layout:

MagicFormatCommon use
0x10bPE3232-bit image
0x20bPE32+64-bit-capable image
0x107ROMROM image

Optional-header Magic values for PE32, PE32+, and ROM images

AIDebug optional-header field view

PE32+ is not simply PE32 with every field widened. Notable differences include:

  • ImageBase is 8 bytes in PE32+;
  • stack and heap reserve/commit fields are 8 bytes in PE32+;
  • BaseOfData exists in PE32 but is absent in PE32+;
  • import thunk entries are 32 bits in PE32 and 64 bits in PE32+.

Always parse according to Magic and respect SizeOfOptionalHeader.

Standard fields

High-value standard fields include:

FieldMeaning
SizeOfCodeCombined size of code sections, rounded according to file rules
SizeOfInitializedDataCombined initialized-data size
SizeOfUninitializedDataCombined uninitialized-data size
AddressOfEntryPointRVA where image startup normally begins
BaseOfCodeRVA of the beginning of code
BaseOfDataPE32-only data base

PE optional-header standard fields

AIDebug detailed optional-header values

AddressOfEntryPoint is not necessarily a source-level main or WinMain. It commonly points to:

  • C/C++ runtime startup;
  • a DLL initialization stub;
  • a driver entry routine;
  • a packer or protector stub;
  • a managed-runtime bootstrap;
  • a custom loader.

TLS callbacks can execute before the nominal entry point. A zero entry-point RVA is valid for an image that has no entry point.

Windows-specific fields

FieldWhy analysts use it
ImageBasePreferred load address
SectionAlignmentIn-memory section alignment
FileAlignmentOn-disk section alignment
SizeOfImageTotal aligned mapped-image size
SizeOfHeadersAligned size of all headers
CheckSumImage checksum used for selected Windows image classes
SubsystemGUI, console, native, EFI, and other runtime environments
DllCharacteristicsMitigation and loader-behavior flags
SizeOfStackReserve/CommitInitial stack policy
SizeOfHeapReserve/CommitInitial heap policy
NumberOfRvaAndSizesNumber of directory entries present

Windows-specific optional-header fields and why analysts use them

Alignment

The specification normally requires:

SectionAlignment >= FileAlignment

FileAlignment is generally a power of two between 512 bytes and 64 KiB. If SectionAlignment is below the architecture's page size, FileAlignment must match it, and low-alignment images follow tighter mapping rules.

Values that are zero, non-power-of-two where prohibited, contradictory, or inconsistent with section locations are structural warnings.

SizeOfImage and SizeOfHeaders

SizeOfImage covers the loaded headers and sections rounded to SectionAlignment. It is a memory-image size, not the file length.

SizeOfHeaders covers the DOS area, PE signature, file header, optional header, and section table rounded to FileAlignment.

A file can be larger than SizeOfImage because disk-only data may follow mapped sections. It can also be smaller than SizeOfImage because uninitialized and zero-filled virtual space does not require raw bytes.

Subsystem

Common values describe:

  • Windows GUI;
  • Windows console;
  • native subsystem;
  • EFI application or driver;
  • boot application.

Subsystem affects startup expectations but does not identify intent. A console binary can hide its window; a GUI binary can allocate a console; a native image may be a legitimate system component or a specialized malicious implant.

DllCharacteristics and mitigation clues

High-value flags include:

  • IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE — image can participate in base relocation/ASLR;
  • IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA — supports high-entropy 64-bit address space where applicable;
  • IMAGE_DLLCHARACTERISTICS_NX_COMPAT — image is compatible with data-execution prevention;
  • IMAGE_DLLCHARACTERISTICS_GUARD_CF — image was built with Control Flow Guard instrumentation/metadata;
  • IMAGE_DLLCHARACTERISTICS_NO_SEH — image does not use structured exception handling under applicable conditions;
  • IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE.

A flag is a declaration. Confirm that supporting structures exist—for example, relocations for practical ASLR and load-configuration data for CFG.

AIDebug DllCharacteristics mitigation clues

8. Data directories: routes to important structures

The end of the optional header contains an array of address-and-size pairs. These are data directories.

AIDebug optional-header data directories

Before reading directory index n, validate:

  • NumberOfRvaAndSizes > n;
  • SizeOfOptionalHeader is large enough to contain that entry;
  • the address and size are internally consistent;
  • the referenced range maps to valid file bytes when disk content is required.

The commonly defined directory indexes are:

IndexDirectoryPrimary analytical use
0ExportFunctions/data exposed by the image
1ImportDLLs and symbols requested at normal load
2ResourceIcons, manifests, versions, strings, embedded data
3ExceptionFunction/unwind information, especially on x64
4CertificateAuthenticode attribute certificates
5Base RelocationFixups used when image base changes
6DebugCodeView/PDB and other debug records
7ArchitectureReserved
8Global PtrArchitecture-specific global pointer
9TLSThread-local storage and callbacks
10Load ConfigSecurity cookie, CFG, SafeSEH, and evolving loader metadata
11Bound ImportPrebound import metadata
12IATImport Address Table range
13Delay ImportSymbols resolved on first use
14CLR Runtime.NET/CLI header
15ReservedMust be treated as reserved

PE data-directory indexes and their primary analytical use

The certificate-table exception

For almost every image directory, the first value is an RVA. Directory index 4 is the major exception: its “virtual address” field is a file offset to the certificate table because certificate data is not loaded as part of the image.

This exception breaks generic “directory RVA to section” code and is a frequent source of parser mistakes.

A zero directory

An address and size of zero usually mean the directory is absent. An address with zero size, a size with zero address, a range outside the image, or a range that crosses unrelated data should be treated cautiously.

The directory does not need to live in the section whose conventional name suggests it. Imports may be found in .rdata, .idata, or a custom section. Parse by directory address, not by name.

9. The section table and section data

Each IMAGE_SECTION_HEADER is 40 bytes and connects a region of the file to a region of the loaded image.

FieldMeaning
NameUp to eight bytes of section-name data
VirtualSizeMeaningful size when loaded
VirtualAddressSection RVA
SizeOfRawDataAligned byte count stored in the file
PointerToRawDataFile offset of raw section bytes
PointerToRelocationsCOFF relocation pointer; normally zero for images
PointerToLinenumbersDeprecated COFF line-number pointer
NumberOfRelocationsCOFF relocation count
NumberOfLinenumbersCOFF line-number count
CharacteristicsContent and memory-permission flags

IMAGE_SECTION_HEADER fields and meanings

Common section names

NameConventional content
.textExecutable code
.rdataRead-only data, imports, strings, metadata
.dataInitialized writable data
.bssUninitialized writable data
.idataImport structures
.edataExport structures
.rsrcResources
.relocBase relocations
.pdataException/function table
.tlsTLS template/callback-related data
.debugDebug information

Common PE section names and conventional content

AIDebug IMAGE_SECTION_HEADER record view

These are conventions, not enforcement. A section called .text can hold data; executable code can live in .data; packers routinely use custom or misleading names.

VirtualSize versus SizeOfRawData

The two sizes answer different questions:

  • SizeOfRawData: how many aligned bytes are stored in the file;
  • VirtualSize: how much meaningful space the section requests in memory.

Common cases:

  1. Raw size greater than virtual size: the file contains alignment padding after meaningful virtual content.
  2. Virtual size greater than raw size: the loader zero-fills the remaining memory.
  3. Raw size zero, virtual size nonzero: uninitialized storage such as .bss.
  4. Both unexpectedly huge or inconsistent: corruption, unusual linker behavior, or evasion.

Do not hash or extract padding as if it were necessarily meaningful. Do not attempt to read zero-filled virtual bytes from beyond the end of the raw section.

Section characteristics

Content flags include:

  • IMAGE_SCN_CNT_CODE;
  • IMAGE_SCN_CNT_INITIALIZED_DATA;
  • IMAGE_SCN_CNT_UNINITIALIZED_DATA.

Memory flags include:

  • IMAGE_SCN_MEM_READ;
  • IMAGE_SCN_MEM_WRITE;
  • IMAGE_SCN_MEM_EXECUTE;
  • IMAGE_SCN_MEM_SHARED;
  • IMAGE_SCN_MEM_DISCARDABLE.

Useful observations:

  • executable and writable (RWX) is high-priority evidence but not proof of malware;
  • code in a non-executable section may indicate malformed metadata, a protector, or a parser mismatch;
  • an executable section with high entropy and a small entry stub can suggest packing;
  • a discardable relocation section is normal;
  • a writable IAT-containing region can be normal because the loader must update it.

Section overlap and slack

Check for:

  • overlapping raw ranges;
  • overlapping virtual ranges;
  • raw pointers inside the headers;
  • sections extending beyond end-of-file;
  • directory entries that cross section boundaries;
  • data between the end of meaningful virtual content and the end of raw data;
  • data between the end of one raw section and the next aligned section.

Slack can contain linker padding, stale bytes, deliberately hidden data, or nothing of interest. Its presence requires inspection, not immediate classification.

10. Imports, thunks, and the IAT

Imports describe external symbols the image expects the loader—or a delay-load helper—to resolve.

Import descriptors

The import directory is an array of IMAGE_IMPORT_DESCRIPTOR records, normally terminated by an all-zero descriptor.

Important fields include:

FieldRole
OriginalFirstThunkRVA of the Import Lookup Table (ILT), also called the Import Name Table
TimeDateStampBinding-related value
ForwarderChainLegacy binding information
NameRVA of the imported DLL name
FirstThunkRVA of the Import Address Table (IAT)

IMAGE_IMPORT_DESCRIPTOR fields and roles

AIDebug import-descriptor records

One descriptor represents one imported DLL.

Import Lookup Table

The ILT is an array of pointer-sized thunk entries:

  • 32-bit entries in PE32;
  • 64-bit entries in PE32+;
  • zero terminates the array.

Each nonzero thunk usually identifies an import:

  • if the high ordinal flag is set, the remaining bits encode an ordinal;
  • otherwise, the value is an RVA to IMAGE_IMPORT_BY_NAME, which contains a 2-byte hint followed by a null-terminated ASCII symbol name.

The hint is an optimization clue, not the identity by itself. The name or ordinal resolution is authoritative for the import request.

Import Address Table

On disk, the IAT commonly resembles the ILT. During loading, its entries are replaced with resolved function addresses. Calls can then use indirection:

call qword ptr [rip+__imp_CreateFileW]

An import thunk may end with a jmp through an IAT slot rather than a call. See the assembly guide for call-site and thunk interpretation.

AIDebug resolved imports and IAT addresses

Imports as capability evidence

Imports help prioritize investigation:

Import groupPossible question
CreateFileW, ReadFile, WriteFileWhat local or device data is accessed?
RegOpenKeyExW, RegSetValueExWWhich registry paths and values are touched?
OpenProcess, WriteProcessMemoryWhich process is targeted and what bytes move?
WinHttpSendRequest, connect, sendWhich endpoint, protocol, and payload are used?
CryptDecrypt, BCryptDecryptWhat data, key material, and algorithm are involved?

Import groups as capability evidence

An import is not proof that a function executes. It may be unused, compiler-generated, defensive, or deliberately planted. Confirm cross-references and runtime paths.

For a deeper workflow, use PE Import Analyzer: A Practical Guide.

Missing or sparse imports

Very few imports can mean:

  • a genuinely small program;
  • static linking;
  • managed code;
  • runtime API resolution;
  • a custom loader;
  • packing or import reconstruction after unpacking.

Trace LoadLibrary*, GetProcAddress, export walking, API-name hashes, and indirect calls before concluding that a capability is absent.

Bound imports

Binding can precompute imported addresses for a particular DLL version. The loader validates binding information and may resolve normally when it is stale or incompatible. Bound metadata is a historical optimization and should not be mistaken for runtime proof.

Delay imports

The delay-import directory describes DLLs and symbols intended to be resolved on first use. A sample can therefore use an API that does not appear in the normal import directory.

Check both:

  • normal imports at directory index 1;
  • delay imports at directory index 13.

Malware reports that list only normal imports are incomplete.

AIDebug delay-import descriptor evidence

11. Exports and forwarded functions

Exports make code or data available to other modules. They are especially important for:

  • DLLs;
  • plugins;
  • service modules;
  • reflective-loading investigations;
  • samples launched through rundll32;
  • drivers and native system components.

The export directory connects several tables:

  • Export Address Table (EAT);
  • Export Name Pointer Table;
  • Export Ordinal Table;
  • export-name strings.

AIDebug exports, ordinals, RVAs, and forwarded symbols

Names and ordinals

Every EAT slot has an ordinal relationship, but not every export has a public name. The directory's Base biases public ordinal numbers:

EAT index = public ordinal - export Base

The 16-bit entries in the Export Ordinal Table are unbiased indexes into the EAT and run parallel to the Export Name Pointer Table.

Do not assume:

  • ordinal 1 maps to EAT index 1;
  • every EAT entry has a name;
  • names appear in source-code order.

Forwarded exports

An EAT entry normally contains an RVA to code or data. If the RVA falls inside the export-directory range, it can instead point to a forwarder string such as:

KERNELBASE.CreateFileW
NTDLL.#123

A forwarder delegates resolution to another module and symbol. A disassembler that treats the forwarder string as executable code will produce nonsense.

Analyst questions

  • Which exports have code cross-references?
  • Which export is selected by the observed launcher?
  • Are names descriptive, misleading, or absent?
  • Does the DLL require a particular ordinal?
  • Is an export a short forwarding thunk?
  • Does the export table claim RVAs outside valid executable or data ranges?

12. Resources

The resource directory stores a hierarchy, conventionally:

Type
└── Name or numeric ID
└── Language
└── IMAGE_RESOURCE_DATA_ENTRY

Common resource types include:

  • icons and cursors;
  • dialogs and menus;
  • string tables;
  • version information;
  • manifests;
  • HTML;
  • arbitrary RCDATA;
  • embedded executables, archives, configuration, or encrypted blobs.

AIDebug resource hierarchy and extracted resource files

The final data entry contains an RVA, size, code-page field, and reserved field. Convert its RVA through the containing section before extracting bytes.

What resources can reveal

  • claimed product and company names;
  • requested execution level in a manifest;
  • visual impersonation;
  • language targeting;
  • embedded configuration;
  • decoy documents;
  • secondary payloads;
  • packer or installer content.

Version strings and icons are easy to copy. Treat them as sample claims, not publisher identity.

Safe extraction

Extract resources as bytes first. Hash them, identify their real format by magic bytes, and inspect them with the appropriate parser. Do not rely on the resource name or extension, and do not open an extracted child through the Windows shell.

13. Base relocations and ASLR

ImageBase is a preference, not a guarantee. If Windows maps the image elsewhere, absolute addresses embedded in the image may require adjustment.

The relocation delta is:

delta = actual load base - preferred ImageBase

The base-relocation directory is organized into blocks. Each block covers a 4 KiB page and begins with:

  • VirtualAddress — page RVA;
  • SizeOfBlock — total block size.

The remainder is an array of 16-bit entries:

high 4 bits = relocation type
low 12 bits = offset within the page

The target RVA is:

target RVA = block.VirtualAddress + entry.offset

Common types include:

TypeUse
IMAGE_REL_BASED_ABSOLUTEPadding/no fixup
IMAGE_REL_BASED_HIGHLOWAdd delta to a 32-bit field; common in PE32
IMAGE_REL_BASED_DIR64Add delta to a 64-bit field; common in PE32+

AIDebug base-relocation blocks and ASLR evidence

Analyst interpretation

Practical ASLR normally requires both:

  • an image that declares dynamic-base compatibility;
  • usable relocation information.

If relocations are stripped, the image may need its preferred base. Drivers, fixed-base images, unusual loaders, and manually mapped images create special cases.

Relocation entries are also useful for distinguishing stored absolute pointers from ordinary integers during reverse engineering.

AIDebug ASLR declaration clue

14. TLS data and callbacks

Thread Local Storage gives each thread its own instance of selected data. The PE TLS directory can describe:

  • the TLS initialization template;
  • an index used by the runtime;
  • zero-fill requirements;
  • a null-terminated callback array.

AIDebug TLS data and callback presentation

A crucial detail is that several TLS-directory fields are virtual addresses rather than RVAs. Parse them according to the PE32 or PE32+ structure and the specification.

TLS callbacks

TLS callbacks can run during:

  • process attach;
  • thread attach;
  • thread detach;
  • process detach.

At process startup, callbacks can execute before control reaches AddressOfEntryPoint.

Legitimate compilers use TLS callbacks for runtime initialization and object construction. Packers and malware may use them to:

  • perform environment checks;
  • decrypt state;
  • initialize hooks;
  • alter memory protections;
  • terminate before the analyst's entry-point breakpoint;
  • transfer control into an unpacking path.

Triage procedure

  1. Parse the TLS directory.
  2. Resolve the callback-array VA against the image base.
  3. Walk pointer-sized entries until the null terminator, with strict bounds.
  4. Validate that each callback points into a plausible mapped executable range.
  5. Disassemble and cross-reference every callback.
  6. In a debugger, set breakpoints on callbacks as well as the nominal entry point.

Do not label every TLS callback anti-debugging. Show what the callback does and how its result changes execution.

15. Exception and unwind information

Directory index 3 points to exception-handling data. Its structure is architecture-specific.

On x64, .pdata commonly contains sorted RUNTIME_FUNCTION records with:

  • function begin RVA;
  • function end RVA;
  • unwind-information RVA.

The associated unwind metadata describes stack allocation, saved nonvolatile registers, frame usage, and exception-handling relationships.

Why it helps analysts

  • recover function boundaries in stripped x64 binaries;
  • distinguish code from embedded data;
  • understand stack frames when a compiler omits RBP;
  • improve disassembler and decompiler analysis;
  • identify unusual handlers or missing metadata;
  • support reliable stack walking during incident response.

Limits

  • leaf functions may not need full unwind records;
  • packers and hand-written assembly may omit or manipulate metadata;
  • architecture formats differ;
  • a table entry describes unwind mechanics, not business logic;
  • corrupted ranges can confuse tools.

Cross-check exception records with control-flow reachability and actual section permissions.

16. Load configuration and exploit mitigations

The load-configuration directory has evolved across Windows and toolchain versions. Its structure begins with a size field; parsers should use that size and the image's bitness rather than assuming the newest structure is fully present.

Depending on version and architecture, the directory can expose:

  • the security-cookie address used by stack-protection logic;
  • SafeSEH handler table and count for applicable 32-bit images;
  • Control Flow Guard check and dispatch pointers;
  • CFG function table and count;
  • Guard flags;
  • code-integrity metadata;
  • dynamic-relocation and newer mitigation-related tables.

AIDebug load-configuration and CFG evidence

CFG evidence

For Control Flow Guard, correlate:

  • IMAGE_DLLCHARACTERISTICS_GUARD_CF;
  • load-config GuardFlags;
  • guard function tables and counts;
  • compiler-generated indirect-call checks in code.

A lone flag without coherent supporting metadata may be malformed, stripped, or misleading.

A security-cookie field can help locate compiler-inserted stack-protection state. Calls such as __security_init_cookie and failure handlers can reveal startup routines and protected functions, but they do not mean a vulnerability exists.

SafeSEH

SafeSEH metadata is relevant to compatible 32-bit images. It should not be projected onto x64, whose exception and unwind model differs.

General rule

Mitigation metadata describes build and loader expectations. It does not guarantee that every control is effective, that code is safe, or that the image was produced by a trustworthy party.

17. Authenticode certificates and signatures

Directory index 4 points to an attribute-certificate table, usually containing one or more WIN_CERTIFICATE records.

This directory is structurally unusual:

  • its address is a file offset, not an RVA;
  • its data is not mapped as an ordinary image section;
  • entries are aligned to 8-byte boundaries;
  • each entry's dwLength must be rounded to the next 8-byte boundary when finding the following entry.

AIDebug Authenticode certificate table evidence

The image-digest calculation treats selected fields specially. In particular, the checksum, certificate-table directory entry, and certificate content cannot be hashed in the same ordinary way because adding a signature changes them.

What a valid signature establishes

Subject to certificate-chain, timestamp, policy, and revocation validation, a valid Authenticode signature can support:

  • integrity of the covered file content;
  • identity asserted by the signing certificate;
  • signing-time evidence when a trusted timestamp is present.

It does not prove:

  • the program is benign;
  • the publisher's environment was never compromised;
  • the certificate was not stolen or misused;
  • behavior after loading is safe;
  • unsigned overlay or externally retrieved content is trustworthy.

Analyst workflow

Record:

  • signature presence;
  • cryptographic validation result;
  • signer subject and issuer;
  • certificate thumbprint and serial;
  • validity period;
  • timestamp and timestamp authority;
  • revocation result and whether it was actually checked;
  • catalog signing versus embedded signing;
  • warnings from multiple verification tools.

Do not report “signed” as “trusted.” Report the exact validation state.

18. Debug data, the Rich header, and overlays

Debug directory

The debug directory can point to several record types. CodeView records commonly begin with RSDS and contain:

  • a PDB signature GUID;
  • an age value;
  • a path to the Program Database file.

A PDB path can reveal usernames, build directories, project names, branch names, or internal product terminology. It is useful provenance evidence but easy to remove or forge.

Some records expose both an RVA and a file pointer because debug data may be mapped or stored at the end of the file. Validate each location independently.

AIDebug CodeView, Rich header, and overlay evidence

Reproducible-build metadata can make timestamp fields intentionally non-temporal. Do not force every 32-bit timestamp-like value into a wall-clock narrative.

Rich header

Microsoft-produced binaries often contain an undocumented, encoded “Rich” structure between the DOS stub and PE signature. Tools use it to infer product IDs, toolchain components, and build counts.

Analytical limits:

  • it is not part of the documented PE/COFF contract;
  • it may be absent from legitimate binaries;
  • it can be copied, stripped, modified, or fabricated;
  • product identifiers require an external interpretation database;
  • a Rich hash is a clustering feature, not attribution proof.

Overlay

An overlay is data after the last expected raw image region. It may contain:

  • installer payloads;
  • self-extracting archive data;
  • configuration;
  • appended signatures;
  • packer data;
  • benign product metadata;
  • hidden or encrypted content.

Be precise when calculating it. A certificate table commonly sits after section data and can look like overlay to a naive detector even though it is referenced by the security directory.

A defensible overlay report identifies:

  1. the end of the last valid raw section;
  2. any referenced certificate/debug ranges;
  3. the remaining unreferenced byte ranges;
  4. hashes, magic bytes, entropy, and extraction results for each range.

19. .NET assemblies inside PE files

A managed .NET assembly still uses the PE container. Directory index 14 points to the CLR runtime header, commonly represented by IMAGE_COR20_HEADER.

The CLR header can reference:

  • metadata;
  • managed resources;
  • a strong-name signature;
  • code-manager and fixup information;
  • an entry-point token or native entry-point RVA;
  • flags describing IL-only, 32-bit requirements/preferences, and related runtime behavior.

Metadata streams

The metadata root commonly contains streams such as:

StreamContent
#~ or #-Metadata tables
#StringsIdentifier and name strings
#USUser strings
#GUIDGUID heap
#BlobSignatures and arbitrary blobs

Managed types, methods, references, attributes, and IL are reconstructed from these metadata tables and heaps.

Analyst consequences

  • a native disassembler may show only a small runtime bootstrap;
  • the source-level entry method can be represented by a metadata token;
  • imports may be sparse because framework behavior is described in metadata;
  • IL decompilers such as ILSpy or dnSpy-derived tools are usually more informative;
  • mixed-mode, ReadyToRun, NativeAOT, protectors, and embedded native code require both managed and native analysis.

Strong-name signing is not equivalent to Authenticode publisher validation. They serve different identity and integrity roles.

20. How the Windows loader uses the image

A simplified conceptual loading flow is:

Simplified Windows PE loader flow from validation through entry point

  1. validate enough header structure to recognize the image;
  2. reserve address space for SizeOfImage;
  3. map headers and sections according to alignment and section metadata;
  4. choose the actual image base;
  5. apply base relocations when required;
  6. resolve imported dependencies and populate IAT entries;
  7. configure section protections and loader-maintained state;
  8. initialize TLS and invoke applicable callbacks;
  9. transfer control through the platform's image-startup path.

The real loader is more complex. Dependency loading is recursive, activation contexts and manifests matter, mitigations influence mapping, DLL initialization has ordering constraints, and implementation details vary by Windows version.

Manual mapping differs

Reflective loaders, process hollowing components, packers, and custom in-memory loaders may reproduce only part of normal loader behavior. Analysts should compare:

  • relocations applied or skipped;
  • imports resolved manually;
  • section permissions left overly broad;
  • TLS callbacks invoked or omitted;
  • exception tables registered or ignored;
  • headers erased after mapping;
  • memory layout versus the original SizeOfImage and section RVAs.

This comparison can expose a manually mapped image even when its original PE header is no longer present in memory.

21. References

Primary and authoritative references:

Published · Last updated