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_HEADER32: 96 bytes of fixed fields, then the
data directories, 224 bytes in all with the usual 16.
Standard fields
The first 28 bytes, inherited from COFF. The magic number decides the layout of everything after it.
| Offset | Size | Type | Field | Meaning |
|---|---|---|---|---|
| 0 | 2 | u16 | Magic | 0x10B for PE32. 0x20B 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. |
| 24 | 4 | u32 | BaseOfData | RVA of the start of the data. Only PE32 has this field. |
Windows fields
The next 68 bytes. In PE32 the image base and the four stack and heap sizes are 32 bits.
| Offset | Size | Type | Field | Meaning |
|---|---|---|---|---|
| 28 | 4 | u32 | ImageBase | The address the image prefers to be loaded at, a multiple of 64 KB. Programs usually ask for 0x400000 and DLLs for 0x10000000. If it 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 | 4 | u32 | SizeOfStackReserve | Address space to reserve for the main thread’s stack. |
| 76 | 4 | u32 | SizeOfStackCommit | How much of it to commit at the start. |
| 80 | 4 | u32 | SizeOfHeapReserve | Address space to reserve for the process heap. |
| 84 | 4 | u32 | SizeOfHeapCommit | How much of it to commit at the start. |
| 88 | 4 | u32 | LoaderFlags | Reserved, 0. |
| 92 | 4 | u32 | NumberOfRvaAndSizes | The number of data directories that follow, 16 in practice. |
| 96 | 8 each | – | Data directories | An RVA and a size for each table; see Data directories. |
00000110 0B 01 0E 00 00 80 00 00
00000120 00 3A 00 00 00 00 00 00 4C 86 00 00 00 10 00 00
00000130 00 90 00 00 00 00 00 10 00 10 00 00 00 02 00 00
00000140 06 00 00 00 03 00 01 00 06 00 00 00 00 00 00 00
00000150 00 F0 00 00 00 04 00 00 ED 11 01 00 02 00 40 01
00000160 00 00 10 00 00 10 00 00 00 00 10 00 00 10 00 00
00000170 00 00 00 00 10 00 00 00
0x118: magic 0x10B; linker 14.00; code 0x8000 bytes, initialised data 0x3A00; entry point 0x864C; BaseOfCode 0x1000; BaseOfData 0x9000; ImageBase 0x10000000; alignments 0x1000 and 0x200; Windows 6.0; image version 3.1; subsystem 6.0; SizeOfImage 0xF000; SizeOfHeaders 0x400; CheckSum 0x111ED; subsystem 2 (GUI); DllCharacteristics 0x0140; stack and heap 1 MB reserved, 4 KB committed; 16 data directoriesThe entry point of that DLL is at 0x1000864C 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, so signing a file
changes it. The 32-bit glfw3.dll’s 0x000111ED is correct. In the files
examined for this site, most had 0, and 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. |
Most PE32 files examined for this site were GUI programs or DLLs, about a third console ones, and a handful native, Windows CE or EFI.
DLL characteristics
| Bit | Name | Meaning |
|---|---|---|
0x0001–0x0008 | – | Reserved, 0. |
0x0020 | HIGH_ENTROPY_VA | The image can take a 64-bit address space with high-entropy ASLR. It means something only in a 64-bit image. |
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 0x0140 is DYNAMIC_BASE and NX_COMPAT. The .NET library
AsyncCtpLibrary.dll has 0x8540: DYNAMIC_BASE, NX_COMPAT, NO_SEH and
TERMINAL_SERVER_AWARE.