Geoff Chappell, Software Analyst
The LOADER_PARAMETER_EXTENSION structure is part of the mechanism through which the kernel and HAL learn the initialisation data that was gathered by the loader. It exists only as data that is pointed to from the LOADER_PARAMETER_BLOCK whose address the loader passes to the kernel for the latter’s initialisation.
The architectural point to having two structures seems to be that the LOADER_PARAMETER_BLOCK should be relatively stable across Windows versions, which indeed it was until Windows 7, but the LOADER_PARAMETER_EXTENSION can vary significantly and often has.
It cannot be stressed enough that the LOADER_PARAMETER_EXTENSION, however vital as shared data between the loader, kernel and HAL, is highly variable. Indeed, it is greatly expanded in later versions. Importantly, the change is not just from growth at the end: members are removed, changed and inserted without regard for continuity. 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) |
---|---|---|
5.0 | 0x28 | |
5.1 | 0x3C | |
5.1 starting with SP1 | 0x40 | |
5.2 | 0x50 | |
5.2 starting with SP1 | 0x58 | |
6.0 | 0x7C | 0xB8 |
6.1 | 0xE8 | 0x0148 |
6.2 | 0x0870 | 0x0920 |
6.3 | 0x08E0 | 0x0988 |
10.0 | 0x0920 | 0x09E0 |
10.0 starting with Version 1511 | 0x0930 | 0x09F0 |
Until recently, Microsoft’s names for the LOADER_PARAMETER_EXTENSION 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…
A header file, ARC.H, in the Windows Driver Kit (WDK) for Windows 10 supplies a C-language definition of the LOADER_PARAMETER_EXTENSION. 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 not just Windows 10 specifically but one particular update 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_EXTENSION 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.
The following table presents the layout of the LOADER_PARAMETER_EXTENSION for the original release of Windows 10 (build 10240), using names, types and offsets from Microsoft’s header:
Offset (x86) | Offset (x64) | Definition |
---|---|---|
0x00 | same |
ULONG Size; |
0x04 | same |
PROFILE_PARAMETER_BLOCK Profile; |
0x14 | 0x18 |
PVOID EmInfFileImage; |
0x18 | 0x20 |
ULONG EmInfFileSize; |
0x1C | 0x28 |
PVOID TriageDumpBlock; |
0x20 | 0x30 |
HEADLESS_LOADER_BLOCK *HeadlessLoaderBlock; |
0x24 | 0x38 |
SMBIOS_TABLE_HEADER *SMBiosEPSHeader; |
0x28 | 0x40 |
PVOID DrvDBImage; |
0x2C | 0x48 |
ULONG DrvDBSize; |
0x30 | 0x50 |
NETWORK_LOADER_BLOCK *NetworkLoaderBlock; |
0x34 |
PUCHAR HalpIRQLToTPR; |
|
0x38 |
PUCHAR HalpVectorToIRQL; |
|
0x3C | 0x58 |
LIST_ENTRY FirmwareDescriptorListHead; |
0x44 | 0x68 |
PVOID AcpiTable; |
0x48 | 0x70 |
ULONG AcpiTableSize; |
0x4C | 0x74 |
struct { ULONG LastBootSucceeded : 1; // 0x00000001 ULONG LastBootShutdown : 1; // 0x00000002 ULONG IoPortAccessSupported : 1; // 0x00000004 ULONG BootDebuggerActive : 1; // 0x00000008 ULONG StrongCodeGuarantees : 1; // 0x00000010 ULONG HardStrongCodeGuarantees : 1; // 0x00000020 ULONG SidSharingDisabled : 1; // 0x00000040 ULONG TpmInitialized : 1; // 0x00000080 ULONG VsmConfigured : 1; // 0x00000100 ULONG IumEnabled : 1; // 0x00000200 ULONG IsSmbboot : 1; // 0x00000400 ULONG Reserved : 21; }; |
0x50 | 0x78 |
LOADER_PERFORMANCE_DATA *LoaderPerformanceData; |
0x54 | 0x80 |
LIST_ENTRY BootApplicationPersistentData; |
0x5C | 0x90 |
PVOID WmdTestResult; |
0x60 | 0x98 |
GUID BootIdentifier; |
0x70 | 0xA8 |
ULONG ResumePages; |
0x74 | 0xB0 |
PVOID DumpHeader; |
0x78 | 0xB8 |
PVOID BgContext; |
0x7C | 0xC0 |
PVOID NumaLocalityInfo; |
0x80 | 0xC8 |
PVOID NumaGroupAssignment; |
0x84 | 0xD0 |
LIST_ENTRY AttachedHives; |
0x8C | 0xE0 |
ULONG MemoryCachingRequirementsCount; |
0x90 | 0xE8 |
PVOID MemoryCachingRequirements; |
0x98 | 0xF0 |
BOOT_ENTROPY_LDR_RESULT BootEntropyResult; |
0x0810 | 0x0868 |
ULONGLONG ProcessorCounterFrequency; |
0x0818 | 0x0870 |
LOADER_PARAMETER_HYPERVISOR_EXTENSION HypervisorExtension; |
0x0850 | 0x08A8 |
GUID HardwareConfigurationId; |
0x0860 | 0x08B8 |
LIST_ENTRY HalExtensionModuleList; |
0x0868 | 0x08C8 |
LARGE_INTEGER SystemTime; |
0x0870 | 0x08D0 |
ULONGLONG TimeStampAtSystemTimeRead; |
0x0878 | 0x08D8 |
ULONGLONG BootFlags; |
0x0880 | 0x08E0 |
ULONGLONG InternalBootFlags; |
0x0888 | 0x08E8 |
PVOID WfsFPData; |
0x088C | 0x08F0 |
ULONG WfsFPDataSize; |
0x0890 | 0x08F8 |
LOADER_BUGCHECK_PARAMETERS BugcheckParameters; |
0x08A4 | 0x0920 |
PVOID ApiSetSchema; |
0x08A8 | 0x0928 |
ULONG ApiSetSchemaSize; |
0x08AC | 0x0930 |
LIST_ENTRY ApiSetSchemaExtensions; |
0x08B4 | 0x0940 |
UNICODE_STRING AcpiBiosVersion; |
0x08BC | 0x0950 |
UNICODE_STRING SmbiosVersion; |
0x08C4 | 0x0960 |
UNICODE_STRING EfiVersion; |
0x08CC | 0x0970 |
DEBUG_DEVICE_DESCRIPTOR *KdDebugDevice; |
0x08D0 | 0x0978 |
OFFLINE_CRASHDUMP_CONFIGURATION_TABLE OfflineCrashdumpConfigurationTable; |
0x08F0 | 0x0998 |
UNICODE_STRING ManufacturingProfile; |
0x08F8 | 0x09A8 |
PVOID BbtBuffer; |
0x0900 | 0x09B0 |
ULONG64 XsaveAllowedFeatures; |
0x0908 | 0x09B8 |
ULONG XsaveFlags; |
0x090C | 0x09C0 |
PVOID BootOptions; |
0x0910 | 0x09C8 |
ULONG BootId; |
0x0914 | 0x09D0 |
LOADER_PARAMETER_CI_EXTENSION *CodeIntegrityData; |
0x0918 | 0x09D8 |
ULONG CodeIntegrityDataSize; |
The definition in Microsoft’s header continues with a
LOADER_HIVE_RECOVER_INFO SystemHiveRecoveryInfo;
which would be at offsets 0x091C and 0x09E0 in the 32-bit and 64-bit builds, respectively, and bring the structure to 0x0930 and 0x09F0 bytes. The preceding table omits this member because it is not in the structure as used in the original Windows 10. It is in the Version 1511 (build 10586), but not in the original—and working out how to present developments now that Microsoft says all future Windows releases will be version 10.0 is a problem I leave for another time.
Some changes on the way to Windows 10 are known. Especially notable is the huge expansion that came when version 6.2 changed from a TPM_BOOT_ENTROPY_LDR_RESULT to a BOOT_ENTROPY_LDR_RESULT (which then changes internally for version 6.3). The three members starting with ApiSetSchema were inserted for version 6.3 (in front of the AcpiBiosVersion that was already defined for version 6.2).
A detailed history surely will be presented here some time, but the work has no sort of priority. Meanwhile, the following names, types and offsets are known from symbol files for Windows Vista and Windows 7. Type information for the LOADER_PARAMETER_EXTENSION is also in symbol files 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.
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x00 (6.0); 0x00 |
0x00 (6.0); 0x00 |
ULONG Size; |
6.0 to 6.1 |
0x04 (6.0); 0x04 |
0x04 (6.0); 0x04 |
PROFILE_PARAMETER_BLOCK Profile; |
6.0 to 6.1 |
0x14 (6.0) | 0x14 (6.0) |
ULONG MajorVersion; |
6.0 only |
0x18 (6.0) | 0x18 (6.0) |
ULONG MinorVersion; |
6.0 only |
0x1C (6.0); 0x14 |
0x20 (6.0); 0x18 |
PVOID EmInfFileImage; |
6.0 to 6.1 |
0x20 (6.0); 0x18 |
0x28 (6.0); 0x20 |
ULONG EmInfFileSize; |
6.0 to 6.1 |
0x24 (6.0); 0x1C |
0x30 (6.0); 0x28 |
PVOID TriageDumpBlock; |
6.0 to 6.1 |
0x28 (6.0); 0x20 |
0x38 (6.0); 0x30 |
ULONG_PTR LoaderPagesSpanned; |
6.0 to 6.1 |
0x2C (6.0); 0x24 |
0x40 (6.0); 0x38 |
HEADLESS_LOADER_BLOCK *HeadlessLoaderBlock; |
6.0 to 6.1 |
0x30 (6.0); 0x28 |
0x48 (6.0); 0x40 |
SMBIOS_TABLE_HEADER *SMBiosEPSHeader; |
6.0 to 6.1 |
0x34 (6.0); 0x2C |
0x50 (6.0); 0x48 |
PVOID DrvDBImage; |
6.0 to 6.1 |
0x38 (6.0); 0x30 |
0x58 (6.0); 0x50 |
ULONG DrvDBSize; |
6.0 to 6.1 |
0x3C (6.0); 0x34 |
0x60 (6.0); 0x58 |
NETWORK_LOADER_BLOCK *NetworkLoaderBlock; |
6.0 to 6.1 |
0x40 (6.0); 0x38 |
PUCHAR HalpIRQLToTPR; |
6.0 to 6.1 | |
0x44 (6.0); 0x3C |
PUCHAR HalpVectorToIRQL; |
6.0 to 6.1 | |
0x48 (6.0); 0x40 |
0x68 (6.0); 0x60 |
LIST_ENTRY FirmwareDescriptorListHead; |
6.0 to 6.1 |
0x50 (6.0); 0x48 |
0x78 (6.0); 0x70 |
PVOID AcpiTable; |
6.0 to 6.1 |
0x54 (6.0); 0x4C |
0x80 (6.0); 0x78 |
ULONG AcpiTableSize; |
6.0 to 6.1 |
0x58 (6.0); 0x50 |
0x84 (6.0); 0x7C |
struct { ULONG BootViaWinload : 1; // 0x01 ULONG Reserved : 31; }; |
6.0 only |
struct { ULONG LastBootSucceeded : 1; // 0x01 ULONG LastBootShutdown : 1; // 0x02 ULONG IoPortAccessSupported : 1; // 0x04 ULONG Reserved : 29; }; |
6.1 only | ||
0x5C (6.0); 0x54 |
0x88 (6.0); 0x80 |
LOADER_PERFORMANCE_DATA *LoaderPerformanceData; |
6.0 to 6.1 |
0x60 (6.0); 0x58 |
0x90 (6.0); 0x88 |
LIST_ENTRY BootApplicationPersistentData; |
6.0 to 6.1 |
0x68 (6.0); 0x60 |
0xA0 (6.0); 0x98 |
PVOID WmdTestResult; |
6.0 to 6.1 |
0x6C (6.0); 0x64 |
0xA8 (6.0); 0xA0 |
GUID BootIdentifier; |
6.0 to 6.1 |
0x74 | 0xB0 |
ULONG ResumePages; |
6.1 only |
0x78 | 0xB8 |
PVOID DumpHeader; |
6.1 only |
0x7C | 0xC0 |
PVOID BgContext; |
6.1 only |
0x80 | 0xC8 |
PVOID NumaLocalityInfo; |
6.1 only |
0x84 | 0xD0 |
PVOID NumaGroupAssignment; |
6.1 only |
0x88 | 0xD8 |
LIST_ENTRY AttachedHives; |
6.1 only |
0x90 | 0xE8 |
ULONG MemoryCachingRequirementsCount; |
6.1 only |
0x94 | 0xF0 |
PVOID MemoryCachingRequirements; |
6.1 only |
0x98 | 0xF8 |
TPM_BOOT_ENTROPY_LDR_RESULT TpmBootEntropyResult; |
6.1 only |
0xE0 | 0x0140 |
ULONGLONG ProcessorCounterFrequency; |
6.1 only |
Especially notable above is that Windows 7 does away with the MajorVersion and MinorVersion (and LoaderPagesSpanned disappears with version 6.2).