The optional header follows the COFF
file header, at e_lfanew + 24. Object files can do without it, hence
the name, but every program and library has one. It holds what Windows needs to load the
image: where it wants to be loaded, how its sections are aligned, where to start
running, how much stack and heap to reserve, and the data directories that locate every
table. In a PE32+ file it is IMAGE_OPTIONAL_HEADER64: 112 bytes of fixed fields, then
the data directories, 240 bytes in all with the usual 16. It has no BaseOfData field,
and its image base and stack and heap sizes are 64 bits.
Standard fields
The first 24 bytes, inherited from COFF. The magic number decides the layout of everything after it.
| Offset | Size | Type | Field | Meaning |
|---|---|---|---|---|
| 0 | 2 | u16 | Magic | 0x20B for PE32+. 0x10B is PE32, a separate format, and 0x107 a ROM image. |
| 2 | 1 | u8 | MajorLinkerVersion | The version of the linker that made the file. |
| 3 | 1 | u8 | MinorLinkerVersion | Shown as two digits: 14 and 0 are 14.00. |
| 4 | 4 | u32 | SizeOfCode | The total size of the code sections. |
| 8 | 4 | u32 | SizeOfInitializedData | The total size of the initialised data sections. |
| 12 | 4 | u32 | SizeOfUninitializedData | The total size of the uninitialised (.bss) sections. |
| 16 | 4 | u32 | AddressOfEntryPoint | RVA of the entry point: the program’s start, a DLL’s initialisation function or a driver’s DriverEntry. 0 for a DLL without one. |
| 20 | 4 | u32 | BaseOfCode | RVA of the start of the code. |
Windows fields
The next 88 bytes. The image base and the four stack and heap sizes are 64 bits.
| Offset | Size | Type | Field | Meaning |
|---|---|---|---|---|
| 24 | 8 | u64 | ImageBase | The address the image prefers to be loaded at, a multiple of 64 KB. Microsoft’s linker uses 0x140000000 for programs and 0x180000000 for DLLs unless told otherwise, both above 4 GB. If the image cannot load there, the loader applies the base relocations. |
| 32 | 4 | u32 | SectionAlignment | The alignment of sections in memory: at least FileAlignment, and by default the page size, 4 KB. |
| 36 | 4 | u32 | FileAlignment | The alignment of section data in the file: a power of 2 from 512 to 64 KB, by default 512. |
| 40 | 2 | u16 | MajorOperatingSystemVersion | The version of Windows the image needs. |
| 42 | 2 | u16 | MinorOperatingSystemVersion | |
| 44 | 2 | u16 | MajorImageVersion | The image’s own version, set with the linker’s /VERSION. |
| 46 | 2 | u16 | MinorImageVersion | |
| 48 | 2 | u16 | MajorSubsystemVersion | The version of the subsystem the image needs. Windows refuses to run an image whose subsystem version is newer than itself. |
| 50 | 2 | u16 | MinorSubsystemVersion | |
| 52 | 4 | u32 | Win32VersionValue | Reserved, 0. |
| 56 | 4 | u32 | SizeOfImage | The size of the image in memory, headers included, a multiple of SectionAlignment. |
| 60 | 4 | u32 | SizeOfHeaders | The size of the DOS header, stub, PE headers and section table, rounded up to FileAlignment. The first section’s data starts here. |
| 64 | 4 | u32 | CheckSum | The image checksum; see Checksum. |
| 68 | 2 | u16 | Subsystem | What runs the image; see Subsystem. |
| 70 | 2 | u16 | DllCharacteristics | Flags; see DLL characteristics. Programs have them too. |
| 72 | 8 | u64 | SizeOfStackReserve | Address space to reserve for the main thread’s stack. |
| 80 | 8 | u64 | SizeOfStackCommit | How much of it to commit at the start. |
| 88 | 8 | u64 | SizeOfHeapReserve | Address space to reserve for the process heap. |
| 96 | 8 | u64 | SizeOfHeapCommit | How much of it to commit at the start. |
| 104 | 4 | u32 | LoaderFlags | Reserved, 0. |
| 108 | 4 | u32 | NumberOfRvaAndSizes | The number of data directories that follow, 16 in practice. |
| 112 | 8 each | – | Data directories | An RVA and a size for each table; see Data directories. |
00000100 0B 02 0E 00 00 8E 00 00
00000110 00 4C 00 00 00 00 00 00 E0 90 00 00 00 10 00 00
00000120 00 00 00 80 01 00 00 00 00 10 00 00 00 02 00 00
00000130 06 00 00 00 03 00 01 00 06 00 00 00 00 00 00 00
00000140 00 30 01 00 00 04 00 00 45 5B 01 00 02 00 60 01
00000150 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00
00000160 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00
00000170 00 00 00 00 10 00 00 00
0x108: magic 0x20B; linker 14.00; code 0x8E00 bytes, initialised data 0x4C00; entry point 0x90E0; BaseOfCode 0x1000; ImageBase 0x180000000, in 8 bytes where PE32 has BaseOfData and a 4-byte image base; alignments 0x1000 and 0x200; Windows 6.0; image version 3.1; subsystem 6.0; SizeOfImage 0x13000; SizeOfHeaders 0x400; CheckSum 0x15B45; subsystem 2 (GUI); DllCharacteristics 0x0160; stack and heap 1 MB reserved and 4 KB committed, 8 bytes each; 16 data directoriesThe entry point of that DLL is at 0x1800090E0 when it loads at its image
base. The image version, 3.1, is the version of GLFW it holds.
Checksum
Windows checks CheckSum only for drivers, for DLLs loaded at boot and for DLLs loaded
into critical system processes; for anything else 0 is fine, and most files have 0.
The algorithm is Microsoft’s CheckSumMappedFile, and the explorer
computes it for files up to 64 MB:
sum = 0
for each little-endian 16-bit word of the file, skipping the 4 bytes of CheckSum:
sum = sum + word
sum = (sum & 0xFFFF) + (sum >> 16)
(an odd last byte counts as a word whose high byte is 0)
sum = (sum & 0xFFFF) + (sum >> 16)
checksum = sum + the length of the file
The checksum covers the whole file, the certificate table included. The 64-bit
glfw3.dll’s 0x00015B45 is correct. In the files examined for this site, almost all of those whose checksum was wrong
were Wine’s own DLLs; an inference is that Wine’s build changes the files after the
checksum is set.
Subsystem
| Value | Name | Meaning |
|---|---|---|
| 0 | UNKNOWN | Unknown. |
| 1 | NATIVE | No subsystem: device drivers and native Windows processes. |
| 2 | WINDOWS_GUI | A Windows program with a graphical interface. |
| 3 | WINDOWS_CUI | A Windows console (character) program. |
| 5 | OS2_CUI | An OS/2 console program. |
| 7 | POSIX_CUI | A POSIX console program. |
| 8 | NATIVE_WINDOWS | A native Windows 9x driver. |
| 9 | WINDOWS_CE_GUI | A Windows CE program. |
| 10 | EFI_APPLICATION | An EFI application. |
| 11 | EFI_BOOT_SERVICE_DRIVER | An EFI driver with boot services. |
| 12 | EFI_RUNTIME_DRIVER | An EFI driver with run-time services. |
| 13 | EFI_ROM | An EFI ROM image. |
| 14 | XBOX | Xbox. |
| 16 | WINDOWS_BOOT_APPLICATION | A Windows boot application. |
In the PE32+ files examined for this site most were console DLLs and programs, largely Wine’s, then GUI ones, with a handful of native drivers and EFI applications and drivers.
DLL characteristics
| Bit | Name | Meaning |
|---|---|---|
0x0001–0x0008 | – | Reserved, 0. |
0x0020 | HIGH_ENTROPY_VA | The image can take high-entropy ASLR, which randomises addresses across the whole 64-bit address space. |
0x0040 | DYNAMIC_BASE | The image can be loaded at a random address (ASLR). |
0x0080 | FORCE_INTEGRITY | Code integrity checks are enforced: the image must be signed. |
0x0100 | NX_COMPAT | The image is compatible with data execution prevention (DEP). |
0x0200 | NO_ISOLATION | Isolation aware, but do not isolate the image. |
0x0400 | NO_SEH | The image uses no structured exception handlers, so none may be called in it. |
0x0800 | NO_BIND | Do not bind the image. |
0x1000 | APPCONTAINER | The image must run in an AppContainer. |
0x2000 | WDM_DRIVER | A WDM driver. |
0x4000 | GUARD_CF | The image supports Control Flow Guard; see Load configuration. |
0x8000 | TERMINAL_SERVER_AWARE | The program is aware of Terminal Server. |
The example’s 0x0160 is HIGH_ENTROPY_VA, DYNAMIC_BASE and
NX_COMPAT.