Geoff Chappell - Software Analyst
The MEMORY_ALLOCATION_DESCRIPTOR structure (formally _MEMORY_ALLOCATION_DESCRIPTOR) is how the loader describes to the kernel what memory has been found and which of it is already in use for what purpose.
There is one structure for each memory block. The structures are provided by the loader to the kernel as a double-linked list, linked through the ListEntry member. The head is the MemoryDescriptorListHead member of the LOADER_PARAMETER_BLOCK structure whose address the loader passes to the kernel as the latter’s one argument for initialisation. Until the kernel completes its initialisation, it keeps the address in the exported KeLoaderBlock variable, which means the whole list of memory blocks can be easily inspected not just with a debugger but by device drivers.
The MEMORY_ALLOCATION_DESCRIPTOR and its relationship to the LOADER_PARAMETER_BLOCK are ancient, being already well established for Windows NT 3.1.
Microsoft is not known ever to have documented the MEMORY_ALLOCATION_DESCRIPTOR. For many years, it was known from Microsoft only through type information in public symbol files for the kernel. Even this started only as recently as Windows Vista. After roughly another decade, Microsoft published a C-language definition. This is in a header named ARC.H which Microsoft distributed with the Windows Driver Kit (WDK) for Windows 10 in its original and Version 1511 editions. This disclosure was very likely a mistake. The header is in a subdirectory, named “minwin”, of a directory named “um” as if for user-mode programming even though many of the headers in the subdirectory define types that no user-mode software has any access to. Oversight or not, the header was gone from the WDK for Version 1607.
Though the MEMORY_ALLOCATION_DESCRIPTOR structure is undocumented, it is stable up to and including Windows Vista. In 32-bit builds, it is stable even to Windows 10. In 64-bit builds, however, Windows 7 supports physical memory above 16TB, i.e., physical page numbers that are too wide for 32 bits, and therefore widens two members. The size of a MEMORY_ALLOCATION_DESCRIPTOR is 0x14 bytes in 32-bit builds and either 0x20 or 0x28 bytes in 64-bit builds depending on the version.
Names, types and offsets given below are from Microsoft’s symbol files for the kernel, starting with Windows Vista. What’s known for earlier versions comes from inspecting the binaries for continuity with the later versions.
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x00 | 0x00 |
LIST_ENTRY ListEntry; |
all |
0x08 | 0x10 |
TYPE_OF_MEMORY MemoryType; |
all |
0x0C | 0x14 |
ULONG BasePage; |
3.10 to 6.1 |
0x18 |
ULONG_PTR BasePage; |
6.1 and higher | |
0x10 | 0x18 |
ULONG PageCount; |
3.10 to 6.1 |
0x20 |
ULONG_PTR PageCount; |
6.1 and higher |
What the descriptor describes is physical memory. The BasePage would be appropriatedly defined as a PFN_NUMBER. The PageCount might be defined as a PFN_NUMBER too. The (briefly) published C-language definition, however, confirms that Microsoft defines both as ULONG_PTR.