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. During the system’s initialisation, however, 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 version 5.2, however, each change even of the minor version number brings a change of size:

Version Size (x86) Size (x64)
3.10 to early 4.0 (before Windows NT 4.0 SP3) 0x64  
late 4.0 to 5.2 0x68 0xC8
6.0 0x7C 0xE8
6.1 0x88 0xF0
6.2 0xA0 0x0118
6.3 0xAC 0x0128
10.0 to 1709 0xBC 0x0148
1803 and higher 0xC8 0x0160

The growth in version 4.0 and again from 6.2 to 6.3 involves no additions, removals or rearrangements to the structure’s own members, just growth within the member that was at the time the structure’s last. Version 6.0 brought a straightforward appending of one member. Such growth only at the end allows for backwards compatibility. A new loader can prepare the structure in its new layout but safely pass it to an old kernel. This was indeed depended on for multi-boot configurations in the days when the one NTLDR in the root directory of the bootable partition might load the kernel of any earlier Windows version (if not of a later one).

Version 6.0 separated the booting of Windows into a boot manager, e.g., BOOTMGR, and a boot loader, e.g., WINLOAD. The boot manager selects which of the installed Windows versions (or different configurations) to proceed with. Each Windows version provides its own boot loader. This, not the boot manager, is what prepares the LOADER_PARAMETER_BLOCK and it only has to do so for the matching kernel. Backwards compatibility is no longer an issue for the structure. Most changes since version 6.0 are not just from growing at the end: members are inserted and removed without regard for continuity. Notably, version 6.1 inserted version numbers and a size at the structure’s very start, surely to provide some easy and reliable means for future kernels to validate that the structure received from the loader is plausibly what that kernel expects. This defence was apparently thought important enough to warrant its own bug-check, LOADER_BLOCK_MISMATCH (0x0100).

Layout

Until recently, Microsoft’s names for the LOADER_PARAMETER_BLOCK members and types were known only from type information in the public symbol files in occasional Windows versions: first for Windows 2000 SP3 and SP4, and then for all releases of Windows Vista and Windows 7. How the type information gets into symbol files for some versions but not others is not known. Windows 10, however, brings something new…

A header file, named ARC.H, in the Enterprise edition of the Windows Driver Kit (WDK) for Windows 10 Version 1511 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 a specific release of Windows 10, 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 was published by mistake.

Still, published it is. Then, just as that seemed to be the end of disclosure, perhaps forever, Microsoft’s names and types returned to the public symbol files for the kernel in the 1803 release of Windows 10.

At the other end of the history, as something of an archaeological dig, it turns out that type information for the LOADER_PARAMETER_BLOCK was published by Microsoft even for version 4.0, just not in symbol files but instead in an unusually large CRASHLIB.LIB supplied with source code for the Dr. Watson sample in a Platfrom Software Development Kit (SDK) from January 1998.

The following table presents the layout of the LOADER_PARAMETER_BLOCK for the 1803 release of Windows 10, as given by the public symbol files, and for the 1511 release of Windows 10, as given by Microsoft’s ARC.H. For earlier versions, the layout is directly from type information in symbol files and libraries, if available. Names, types and offsets for all other versions are something of a guess from assuming continuity except where inspection of the loader or kernel shows that members have come and gone.

Offset (x86) Offset (x64) Definition Versions
0x00 0x00
ULONG OsMajorVersion;
6.1 and higher
0x04 0x04
ULONG OsMinorVersion;
6.1 and higher
0x08 0x08
ULONG Size;
6.1 and higher
0x0C 0x0C
ULONG Reserved;
6.1 to 10.0
ULONG OsLoaderSecurityVersion;
1511 and higher
0x00 (3.10 to 6.0);
0x10
0x00 (5.2 to 6.0);
0x10
LIST_ENTRY LoadOrderListHead;
all
0x08 (3.10 to 6.0);
0x18
0x10 (5.2 to 6.0);
0x20
LIST_ENTRY MemoryDescriptorListHead;
all
0x10 (3.10 to 6.0);
0x20
0x20 (5.2 to 6.0);
0x30
LIST_ENTRY BootDriverListHead;
all
0x28 0x40
LIST_ENTRY EarlyLaunchListHead;
6.2 and higher
0x30 0x50
LIST_ENTRY CoreDriverListHead;
6.2 and higher
0x38 0x60
LIST_ENTRY CoreExtensionsDriverListHead;
10.0 and higher
0x40 0x70
LIST_ENTRY TpmCoreDriverListHead;
10.0 and higher
0x18 (3.10 to 6.0);
0x28 (6.1);
0x38 (6.2 to 6.3);
0x48
0x30 (5.2 to 6.0);
0x40 (6.1);
0x60 (6.2 to 6.3);
0x80
ULONG_PTR KernelStack;
all
0x1C (3.10 to 6.0);
0x2C (6.1);
0x3C (6.2 to 6.3);
0x4C
0x38 (5.2 to 6.0);
0x48 (6.1);
0x68 (6.2 to 6.3);
0x88
ULONG_PTR Prcb;
all
0x20 (3.10 to 6.0);
0x30 (6.1);
0x40 (6.2 to 6.3);
0x50
0x40 (5.2 to 6.0);
0x50 (6.1);
0x70 (6.2 to 6.3);
0x90
ULONG_PTR Process;
all
0x24 (3.10 to 6.0);
0x34 (6.1);
0x44 (6.2 to 6.3);
0x54
0x48 (5.2 to 6.0);
0x58 (6.1);
0x78 (6.2 to 6.3);
0x98
ULONG_PTR Thread;
all
0x48 (6.2 to 6.3);
0x58
0x80 (6.2 to 6.3);
0xA0
ULONG KernelStackSize;
6.2 and higher
0x28 (3.10 to 6.0);
0x38 (6.1);
0x4C (6.2 to 6.3);
0x5C
0x50 (5.2 to 6.0);
0x60 (6.1);
0x84 (6.2 to 6.3);
0xA4
ULONG RegistryLength;
all
0x2C (3.10 to 6.0);
0x3C (6.1);
0x50 (6.2 to 6.3);
0x60
0x58 (5.2 to 6.0);
0x68 (6.1);
0x88 (6.2 to 6.3);
0xA8
PVOID RegistryBase;
all
0x30 (3.10 to 6.0);
0x40 (6.1);
0x54 (6.2 to 6.3);
0x64
0x60 (5.2 to 6.0);
0x70 (6.1);
0x90 (6.2 to 6.3);
0xB0
CONFIGURATION_COMPONENT_DATA *ConfigurationRoot;
all
0x34 (3.10 to 6.0);
0x44 (6.1);
0x58 (6.2 to 6.3);
0x68
0x68 (5.2 to 6.0);
0x78 (6.1);
0x98 (6.2 to 6.3);
0xB8
PSTR ArcBootDeviceName;
all
0x38 (3.10 to 6.0);
0x48 (6.1);
0x5C (6.2 to 6.3);
0x6C
0x70 (5.2 to 6.0);
0x80 (6.1);
0xA0 (6.2 to 6.3);
0xC0
PSTR ArcHalDeviceName;
all
0x3C (3.10 to 6.0);
0x4C (6.1);
0x60 (6.2 to 6.3);
0x70
0x78 (5.2 to 6.0);
0x88 (6.1);
0xA8 (6.2 to 6.3);
0xC8
PSTR NtBootPathName;
all
0x40 (3.10 to 6.0);
0x50 (6.1);
0x64 (6.2 to 6.3);
0x74
0x80 (5.2 to 6.0);
0x90 (6.1);
0xB0 (6.2 to 6.3);
0xD0
PSTR NtHalPathName;
all
0x44 (3.10 to 6.0);
0x54 (6.1);
0x68 (6.2 to 6.3);
0x78
0x88 (5.2 to 6.0);
0x98 (6.1);
0xB8 (6.2 to 6.3);
0xD8
PSTR LoadOptions;
all
0x48 (3.10 to 6.0);
0x58 (6.1);
0x6C (6.2 to 6.3);
0x7C
0x90 (5.2 to 6.0);
0xA0 (6.1);
0xC0 (6.2 to 6.3);
0xE0
NLS_DATA_BLOCK *NlsData;
all
0x4C (3.10 to 6.0);
0x5C (6.1);
0x70 (6.2 to 6.3);
0x80
0x98 (5.2 to 6.0);
0xA8 (6.1);
0xC8 (6.2 to 6.3);
0xE8
ARC_DISK_INFORMATION *ArcDiskInformation;
all
0x50 (3.10 to 6.0);
0x60 (6.1)
0xA0 (5.2 to 6.0);
0xB0 (6.1)
PVOID OemFontFile;
3.10 to 6.1
0x54 (3.10 to 6.0) 0xA8 (5.2 to 6.0)
SETUP_LOADER_BLOCK *SetupLoaderBlock;
3.10 to 6.0
0x58 (3.10 to 6.0);
0x64 (6.1);
0x74 (6.2 to 6.3);
0x84
0xB0 (5.2 to 6.0);
0xB8 (6.1);
0xD0 (6.2 to 6.3);
0xF0
ULONG Spare1;
3.10 to 4.0
LOADER_PARAMETER_EXTENSION *Extension;
5.0 and higher
0x5C (3.10 to 6.0);
0x68 (6.1);
0x78 (6.2 to 6.3);
0x88
0xB8 (5.2 to 6.0);
0xC0 (6.1);
0xD8 (6.2 to 6.3);
0xF8
union {
    I386_LOADER_BLOCK I386;
    MIPS_LOADER_BLOCK Mips;
    ALPHA_LOADER_BLOCK Alpha;
    PPC_LOADER_BLOCK Ppc;
} u;
late 4.0 only
union {
    I386_LOADER_BLOCK I386;
    ALPHA_LOADER_BLOCK Alpha;
    IA64_LOADER_BLOCK Ia64;
} u;
5.0 and 6.0
union {
    I386_LOADER_BLOCK I386;
    IA64_LOADER_BLOCK Ia64;
} u;
6.1 only
union {
    I386_LOADER_BLOCK I386;
    ARM_LOADER_BLOCK Arm;
} u;
10.0 and higher
0x68 (6.0);
0x74 (6.1);
0x84 (6.2 to 6.3);
0x94
0xC8 (6.0);
0xD0 (6.1);
0xE8 (6.2 to 6.3);
0x0108
FIRMWARE_INFORMATION_LOADER_BLOCK FirmwareInformation;
6.0 and higher
0xBC 0x0148
PSTR OsBootstatPathName;
1803 and higher
0xC0 0x0150
PSTR ArcOSDataDeviceName;
1803 and higher
0xC4 0x0158
PSTR ArcWindowsSysPartName;
1803 and higher

The C-language definition in Microsoft’s ARC.H shows that Reserved as known from the Windows 7 symbol files is now put to use as an OsLoaderSecurityVersion. The only security version yet known is 1.

Members of the u union are shown above only for the versions that have type information in symbol files or libraries or for which Microsoft publishes a C-language definition. Despite its name, the I386 member is defined for both x86 and x64 builds. Members other than I386 presumably change with Microsoft’s choice of supported processor architectures. Such support was wider in the early versions, but which other processors had explicit support in this union cannot be known from any inspection just of the x86 and x64 binaries, and is therefore left alone for these notes.

The three new members for the 1803 release elaborate the ancient ArcBootDeviceName and ArcHalDeviceName members, now adding ARC paths for the Boot Status Data (BSD) log and for whatever devices are given by the osdatadevice and windowssyspart boot options.