LOADER_PARAMETER_BLOCK

The LOADER_PARAMETER_BLOCK is the structure through which the kernel and HAL learn the initialisation data that was gathered by the loader.

Historically, and for most practical purposes even in recent Windows versions, there is only ever the one instance of this structure. It is prepared by the loader as its means of handing over to the kernel. When the loader calls the kernel’s initialisation routine, the address of the loader block is the one argument. The kernel saves the address for a while in the exported variable KeLoaderBlock. At the end of the kernel’s initialisation, the structure gets freed and the variable gets cleared. Meanwhile, especially while debugging device driver initialisation, knowledge of this structure can be very helpful.

Variability

Perhaps because the LOADER_PARAMETER_BLOCK is accessible through an exported variable and is vital as shared data between the loader, kernel and HAL, it was highly stable for many Windows versions, certainly in comparison with other undocumented structures. Since Windows 7, however, it has become highly variable. Importantly, the changes after version 6.0 are not just from growth at the end: members are inserted and removed without regard for continuity. Notably, version 6.1 inserted four members at the structure’s very start. If only for now, I do not propose to track the variations much beyond the more or less mechanical work of reading symbol files. However, some measure of variability is readily available from the changing size of the structure. The following are known:

Version Size (x86) Size (x64)
3.51 to 4.0 0x64  
5.0 to 5.2 0x68 0xC8
6.0 0x7C 0xE8
6.1 0x88 0xF0
6.2 0xA0 0x0118
6.3 0xAC 0x0128
10.0 0xBC 0x0148

Layout

Until recently, Microsoft’s names for the LOADER_PARAMETER_BLOCK members and types were known only from the published symbol files for occasional Windows versions: first for Windows 2000 SP3 and SP4, then for all releases of Windows Vista and Windows 7, but for none since. Windows 10, however, brings something new…

Windows 10

A header file, ARC.H, in the Windows Driver Kit (WDK) for Windows 10 supplies a C-language definition of the LOADER_PARAMETER_BLOCK. This appears to be Microsoft’s first formal disclosure of the structure’s layout. It comes with no conditional compilation blocks for accommodating earlier versions. As supplied, it is immediately useful only for programming that targets Windows 10 specifically, yet doesn’t say so. Add that the header is beneath a subdirectory named “um”, presumably to mean user-mode, but that the LOADER_PARAMETER_BLOCK is long gone by the time any user-mode software gets to execute, and one might wonder if this structure’s definition is included by mistake.

Still, included it is. The following table presents the layout of the LOADER_PARAMETER_BLOCK for the original release of Windows 10 (build 10240), using names, types and offsets from Microsoft’s header:

Offset (x86) Offset (x64) Definition
0x00 0x00
ULONG OsMajorVersion;
0x04 0x04
ULONG OsMinorVersion;
0x08 0x08
ULONG Size;
0x0C 0x0C
ULONG OsLoaderSecurityVersion;
0x10 0x10
LIST_ENTRY LoadOrderListHead;
0x18 0x20
LIST_ENTRY MemoryDescriptorListHead;
0x20 0x30
LIST_ENTRY BootDriverListHead;
0x28 0x40
LIST_ENTRY EarlyLaunchListHead;
0x30 0x50
LIST_ENTRY CoreDriverListHead;
0x38 0x60
LIST_ENTRY CoreExtensionsDriverListHead;
0x40 0x70
LIST_ENTRY TpmCoreDriverListHead;
0x48 0x80
ULONG_PTR KernelStack;
0x4C 0x88
ULONG_PTR Prcb;
0x50 0x90
ULONG_PTR Process;
0x54 0x98
ULONG_PTR Thread;
0x58 0xA0
ULONG KernelStackSize;
0x5C 0xA4
ULONG RegistryLength;
0x60 0xA8
PVOID RegistryBase;
0x64 0xB0
CONFIGURATION_COMPONENT_DATA *ConfigurationRoot;
0x68 0xB8
CHAR *ArcBootDeviceName;
0x6C 0xC0
CHAR *ArcHalDeviceName;
0x70 0xC8
CHAR *NtBootPathName;
0x74 0xD0
CHAR *NtHalPathName;
0x78 0xD8
CHAR *LoadOptions;
0x7C 0xE0
NLS_DATA_BLOCK *NlsData;
0x80 0xE8
ARC_DISK_INFORMATION *ArcDiskInformation;
0x84 0xF0
LOADER_PARAMETER_EXTENSION *Extension;
0x88 0xF8
union {
    I386_LOADER_BLOCK I386;
    ARM_LOADER_BLOCK Arm;
} u;
0x94 0x0108
FIRMWARE_INFORMATION_LOADER_BLOCK FirmwareInformation;

History

Until the WDK for Windows 10, Microsoft’s names for the LOADER_PARAMETER_BLOCK members and types were known only from type information in symbol files for Windows Vista and Windows 7, and before then for Windows 2000 Service Packs 3 and 4. How the type information gets into symbol files for some versions but not others is not known. Names, types and offsets given below are from those symbol files in the versions for which they have type information. Names and types for other versions are inferred by assuming continuity except in the few cases where inspection of the loader or kernel shows that members have come and gone. Correlation of the more substantial changes since Windows 7 is left for another day.

Offset (x86) Offset (x64) Definition Versions
0x00 0x00
ULONG OsMajorVersion;
6.0 to 6.1
0x04 0x04
ULONG OsMinorVersion;
6.0 to 6.1
0x08 0x08
ULONG Size;
6.0 to 6.1
0x0C 0x0C
ULONG Reserved;
6.0 to 6.1
0x00 (3.51 to 6.0);
0x10
0x00 (5.2 to 6.0);
0x10
LIST_ENTRY LoadOrderListHead;
3.51 to 6.1
0x08 (3.51 to 6.0);
0x18
0x10 (5.2 to 6.0);
0x20
LIST_ENTRY MemoryDescriptorListHead;
3.51 to 6.1
0x10 (3.51 to 6.0);
0x20
0x20 (5.2 to 6.0);
0x30
LIST_ENTRY BootDriverListHead;
3.51 to 6.1
0x18 (3.51 to 6.0);
0x28
0x30 (5.2 to 6.0);
0x40
ULONG_PTR KernelStack;
3.51 to 6.1
0x1C (3.51 to 6.0);
0x2C
0x38 (5.2 to 6.0);
0x48
ULONG_PTR Prcb;
3.51 to 6.1
0x20 (3.51 to 6.0);
0x30
0x40 (5.2 to 6.0);
0x50
ULONG_PTR Process;
3.51 to 6.1
0x24 (3.51 to 6.0);
0x34
0x48 (5.2 to 6.0);
0x58
ULONG_PTR Thread;
3.51 to 6.1
0x28 (3.51 to 6.0);
0x38
0x50 (5.2 to 6.0);
0x60
ULONG RegistryLength;
3.51 to 6.1
0x2C (3.51 to 6.0);
0x3C
0x58 (5.2 to 6.0);
0x68
PVOID RegistryBase;
3.51 to 6.1
0x30 (3.51 to 6.0);
0x40
0x60 (5.2 to 6.0);
0x70
CONFIGURATION_COMPONENT_DATA *ConfigurationRoot;
3.51 to 6.1
0x34 (3.51 to 6.0);
0x44
0x68 (5.2 to 6.0);
0x78
PSTR ArcBootDeviceName;
3.51 to 6.1
0x38 (3.51 to 6.0);
0x48
0x70 (5.2 to 6.0);
0x80
PSTR ArcHalDeviceName;
3.51 to 6.1
0x3C (3.51 to 6.0);
0x4C
0x78 (5.2 to 6.0);
0x88
PSTR NtBootPathName;
3.51 to 6.1
0x40 (3.51 to 6.0);
0x50
0x80 (5.2 to 6.0);
0x90
PSTR NtHalPathName;
3.51 to 6.1
0x44 (3.51 to 6.0);
0x54
0x88 (5.2 to 6.0);
0x98
PSTR LoadOptions;
3.51 to 6.1
0x48 (3.51 to 6.0);
0x58
0x90 (5.2 to 6.0);
0xA0
NLS_DATA_BLOCK *NlsData;
3.51 to 6.1
0x4C (3.51 to 6.0);
0x5C
0x98 (5.2 to 6.0);
0xA8
ARC_DISK_INFORMATION *ArcDiskInformation;
3.51 to 6.1
0x50 (3.51 to 6.0);
0x60
0xA0 (5.2 to 6.0);
0xB0
PVOID OemFontFile;
3.51 to 6.1
0x54 (3.51 to 6.0) 0xA8 (5.2 to 6.0)
SETUP_LOADER_BLOCK *SetupLoaderBlock;
3.51 to 6.0
0x58 (3.51 to 6.0);
0x64
0xB0 (5.2 to 6.0);
0xB8
LOADER_PARAMETER_EXTENSION *Extension;
3.51 to 6.1
0x5C (3.51 to 6.0);
0x68
0xB8 (5.2 to 6.0);
0xC0
union {
    I386_LOADER_BLOCK I386;
    ALPHA_LOADER_BLOCK Alpha;
    IA64_LOADER_BLOCK Ia64;
} u;
3.51 to 6.0
union {
    I386_LOADER_BLOCK I386;
    IA64_LOADER_BLOCK Ia64;
} u;
6.1 only
0x68 (6.0);
0x74
0xC8 (6.0);
0xD0
FIRMWARE_INFORMATION_LOADER_BLOCK FirmwareInformation;
6.0 to 6.1

I386_LOADER_BLOCK

Since the I386_LOADER_BLOCK seems to have no purpose outside the LOADER_PARAMETER_BLOCK, it may as well be presented here:

Offset (x86) Offset (x64) Definition Versions
0x00 0x00
PVOID CommonDataArea;
3.51 to 6.1
0x04 0x08
ULONG MachineType;
3.51 to 6.1
0x08 0x0C
ULONG VirtualBias;
5.0 to 6.1

The VirtualBias member was added for version 5.0, which is the first to allow for increasing user-mode address space at the expense of kernel-mode (via the /3GB switch in the BOOT.INI configuration file).