Optional Header
The Optional Header is the most important of the NT Headers and contains information allowing the PE file to be executed. It doesn’t have a fixed size, and the actual size can be found in the File Header’s SizeOfOptionalHeader element.
Although it’s called ‘optional’, this is only because some file types don’t contain it. The Optional Header is necessary for PE image files.
There are two versions of the Optional Header: one for 32-bit and one for 64-bit systems. The 32-bit version has one element that the 64-bit version (BaseOfData), and some of the elements are DWORD (4 bytes) in the 32-bit version and ULONGLONG (8 bytes) in the 64-bit version.
The following images show the Optional Header of a PE file as seen in PE-Bear:
The next sections will contain a copy of each version’s struct, followed by descriptions of the elements.
Optional Header Structures
32-Bit Optional Header
typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
64-Bit Optional Header
typedef struct _IMAGE_OPTIONAL_HEADER64 {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
ULONGLONG ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
ULONGLONG SizeOfStackReserve;
ULONGLONG SizeOfStackCommit;
ULONGLONG SizeOfHeapReserve;
ULONGLONG SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
Optional Header Elements
Magic
The magic number is used to determine if the image is 32 or 64-bit executable or used for ROM. This table shows the three possible values of the magic number:
Value | Definition |
0x10B | PE32 (32-bit) executable |
0x20B | PE32+ (64-bit) executable |
0x107 | ROM image |
MajorLinkerVersion
/MinorLinkerVersion
The major and minor version numbers of the linker.
SizeOfCode
The size of the code (.text) section. If there are multiple sections, contains the sum of all code sections.
SizeOfInitializedData
Size of the initialized data (.data) section. If there are multiple sections, contains the sum of all initialized data sections.
SizeOfUninitializedData
The size of the uninitialized data (.bss) section. If there are multiple sections, contains the sum of all uninitialized data sections.
AddressOfEntryPoint
Address of the entry point, relative to the image base when the executable file is loaded into memory. Optional for DLLs. For program images, this points to the starting address. For device drivers, this points to the address of the initialization function. If there is no entry point then this field is zero.
BaseOfCode
Relative virtual address (RVA) of the start of the code (.text) section when the PE is loaded into memory.
BaseOfData
(32-bit Only)
Relative virtual address (RVA) of the start of the data (.data) section when the PE is loaded into memory.
ImageBase
The preferred address of the first byte of image when loaded into memory. Must be a multiple of 64K. This address is rarely used because Windows uses memory protection mechanisms like Address Space Layout Randomization (ASLR). As a result, it’s rare to see an image mapped to the preferred address. Instead, the Windows PE Loader maps the file to a different address with an unused memory range. This process would create issues because some addresses that would have been constant are now changed. The Loader addresses this via a process called PE relocation which fixes these constant addresses to work with the new image base. The relocation section (.reloc) holds data essential to this relocation process.
SectionAlignment
Holds a byte value used for section alignment in memory. This value must be greater than or equal to FileAlignment (the next element in the Optional Header structure). When loaded into memory, sections are aligned in memory boundaries that are multiples of this value. The default value of SectionAlignment is the page size for the architecture. If SectionAlignment is less than the page size then its value should match FileAlignment.
FileAlignment
This field holds a byte value that is used to align the raw data of sections on disk. The default value is 512 but it can be any number that is a power of 2 (i.e. 2x) between 512 and 64K (inclusive). However, it must be less than or equal to the value of SectionAlignment. If FileAlignment is less than SectionAlignment, then remainder will be padded with zeroes in order to maintain the alignment boundaries.
MajorOperatingSystemVersion
Major version number of the required operating system.
MinorOperatingSystemVersion
Minor version number of the required operating system.
MajorImageVersion
Major version number of the image.
MinorImageVersion
Minor version number of the image.
MajorSubsystemVersion
Major version number of the subsystem.
MinorSubsystemVersion
Minor version number of the subsystem.
Win32VersionValue
A reserved field that must be set to 0
(according to the Microsoft Docs).
SizeOfImage
The size of the image file (in bytes), including all headers. It gets rounded up to a multiple of SectionAlignment
because this value is used when loading the image into memory.
SizeOfHeaders
The combined size of the MS-DOS stub, PE header(the NT Headers), and section headers. This number is rounded up to a multiple of FileAlignment.
CheckSum
The checksum of the image file, calculated using an algorithm incorporated into IMAGHELP.DLL.
Subsystem
The subsystem required to run the image. The following table contains the defined values, for reference:
Value | Constant | Description |
---|---|---|
0 | IMAGE_SUBSYSTEM_UNKNOWN | Unknown subsystem |
1 | IMAGE_SUBSYSTEM_NATIVE | Device drivers / native Windows processes |
2 | IMAGE_SUBSYSTEM_WINDOWS_GUI | The Windows GUI subsystem |
3 | IMAGE_SUBSYSTEM_WINDOWS_CUI | The Windows character subsystem |
5 | IMAGE_SUBSYSTEM_OS2_CUI | The OS/2 character subsystem |
7 | IMAGE_SUBSYSTEM_POSIX_CUI | The Posix character subsystem |
8 | IMAGE_SUBSYSTEM_NATIVE_WINDOWS | Native Win9x driver |
9 | IMAGE_SUBSYSTEM_WINDOWS_CE_GUI | Windows CE |
10 | IMAGE_SUBSYSTEM_EFI_APPLICATION | An EFI application |
11 | IMAGE_SUBSYSTEM_EFI_BOOT_ SERVICE_DRIVER | An EFI driver with boot services |
12 | IMAGE_SUBSYSTEM_EFI_RUNTIME_ DRIVER | An EFI driver with run-time services |
13 | IMAGE_SUBSYSTEM_EFI_ROM | An EFI ROM image |
14 | IMAGE_SUBSYSTEM_XBOX | XBOX |
16 | IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION | Windows boot application. |
DLLCharacteristics
Some characteristics of the image file. See the below table for the defined values.
Value | Constant | Description |
---|---|---|
0x001 | Reserved; must be zero. | |
0x002 | Reserved; must be zero. | |
0x004 | Reserved; must be zero. | |
0x008 | Reserved; must be zero. | |
0x0020 | IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | The Image can handle a high entropy 64-bit virtual address space. |
0x0040 | IMAGE_DLLCHARACTERISTICS_ DYNAMIC_BASE | DLL can be relocated at load time. |
0x0080 | IMAGE_DLLCHARACTERISTICS_ FORCE_INTEGRITY | Code Integrity checks are enforced. |
0x0100 | IMAGE_DLLCHARACTERISTICS_ NX_COMPAT | Image is NX compatible. |
0x0200 | IMAGE_DLLCHARACTERISTICS_ NO_ISOLATION | Isolation aware, but do not isolate the image. |
0x0400 | IMAGE_DLLCHARACTERISTICS_ NO_SEH | Does not use structured exception handling. |
0x0800 | IMAGE_DLLCHARACTERISTICS_ NO_BIND | Do not bind the image. |
0x1000 | IMAGE_DLLCHARACTERISTICS_APPCONTAINER | Image must execute inside an AppContainer. |
0x2000 | IMAGE_DLLCHARACTERISTICS_ WDM_DRIVER | WDM driver. |
0x4000 | IMAGE_DLLCHARACTERISTICS_GUARD_CF | Image supports Control Flow Guard. |
0x8000 | IMAGE_DLLCHARACTERISTICS_ TERMINAL_SERVER_AWARE | Terminal Server aware. |
SizeOfStackReserve
The size of the stack to reserve. Note that only SizeOfStackCommit is committed. The rest is made available one page at a time until the reserve size is reached.
SizeOfStackCommit
The size of the stack to commit.
SizeOfHeapReserve
The size of local heap space to reserve. Note that only SizeOfHeapCommit is committed. The rest is made available one page at a time until the reserve size is reached.
SizeOfHeapCommit
The size of local heap space to commit.
LoaderFlags
Reserved; according to the Microsoft docs, this must be set to zero.
NumberOfRvaAndSizes
The number of entries in the data directory array.
DataDirectory
This is one of the most important members of the Optional Header. It contains an array of IMAGE_DATA_DIRECTORY
structures. The Data Directory is important enough that it it has its own page.