PE/COFF File Format
The Portable Executable format is used by Windows executables (.exe), libraries (.dll), drivers (.sys) and UEFI binaries; COFF is the object file format it extends.
This page describes every header with its offsets in PE32 and PE32+ files, then annotates every byte of a small working 64-bit executable.
- All formats
- Layout
- Annotated sample
- DOS header
- File header
- Optional header
- Data directories
- Sections
- RVA and offsets
- Imports
- Exports
- Base relocations
- TLS callbacks
- COFF objects
- Tools
Layout
On disk
In memory (typical layout, ImageBase + RVA)
R--headers (one page)R-X.textR--.rdata: IAT, import tables, constantsRW-.data, .bss (VirtualSize > SizeOfRawData)R--.reloc (discardable)The loader maps the headers and then each section at ImageBase + VirtualAddress, rounded to SectionAlignment, with the protection given by its characteristics.
Unlike ELF there is a single table: sections are both the linker and the loader unit.
Annotated sample (2048 bytes, PE32+ x64)
A console program that prints Hello, PE! with GetStdHandle, WriteFile and ExitProcess from KERNEL32.dll.
Three sections: code, read-only data holding the import tables, and one base relocation for an absolute pointer. Every byte is described; zero padding is folded.
Hover a byte or a field to see what it is. Click to pin it.
IMAGE_DOS_HEADER 0x0
- e_magic"MZ"
- e_cblp0x90
- e_cp3
- e_crlc0
- e_cparhdr4
- e_minalloc0
- e_maxalloc0xffff
- e_ss0
- e_sp0xb8
- e_csum0
- e_ip0
- e_cs0
- e_lfarlc0x40
- e_ovno0
- e_reszero
- e_oemid0
- e_oeminfo0
- e_res2zero
- e_lfanew0x80
DOS stub 0x40
- stub codepush cs; pop ds; mov…
- message"This program cannot…
Padding 0x79
- paddingzeros
PE signature 0x80
- Signature"PE\0\0"
IMAGE_FILE_HEADER 0x84
- MachineIMAGE_FILE_MACHINE_A…
- NumberOfSections3
- TimeDateStamp0x67000000
- PointerToSymbolTable0
- NumberOfSymbols0
- SizeOfOptionalHeader0xf0
- CharacteristicsEXECUTABLE_IMAGE | L…
IMAGE_OPTIONAL_HEADER64 0x98
- MagicPE32+
- MajorLinkerVersion0xe
- MinorLinkerVersion0
- SizeOfCode0x200
- SizeOfInitializedData0x400
- SizeOfUninitializedData0
- AddressOfEntryPoint0x1000
- BaseOfCode0x1000
- ImageBase0x140000000
- SectionAlignment0x1000
- FileAlignment0x200
- MajorOperatingSystemVersion6
- MinorOperatingSystemVersion0
- MajorImageVersion0
- MinorImageVersion0
- MajorSubsystemVersion6
- MinorSubsystemVersion0
- Win32VersionValue0
- SizeOfImage0x4000
- SizeOfHeaders0x200
- CheckSum0xbd64
- SubsystemIMAGE_SUBSYSTEM_WIND…
- DllCharacteristicsHIGH_ENTROPY_VA | DY…
- SizeOfStackReserve0x100000
- SizeOfStackCommit0x1000
- SizeOfHeapReserve0x100000
- SizeOfHeapCommit0x1000
- LoaderFlags0
- NumberOfRvaAndSizes0x10
Data directories 0x108
- [0] Export RVA0
- [0] Export Size0
- [1] Import RVA0x2028
- [1] Import Size0x28
- [2] Resource RVA0
- [2] Resource Size0
- [3] Exception RVA0
- [3] Exception Size0
- [4] Security RVA0
- [4] Security Size0
- [5] Base Relocation RVA0x3000
- [5] Base Relocation Size0xc
- [6] Debug RVA0
- [6] Debug Size0
- [7] Architecture RVA0
- [7] Architecture Size0
- [8] Global Ptr RVA0
- [8] Global Ptr Size0
- [9] TLS RVA0
- [9] TLS Size0
- [10] Load Config RVA0
- [10] Load Config Size0
- [11] Bound Import RVA0
- [11] Bound Import Size0
- [12] IAT RVA0x2000
- [12] IAT Size0x20
- [13] Delay Import RVA0
- [13] Delay Import Size0
- [14] CLR Runtime Header RVA0
- [14] CLR Runtime Header Size0
- [15] Reserved RVA0
- [15] Reserved Size0
Section header .text 0x188
- Name".text"
- VirtualSize0x3c
- VirtualAddress0x1000
- SizeOfRawData0x200
- PointerToRawData0x200
- PointerToRelocations0
- PointerToLinenumbers0
- NumberOfRelocations0
- NumberOfLinenumbers0
- CharacteristicsCNT_CODE | MEM_EXECU…
Section header .rdata 0x1b0
- Name".rdata"
- VirtualSize0xb4
- VirtualAddress0x2000
- SizeOfRawData0x200
- PointerToRawData0x400
- PointerToRelocations0
- PointerToLinenumbers0
- NumberOfRelocations0
- NumberOfLinenumbers0
- CharacteristicsCNT_INITIALIZED_DATA…
Section header .reloc 0x1d8
- Name".reloc"
- VirtualSize0xc
- VirtualAddress0x3000
- SizeOfRawData0x200
- PointerToRawData0x600
- PointerToRelocations0
- PointerToLinenumbers0
- NumberOfRelocations0
- NumberOfLinenumbers0
- CharacteristicsCNT_INITIALIZED_DATA…
.text (entry point) 0x200
- sub rsp, 0x38sub rsp, 0x38
- mov ecx, -11mov ecx, -11 ; STD_O…
- call [rip+__imp_GetStdHandle]call [rip+__imp_GetS…
- mov rcx, raxmov rcx, rax
- mov rdx, [rip+msg_ptr]mov rdx, [rip+msg_ptr]
- mov r8d, 12mov r8d, 12
- lea r9, [rsp+0x30]lea r9, [rsp+0x30]
- mov qword [rsp+0x20], 0mov qword [rsp+0x20]…
- call [rip+__imp_WriteFile]call [rip+__imp_Writ…
- xor ecx, ecxxor ecx, ecx
- call [rip+__imp_ExitProcess]call [rip+__imp_Exit…
- int3int3
Padding 0x23c
- paddingzeros
Import Address Table 0x400
- IAT[0] GetStdHandle0x2070
- IAT[1] WriteFile0x2080
- IAT[2] ExitProcess0x208c
- IAT end0
msg_ptr 0x420
- msg_ptr0x1400020a8
Import descriptor KERNEL32.dll 0x428
- OriginalFirstThunk0x2050
- TimeDateStamp0
- ForwarderChain0
- Name0x209a
- FirstThunk0x2000
Import descriptor (null) 0x43c
- terminator
Import Lookup Table 0x450
- ILT[0] GetStdHandle0x2070
- ILT[1] WriteFile0x2080
- ILT[2] ExitProcess0x208c
- ILT end0
IMAGE_IMPORT_BY_NAME GetStdHandle 0x470
- Hint0
- Name"GetStdHandle"
IMAGE_IMPORT_BY_NAME WriteFile 0x480
- Hint0
- Name"WriteFile"
IMAGE_IMPORT_BY_NAME ExitProcess 0x48c
- Hint0
- Name"ExitProcess"
DLL name 0x49a
- Name"KERNEL32.dll"
Padding 0x4a7
- paddingzeros
Message 0x4a8
- msg"Hello, PE!\r\n"
Padding 0x4b4
- paddingzeros
Base relocation block 0x600
- VirtualAddress0x2000
- SizeOfBlock0xc
- entry 0DIR64 + 0x020
- entry 1ABSOLUTE
Padding 0x60c
- paddingzeros
DOS header
IMAGE_DOS_HEADER 64 (0x40) bytes
| Field | Offset | Size | Type | Meaning |
|---|---|---|---|---|
e_magic | 0x00 | 2 | WORD | "MZ" (4d 5a), Mark Zbikowski. |
e_cblp | 0x02 | 2 | WORD | Bytes on the last 512-byte page (DOS only). |
e_cp | 0x04 | 2 | WORD | Pages in the file (DOS only). |
e_crlc | 0x06 | 2 | WORD | Relocations (DOS only). |
e_cparhdr | 0x08 | 2 | WORD | Header size in 16-byte paragraphs (DOS only). |
e_minalloc | 0x0a | 2 | WORD | Minimum extra paragraphs (DOS only). |
e_maxalloc | 0x0c | 2 | WORD | Maximum extra paragraphs (DOS only). |
e_ss | 0x0e | 2 | WORD | Initial SS (DOS only). |
e_sp | 0x10 | 2 | WORD | Initial SP (DOS only). |
e_csum | 0x12 | 2 | WORD | Checksum (DOS only). |
e_ip | 0x14 | 2 | WORD | Initial IP (DOS only). |
e_cs | 0x16 | 2 | WORD | Initial CS (DOS only). |
e_lfarlc | 0x18 | 2 | WORD | Offset of the DOS relocation table (DOS only). |
e_ovno | 0x1a | 2 | WORD | Overlay number (DOS only). |
e_res | 0x1c | 8 | WORD[4] | Reserved. |
e_oemid | 0x24 | 2 | WORD | OEM identifier. |
e_oeminfo | 0x26 | 2 | WORD | OEM information. |
e_res2 | 0x28 | 20 | WORD[10] | Reserved. |
e_lfanew | 0x3c | 4 | LONG | File offset of the PE signature. The only field Windows needs besides e_magic. |
e_magic and e_lfanew and nothing else. The bytes between this header and the PE signature usually hold a 16-bit DOS stub that prints This program cannot be run in DOS mode., and, for files linked by Microsoft tools, the undocumented "Rich" header that lists the tool versions used.File header
At e_lfanew + 4, right after the "PE\0\0" signature.
IMAGE_FILE_HEADER 20 (0x14) bytes
| Field | Offset | Size | Type | Meaning |
|---|---|---|---|---|
Machine | 0x00 | 2 | WORD | Target CPU (IMAGE_FILE_MACHINE_*). |
NumberOfSections | 0x02 | 2 | WORD | Entries in the section table. |
TimeDateStamp | 0x04 | 4 | DWORD | Link time (Unix time), or a hash for reproducible builds. |
PointerToSymbolTable | 0x08 | 4 | DWORD | File offset of the COFF symbol table; 0 in images. |
NumberOfSymbols | 0x0c | 4 | DWORD | COFF symbols; 0 in images. |
SizeOfOptionalHeader | 0x10 | 2 | WORD | Size of the optional header: 0xe0 (PE32) or 0xf0 (PE32+); 0 in object files. The section table follows it. |
Characteristics | 0x12 | 2 | WORD | File flags (IMAGE_FILE_*). |
.obj) start directly with this header; images (.exe, .dll, .sys) have it right after the "PE\0\0" signature.Machine
| Name | Value | Meaning |
|---|---|---|
| IMAGE_FILE_MACHINE_UNKNOWN | 0 | Any machine (resource-only DLLs). |
| IMAGE_FILE_MACHINE_I386 | 0x14c | Intel 386 and later. |
| IMAGE_FILE_MACHINE_ARMNT | 0x1c4 | ARM Thumb-2 (Windows on ARM 32-bit). |
| IMAGE_FILE_MACHINE_AMD64 | 0x8664 | x64. |
| IMAGE_FILE_MACHINE_ARM64 | 0xaa64 | ARM64. |
| IMAGE_FILE_MACHINE_ARM64EC | 0xa641 | ARM64EC: ARM64 code that interoperates with x64 code in the same process. |
| IMAGE_FILE_MACHINE_ARM64X | 0xa64e | ARM64X: one file with both ARM64 and ARM64EC code. |
Characteristics
| Name | Value | Meaning |
|---|---|---|
| IMAGE_FILE_RELOCS_STRIPPED | 1 | No base relocations: must load at ImageBase. |
| IMAGE_FILE_EXECUTABLE_IMAGE | 2 | Valid image (set for exe and dll). |
| IMAGE_FILE_LINE_NUMS_STRIPPED | 4 | Deprecated. |
| IMAGE_FILE_LOCAL_SYMS_STRIPPED | 8 | Deprecated. |
| IMAGE_FILE_AGGRESIVE_WS_TRIM | 0x10 | Obsolete. |
| IMAGE_FILE_LARGE_ADDRESS_AWARE | 0x20 | Can handle addresses above 2 GiB. |
| IMAGE_FILE_BYTES_REVERSED_LO | 0x80 | Obsolete. |
| IMAGE_FILE_32BIT_MACHINE | 0x100 | 32-bit word machine. |
| IMAGE_FILE_DEBUG_STRIPPED | 0x200 | Debug information removed. |
| IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP | 0x400 | Copy to swap if run from removable media. |
| IMAGE_FILE_NET_RUN_FROM_SWAP | 0x800 | Copy to swap if run from the network. |
| IMAGE_FILE_SYSTEM | 0x1000 | System file. |
| IMAGE_FILE_DLL | 0x2000 | DLL. |
| IMAGE_FILE_UP_SYSTEM_ONLY | 0x4000 | Uniprocessor only. |
| IMAGE_FILE_BYTES_REVERSED_HI | 0x8000 | Obsolete. |
Optional header
Mandatory for images despite its name. PE32+ drops BaseOfData and widens ImageBase and the four stack/heap sizes to 64 bits, so it is 16 bytes larger.
IMAGE_OPTIONAL_HEADER32 / IMAGE_OPTIONAL_HEADER64 224 (0xe0) bytes / 240 (0xf0) bytes
| Field | Off. PE32 | Off. PE32+ | Size PE32 | Size PE32+ | Type | Meaning |
|---|---|---|---|---|---|---|
Magic | 0x00 | 0x00 | 2 | 2 | WORD | 0x10b = PE32, 0x20b = PE32+ (64-bit). Selects the layout below. |
MajorLinkerVersion | 0x02 | 0x02 | 1 | 1 | BYTE | Linker version. |
MinorLinkerVersion | 0x03 | 0x03 | 1 | 1 | BYTE | Linker version. |
SizeOfCode | 0x04 | 0x04 | 4 | 4 | DWORD | Sum of the code sections (rounded to FileAlignment). |
SizeOfInitializedData | 0x08 | 0x08 | 4 | 4 | DWORD | Sum of the initialized data sections. |
SizeOfUninitializedData | 0x0c | 0x0c | 4 | 4 | DWORD | Sum of the BSS sections. |
AddressOfEntryPoint | 0x10 | 0x10 | 4 | 4 | DWORD | RVA of the entry point (mainCRTStartup, DllMain for DLLs; 0 = none). |
BaseOfCode | 0x14 | 0x14 | 4 | 4 | DWORD | RVA of the first code section. |
BaseOfData | 0x18 | — | 4 | — | DWORD | RVA of the first data section (PE32 only). |
ImageBase | 0x1c | 0x18 | 4 | 8 | PTR | Preferred load address: 0x400000 (PE32 exe), 0x140000000 (PE32+ exe), 0x180000000 (PE32+ DLL). Randomized by ASLR when DYNAMIC_BASE is set. |
SectionAlignment | 0x20 | 0x20 | 4 | 4 | DWORD | Alignment of sections in memory, usually the page size 0x1000. |
FileAlignment | 0x24 | 0x24 | 4 | 4 | DWORD | Alignment of section data in the file, usually 0x200. |
MajorOperatingSystemVersion | 0x28 | 0x28 | 2 | 2 | WORD | Required OS version. |
MinorOperatingSystemVersion | 0x2a | 0x2a | 2 | 2 | WORD | Required OS version. |
MajorImageVersion | 0x2c | 0x2c | 2 | 2 | WORD | Image version. |
MinorImageVersion | 0x2e | 0x2e | 2 | 2 | WORD | Image version. |
MajorSubsystemVersion | 0x30 | 0x30 | 2 | 2 | WORD | Required subsystem version (6.0 = Vista). |
MinorSubsystemVersion | 0x32 | 0x32 | 2 | 2 | WORD | Required subsystem version. |
Win32VersionValue | 0x34 | 0x34 | 4 | 4 | DWORD | Reserved, 0. |
SizeOfImage | 0x38 | 0x38 | 4 | 4 | DWORD | Size of the image in memory, multiple of SectionAlignment. |
SizeOfHeaders | 0x3c | 0x3c | 4 | 4 | DWORD | Size of all headers rounded to FileAlignment; the first section starts here. |
CheckSum | 0x40 | 0x40 | 4 | 4 | DWORD | Image checksum; only checked for drivers and boot-time DLLs. |
Subsystem | 0x44 | 0x44 | 2 | 2 | WORD | Subsystem (IMAGE_SUBSYSTEM_*): console, GUI, native, EFI... |
DllCharacteristics | 0x46 | 0x46 | 2 | 2 | WORD | Security flags (IMAGE_DLLCHARACTERISTICS_*): ASLR, DEP, CFG... |
SizeOfStackReserve | 0x48 | 0x48 | 4 | 8 | PTR | Stack reserved for the main thread. |
SizeOfStackCommit | 0x4c | 0x50 | 4 | 8 | PTR | Stack committed at start. |
SizeOfHeapReserve | 0x50 | 0x58 | 4 | 8 | PTR | Default process heap reserve. |
SizeOfHeapCommit | 0x54 | 0x60 | 4 | 8 | PTR | Default process heap commit. |
LoaderFlags | 0x58 | 0x68 | 4 | 4 | DWORD | Reserved, 0. |
NumberOfRvaAndSizes | 0x5c | 0x6c | 4 | 4 | DWORD | Number of data directories that follow, normally 16. |
DataDirectory | 0x60 | 0x70 | 128 | 128 | IMAGE_DATA_DIRECTORY[16] | 16 IMAGE_DATA_DIRECTORY entries (RVA + size), see below. |
Subsystem
| Name | Value | Meaning |
|---|---|---|
| IMAGE_SUBSYSTEM_UNKNOWN | 0 | Unknown. |
| IMAGE_SUBSYSTEM_NATIVE | 1 | Drivers and native processes (smss.exe). |
| IMAGE_SUBSYSTEM_WINDOWS_GUI | 2 | GUI application (WinMain, no console). |
| IMAGE_SUBSYSTEM_WINDOWS_CUI | 3 | Console application. |
| IMAGE_SUBSYSTEM_OS2_CUI | 5 | OS/2 console. |
| IMAGE_SUBSYSTEM_POSIX_CUI | 7 | POSIX console. |
| IMAGE_SUBSYSTEM_WINDOWS_CE_GUI | 9 | Windows CE. |
| IMAGE_SUBSYSTEM_EFI_APPLICATION | 0xa | UEFI application. |
| IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER | 0xb | UEFI boot service driver. |
| IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER | 0xc | UEFI runtime driver. |
| IMAGE_SUBSYSTEM_EFI_ROM | 0xd | UEFI ROM image. |
| IMAGE_SUBSYSTEM_XBOX | 0xe | Xbox. |
| IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION | 0x10 | Boot application (bootmgr). |
DllCharacteristics
| Name | Value | Meaning |
|---|---|---|
| IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | 0x20 | 64-bit ASLR with full entropy. |
| IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | 0x40 | ASLR: can be relocated (/DYNAMICBASE). |
| IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY | 0x80 | Code integrity checks enforced. |
| IMAGE_DLLCHARACTERISTICS_NX_COMPAT | 0x100 | DEP compatible (/NXCOMPAT). |
| IMAGE_DLLCHARACTERISTICS_NO_ISOLATION | 0x200 | Do not use side-by-side manifests. |
| IMAGE_DLLCHARACTERISTICS_NO_SEH | 0x400 | No structured exception handlers (x86 SafeSEH context). |
| IMAGE_DLLCHARACTERISTICS_NO_BIND | 0x800 | Do not bind. |
| IMAGE_DLLCHARACTERISTICS_APPCONTAINER | 0x1000 | Must run in an AppContainer. |
| IMAGE_DLLCHARACTERISTICS_WDM_DRIVER | 0x2000 | WDM driver. |
| IMAGE_DLLCHARACTERISTICS_GUARD_CF | 0x4000 | Control Flow Guard (/guard:cf). |
| IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE | 0x8000 | Terminal Server aware. |
Data directories
Each entry is an IMAGE_DATA_DIRECTORY (RVA, then size at +4). An entry that is not present is all zero. Offsets below are from the start of the optional header.
IMAGE_DATA_DIRECTORY 8 (0x8) bytes
| Field | Offset | Size | Type | Meaning |
|---|---|---|---|---|
VirtualAddress | 0x00 | 4 | DWORD | RVA of the table (a file offset for the Certificate table). |
Size | 0x04 | 4 | DWORD | Size in bytes. |
| # | Directory | Constant | Offset PE32 | Offset PE32+ | Points to |
|---|---|---|---|---|---|
| 0 | Export | IMAGE_DIRECTORY_ENTRY_EXPORT | 0x60 | 0x70 | IMAGE_EXPORT_DIRECTORY: functions exported by name or ordinal. |
| 1 | Import | IMAGE_DIRECTORY_ENTRY_IMPORT | 0x68 | 0x78 | Array of IMAGE_IMPORT_DESCRIPTOR, one per DLL. |
| 2 | Resource | IMAGE_DIRECTORY_ENTRY_RESOURCE | 0x70 | 0x80 | Resource tree (.rsrc): icons, version info, manifest, dialogs. |
| 3 | Exception | IMAGE_DIRECTORY_ENTRY_EXCEPTION | 0x78 | 0x88 | .pdata: RUNTIME_FUNCTION entries for x64/ARM64 unwinding. |
| 4 | Security | IMAGE_DIRECTORY_ENTRY_SECURITY | 0x80 | 0x90 | Authenticode certificates (WIN_CERTIFICATE). A file offset, not mapped in memory. |
| 5 | Base Relocation | IMAGE_DIRECTORY_ENTRY_BASERELOC | 0x88 | 0x98 | .reloc: blocks of IMAGE_BASE_RELOCATION. |
| 6 | Debug | IMAGE_DIRECTORY_ENTRY_DEBUG | 0x90 | 0xa0 | Array of IMAGE_DEBUG_DIRECTORY: CodeView entry with the PDB path and GUID. |
| 7 | Architecture | IMAGE_DIRECTORY_ENTRY_ARCHITECTURE | 0x98 | 0xa8 | Reserved, 0. |
| 8 | Global Ptr | IMAGE_DIRECTORY_ENTRY_GLOBALPTR | 0xa0 | 0xb0 | RVA of the global pointer (IA-64), size 0. |
| 9 | TLS | IMAGE_DIRECTORY_ENTRY_TLS | 0xa8 | 0xb8 | IMAGE_TLS_DIRECTORY: TLS template and callbacks. |
| 10 | Load Config | IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG | 0xb0 | 0xc0 | IMAGE_LOAD_CONFIG_DIRECTORY: security cookie, SafeSEH table, CFG tables, CET metadata. |
| 11 | Bound Import | IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT | 0xb8 | 0xc8 | Pre-bound import addresses (legacy). |
| 12 | IAT | IMAGE_DIRECTORY_ENTRY_IAT | 0xc0 | 0xd0 | Range of all the Import Address Tables, made writable during binding. |
| 13 | Delay Import | IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT | 0xc8 | 0xd8 | Delay-load descriptors: DLLs loaded on first call. |
| 14 | CLR Runtime Header | IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR | 0xd0 | 0xe0 | .NET: IMAGE_COR20_HEADER, the managed metadata. |
| 15 | Reserved | — | 0xd8 | 0xe8 | Must be zero. |
Sections
The section table follows the optional header: e_lfanew + 24 + SizeOfOptionalHeader.
IMAGE_SECTION_HEADER 40 (0x28) bytes
| Field | Offset | Size | Type | Meaning |
|---|---|---|---|---|
Name | 0x00 | 8 | BYTE[8] | Name, NUL-padded, not necessarily NUL-terminated. In object files /123 means offset 123 in the string table. |
VirtualSize | 0x08 | 4 | DWORD | Size in memory (Misc.VirtualSize). Larger than SizeOfRawData: the rest is zero-filled. |
VirtualAddress | 0x0c | 4 | DWORD | RVA of the section, multiple of SectionAlignment. |
SizeOfRawData | 0x10 | 4 | DWORD | Size in the file, multiple of FileAlignment. |
PointerToRawData | 0x14 | 4 | DWORD | File offset of the data, multiple of FileAlignment. |
PointerToRelocations | 0x18 | 4 | DWORD | File offset of the COFF relocations (object files only). |
PointerToLinenumbers | 0x1c | 4 | DWORD | Deprecated, 0. |
NumberOfRelocations | 0x20 | 2 | WORD | COFF relocations (object files only). |
NumberOfLinenumbers | 0x22 | 2 | WORD | Deprecated, 0. |
Characteristics | 0x24 | 4 | DWORD | Content and permissions (IMAGE_SCN_*). |
Characteristics
| Name | Value | Meaning |
|---|---|---|
| IMAGE_SCN_CNT_CODE | 0x20 | Contains code. |
| IMAGE_SCN_CNT_INITIALIZED_DATA | 0x40 | Contains initialized data. |
| IMAGE_SCN_CNT_UNINITIALIZED_DATA | 0x80 | Contains uninitialized data (BSS). |
| IMAGE_SCN_LNK_INFO | 0x200 | Comments or linker directives (.drectve), object files only. |
| IMAGE_SCN_LNK_REMOVE | 0x800 | Not part of the image, object files only. |
| IMAGE_SCN_LNK_COMDAT | 0x1000 | COMDAT section (C++ inline functions, templates), object files only. |
| IMAGE_SCN_ALIGN_1BYTES .. 8192BYTES | 0x100000 .. 0xe00000 | Alignment in object files: (log2(align) + 1) << 20, e.g. 16 bytes = 0x500000. |
| IMAGE_SCN_MEM_DISCARDABLE | 0x2000000 | Can be discarded after loading (.reloc, debug). |
| IMAGE_SCN_MEM_SHARED | 0x10000000 | Shared between all processes that load the image. |
| IMAGE_SCN_MEM_EXECUTE | 0x20000000 | Executable. |
| IMAGE_SCN_MEM_READ | 0x40000000 | Readable. |
| IMAGE_SCN_MEM_WRITE | 0x80000000 | Writable. |
.text 0x60000020 (code, execute, read), .rdata 0x40000040, .data 0xc0000040 (read, write), .reloc 0x42000040 (discardable).
Common section names: .text, .rdata, .data, .pdata (unwind), .tls, .rsrc, .reloc, .idata (imports, when not merged into .rdata), .edata (exports). Names mean nothing to the loader: packers use UPX0, .vmp0 and so on.RVA and file offsets
Three kinds of addresses
- File offset: position in the file on disk.
- RVA (relative virtual address): offset from the image base once mapped. Almost every pointer in the headers is an RVA.
- VA:
ImageBase + RVA, the real address in memory. Only found in code, data and a few tables (TLS, load config), and fixed by base relocations.
RVA → file offset
Find the section with VirtualAddress ≤ rva < VirtualAddress + VirtualSize, then:
offset = rva - VirtualAddress + PointerToRawData
In the sample, the IAT is at RVA 0x2000, in .rdata (VirtualAddress 0x2000, PointerToRawData 0x400):
0x2000 - 0x2000 + 0x400 = 0x400.
An RVA below SizeOfHeaders maps to the same file offset.
How imports are resolved
For each descriptor the loader loads Name, walks the ILT, looks every name up in the DLL export table, and writes the address in the matching IAT slot.
Code calls through the IAT: call [rip+__imp_WriteFile] (ff 15). Hooking the IAT is the classic user-mode hooking technique.
Imports
IMAGE_IMPORT_DESCRIPTOR 20 (0x14) bytes
| Field | Offset | Size | Type | Meaning |
|---|---|---|---|---|
OriginalFirstThunk | 0x00 | 4 | DWORD | RVA of the Import Lookup Table (ILT, also called INT): names or ordinals, never modified. |
TimeDateStamp | 0x04 | 4 | DWORD | 0, or -1 if bound. |
ForwarderChain | 0x08 | 4 | DWORD | Old binding mechanism, usually 0 or -1. |
Name | 0x0c | 4 | DWORD | RVA of the DLL name ("KERNEL32.dll"). |
FirstThunk | 0x10 | 4 | DWORD | RVA of the Import Address Table (IAT): same content as the ILT on disk, overwritten with the function addresses by the loader. |
IMAGE_THUNK_DATA32 / IMAGE_THUNK_DATA64 (ILT and IAT entries) 4 (0x4) bytes / 8 (0x8) bytes
| Field | Off. PE32 | Off. PE32+ | Size PE32 | Size PE32+ | Type | Meaning |
|---|---|---|---|---|---|---|
u1 | 0x00 | 0x00 | 4 | 8 | PTR | If the top bit (IMAGE_ORDINAL_FLAG: bit 31 or bit 63) is set, import by ordinal (low 16 bits); otherwise RVA of an IMAGE_IMPORT_BY_NAME (WORD Hint + NUL-terminated name, padded to an even size). A zero entry ends the table. |
Exports
IMAGE_EXPORT_DIRECTORY 40 (0x28) bytes
| Field | Offset | Size | Type | Meaning |
|---|---|---|---|---|
Characteristics | 0x00 | 4 | DWORD | Reserved, 0. |
TimeDateStamp | 0x04 | 4 | DWORD | Creation time. |
MajorVersion | 0x08 | 2 | WORD | User version. |
MinorVersion | 0x0a | 2 | WORD | User version. |
Name | 0x0c | 4 | DWORD | RVA of the DLL name. |
Base | 0x10 | 4 | DWORD | First ordinal, usually 1. |
NumberOfFunctions | 0x14 | 4 | DWORD | Entries in AddressOfFunctions. |
NumberOfNames | 0x18 | 4 | DWORD | Entries in AddressOfNames and AddressOfNameOrdinals. |
AddressOfFunctions | 0x1c | 4 | DWORD | RVA of an array of function RVAs (Export Address Table), indexed by ordinal - Base. An RVA that falls inside the export directory is a forwarder string such as "NTDLL.RtlAllocateHeap". |
AddressOfNames | 0x20 | 4 | DWORD | RVA of an array of name RVAs, sorted for binary search. |
AddressOfNameOrdinals | 0x24 | 4 | DWORD | RVA of an array of WORD indexes into AddressOfFunctions, parallel to AddressOfNames. |
GetProcAddress(h, "name"): binary search name in AddressOfNames → index i → AddressOfNameOrdinals[i] → AddressOfFunctions[that].Base relocations
IMAGE_BASE_RELOCATION 8 (0x8) bytes
| Field | Offset | Size | Type | Meaning |
|---|---|---|---|---|
VirtualAddress | 0x00 | 4 | DWORD | RVA of the 4 KiB page the entries apply to. |
SizeOfBlock | 0x04 | 4 | DWORD | Size of the block including this header; (SizeOfBlock - 8) / 2 WORD entries follow. |
type << 12 | offset, where offset is relative to the page. If the image is not loaded at ImageBase, the loader adds the difference to every location listed here.| Name | Value | Meaning |
|---|---|---|
| IMAGE_REL_BASED_ABSOLUTE | 0 | Skipped; pads a block to a multiple of 4 bytes. |
| IMAGE_REL_BASED_HIGH | 1 | Add the high 16 bits of the delta to a WORD. |
| IMAGE_REL_BASED_LOW | 2 | Add the low 16 bits of the delta to a WORD. |
| IMAGE_REL_BASED_HIGHLOW | 3 | Add the delta to a 32-bit location (PE32). |
| IMAGE_REL_BASED_HIGHADJ | 4 | High 16 bits with adjustment; uses the next entry. |
| IMAGE_REL_BASED_DIR64 | 0xa | Add the delta to a 64-bit location (PE32+). |
TLS callbacks
IMAGE_TLS_DIRECTORY32 / IMAGE_TLS_DIRECTORY64 24 (0x18) bytes / 40 (0x28) bytes
| Field | Off. PE32 | Off. PE32+ | Size PE32 | Size PE32+ | Type | Meaning |
|---|---|---|---|---|---|---|
StartAddressOfRawData | 0x00 | 0x00 | 4 | 8 | PTR | VA of the TLS template start (.tls). |
EndAddressOfRawData | 0x04 | 0x08 | 4 | 8 | PTR | VA of the template end. |
AddressOfIndex | 0x08 | 0x10 | 4 | 8 | PTR | VA of the DWORD that receives the TLS slot index (_tls_index). |
AddressOfCallBacks | 0x0c | 0x18 | 4 | 8 | PTR | VA of a NULL-terminated array of PIMAGE_TLS_CALLBACK, called on process and thread attach/detach, before the entry point. |
SizeOfZeroFill | 0x10 | 0x20 | 4 | 4 | DWORD | Zero bytes after the template. |
Characteristics | 0x14 | 0x24 | 4 | 4 | DWORD | Alignment of the TLS block (IMAGE_SCN_ALIGN_* bits). |
main and even before a debugger stops at the entry point, which is why malware and anti-debugging code like them. All addresses here are VAs, not RVAs, so they have base relocations.COFF object files
A .obj file is a COFF file: IMAGE_FILE_HEADER at offset 0 (no DOS header, no optional header), the section table, raw data, per-section relocations, then the symbol table and the string table.
IMAGE_RELOCATION 10 (0xa) bytes
| Field | Offset | Size | Type | Meaning |
|---|---|---|---|---|
VirtualAddress | 0x00 | 4 | DWORD | Offset of the patched location in the section. |
SymbolTableIndex | 0x04 | 4 | DWORD | Index of the target symbol. |
Type | 0x08 | 2 | WORD | Relocation type (IMAGE_REL_AMD64_*, IMAGE_REL_ARM64_*...). |
#pragma pack(2)): 10 bytes, not 12.IMAGE_SYMBOL 18 (0x12) bytes
| Field | Offset | Size | Type | Meaning |
|---|---|---|---|---|
Name | 0x00 | 8 | BYTE[8] | Short name, or 4 zero bytes followed by a DWORD offset in the string table. |
Value | 0x08 | 4 | DWORD | Offset in the section, or size for common symbols. |
SectionNumber | 0x0c | 2 | SHORT | 1-based section index; 0 = undefined or common, -1 = absolute. |
Type | 0x0e | 2 | WORD | 0x20 = function, 0 = not a function. |
StorageClass | 0x10 | 1 | BYTE | 2 EXTERNAL, 3 STATIC, 103 FILE, 105 WEAK_EXTERNAL... |
NumberOfAuxSymbols | 0x11 | 1 | BYTE | Auxiliary 18-byte records that follow. |
x64 relocation types
| Name | Value | Meaning |
|---|---|---|
| IMAGE_REL_AMD64_ABSOLUTE | 0 | Ignored. |
| IMAGE_REL_AMD64_ADDR64 | 1 | 64-bit VA. |
| IMAGE_REL_AMD64_ADDR32 | 2 | 32-bit VA. |
| IMAGE_REL_AMD64_ADDR32NB | 3 | 32-bit RVA (.pdata, .xdata). |
| IMAGE_REL_AMD64_REL32 | 4 | 32-bit PC-relative from the end of the field (call, lea rip). |
| IMAGE_REL_AMD64_REL32_1 | 5 | REL32 when 1 byte of immediate follows the field. |
| IMAGE_REL_AMD64_REL32_2 | 6 | REL32, 2 bytes follow. |
| IMAGE_REL_AMD64_REL32_3 | 7 | REL32, 3 bytes follow. |
| IMAGE_REL_AMD64_REL32_4 | 8 | REL32, 4 bytes follow. |
| IMAGE_REL_AMD64_REL32_5 | 9 | REL32, 5 bytes follow. |
| IMAGE_REL_AMD64_SECTION | 0xa | 16-bit section index (debug info). |
| IMAGE_REL_AMD64_SECREL | 0xb | 32-bit offset from the start of the section (TLS, debug info). |
ARM64 relocation types
| Name | Value | Meaning |
|---|---|---|
| IMAGE_REL_ARM64_ABSOLUTE | 0 | Ignored. |
| IMAGE_REL_ARM64_ADDR32 | 1 | 32-bit VA. |
| IMAGE_REL_ARM64_ADDR32NB | 2 | 32-bit RVA. |
| IMAGE_REL_ARM64_BRANCH26 | 3 | b/bl 26-bit offset. |
| IMAGE_REL_ARM64_PAGEBASE_REL21 | 4 | adrp page. |
| IMAGE_REL_ARM64_REL21 | 5 | adr 21-bit offset. |
| IMAGE_REL_ARM64_PAGEOFFSET_12A | 6 | add low 12 bits. |
| IMAGE_REL_ARM64_PAGEOFFSET_12L | 7 | ldr/str low 12 bits (scaled). |
| IMAGE_REL_ARM64_SECREL | 8 | 32-bit section offset. |
| IMAGE_REL_ARM64_ADDR64 | 0xe | 64-bit VA. |
| IMAGE_REL_ARM64_BRANCH19 | 0xf | Conditional branch, 19-bit offset. |
| IMAGE_REL_ARM64_BRANCH14 | 0x10 | tbz/tbnz 14-bit offset. |
| IMAGE_REL_ARM64_REL32 | 0x11 | 32-bit PC-relative. |
Tools
| Task | Command |
|---|---|
| Headers, data directories | dumpbin /headers a.exe llvm-objdump -p a.exe |
| Imports / exports | dumpbin /imports a.exe dumpbin /exports a.dll |
| Base relocations | dumpbin /relocations a.exe llvm-readobj --coff-basereloc a.exe |
| Load config (CFG, cookie) | dumpbin /loadconfig a.exe llvm-readobj --coff-load-config a.exe |
| Sections | llvm-objdump -h a.exe |
| Disassemble | llvm-objdump -d --x86-asm-syntax=intel a.exe |
| Python | pefile.PE("a.exe").dump_info() |
| GUI | PE-bear, CFF Explorer, PE Studio, Detect It Easy |