Geoff Chappell, Software Analyst
The MMPAGING_FILE structure either holds or points the way to pretty much everything that the kernel’s Memory Manager tracks about a paging file.
As an internal structure, the MMPAGING_FILE varies between versions, but far less than do many others and apparently never between builds of the one version. The changing size gives a rough guide to the variability:
Version | Size (x86) | Size (x64) |
---|---|---|
3.51 to 5.0 | 0x40 | |
5.1 | 0x44 | |
5.2 | 0x3C | 0x78 |
6.0 | 0x50 | 0xA0 |
6.1 | 0x50 | 0x90 |
6.2 | 0x64 | 0xA8 |
6.3 | 0x80 | 0xE0 |
10.0 | 0x90 | 0x0100 |
These sizes, and the offsets, types and names in the tables that follow, are from Microsoft’s symbol files for the kernel starting with Windows 2000 SP3. Since symbol files for earlier versions do not contain type information for the MMPAGING_FILE, what’s known for them is instead inferred from what use the kernel is seen to make of the MMPAGING_FILE. Sizes are relatively straightforward, even without symbol files, but Microsoft’s names and types for all the members in these early versions can be something of a guess.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x00 | 0x00 |
ULONG_PTR Size; |
3.51 and higher | |
0x04 | 0x08 |
ULONG_PTR MaximumSize; |
3.51 and higher | |
0x08 | 0x10 |
ULONG_PTR MinimumSize; |
3.51 and higher | |
0x0C | 0x18 |
ULONG_PTR FreeSpace; |
3.51 and higher | |
0x10 (3.51 to 5.2) | 0x20 (5.2) |
ULONG CurrentUsage; |
3.51 to 5.2 | |
0x14 (3.51 to 5.2); 0x10 |
0x28 (5.2); 0x20 |
ULONG_PTR PeakUsage; |
3.51 and higher | |
0x18 (3.51 to 5.1) |
ULONG Hint; |
3.51 to 5.1 | ||
0x1C (3.51 to 5.1); 0x18 (5.2); 0x14 |
0x30 (5.2); 0x28 |
ULONG_PTR HighestPage; |
3.51 and higher | |
0x18 | 0x30 |
ULONG_PTR FreeReservationSpace; |
6.2 and higher | |
0x1C | 0x38 |
ULONG_PTR LargestReserveCluster; |
6.2 and higher | |
0x1C (5.2); 0x18 (6.0 to 6.1); 0x20 |
0x38 (5.2); 0x30 (6.0 to 6.1); 0x40 |
FILE_OBJECT *File; |
5.2 and higher | previously at 0x2C |
0x20 (3.51 to 5.2); 0x1C (6.0 to 6.1); 0x24 |
0x40 (5.2); 0x38 (6.0 to 6.1); 0x48 |
MMMOD_WRITER_MDL_ENTRY *Entry [2]; |
3.51 and higher | |
0x28 (3.51 to 5.1) |
RTL_BITMAP *Bitmap; |
3.51 to 5.1 | next at 0x30 | |
0x2C (3.51 to 5.1) |
FILE_OBJECT *File; |
3.51 to 5.1 | next at 0x1C | |
0x30 (3.51 to 4.0) |
ULONG PageFileNumber; |
3.51 to 4.0 | next at 0x38 | |
0x30 | 0x60 |
SLIST_HEADER PfnsToFree; |
6.3 and higher | |
0x34 (3.51 to 4.0); 0x30 (5.0 to 5.1); 0x28 (5.2); 0x24 (6.0 to 6.1); 0x2C (6.2); 0x38 |
0x50 (5.2); 0x48 (6.0 to 6.1); 0x58 (6.2); 0x70 |
UNICODE_STRING PageFileName; |
5.0 and higher | |
0x30 (5.2); 0x2C (6.0 to 6.1) |
0x60 (5.2); 0x58 (6.0 to 6.1) |
RTL_BITMAP *Bitmap; |
5.2 to 6.1 | previously at 0x28 |
0x30 (6.1) | 0x60 (6.1) |
RTL_BITMAP *EvictStoreBitmap; |
6.1 only | |
0x34 (6.2); 0x40 |
0x68 (6.2); 0x80 |
MI_PAGING_FILE_SPACE_BITMAPS *Bitmaps; |
6.2 and higher | |
0x30 (6.0); 0x34 (6.1); 0x38 (6.2); 0x44 |
0x60 (6.0); 0x68 (6.1); 0x70 (6.2); 0x88 |
ULONG BitmapHint; |
6.0 to 6.1 | |
ULONG AllocationBitmapHint; |
6.2 and higher | |||
0x3C (6.2); 0x48 |
0x74 (6.2); 0x8C |
ULONG ReservationBitmapHint; |
6.2 and higher | |
0x34 (6.0); 0x38 (6.1) |
0x64 (6.0); 0x6C (6.1) |
ULONG LastAllocationSize; |
6.0 to 6.1 | |
0x40 (6.2); 0x4C |
0x78 (6.2); 0x90 |
ULONG LargestNonReservedClusterSize; |
6.2 and higher | |
0x44 (6.2); 0x50 |
0x7C (6.2); 0x94 |
ULONG RefreshClusterSize; |
6.2 and higher | |
0x48 (6.2); 0x54 |
0x80 (6.2); 0x98 |
ULONG LastRefreshClusterSize; |
6.2 and higher | |
0x4C (6.2); 0x58 |
0x84 (6.2); 0x9C |
ULONG ReservedClusterSizeAggregate; |
6.2 and higher | |
0x3C (6.1); 0x50 (6.2); 0x5C |
0x70 (6.1); 0x88 (6.2); 0xA0 |
ULONG ToBeEvictedCount; |
6.1 to 6.3 | |
union { ULONG ToBeEvictedCount; ULONG HybridPriority; }; |
10.0 and higher | |||
0x60 (6.3) | 0xA4 (6.3) |
ULONG HybridPriority; |
6.3 only | |
0x38 (5.0 to 5.1); 0x34 (5.2); 0x38 (6.0); 0x40 (6.1); 0x54 (6.2); 0x64 (6.3); 0x60 |
ULONG PageFileNumber; |
5.0 to 5.1 | previously at 0x30; next as bit field |
|
0x68 (5.2); 0x68 (6.0); 0x74 (6.1); 0x8C (6.2); 0xA8 (6.3); 0xA4 |
/* ULONG bit fields, see below */ |
5.2 only | ||
/* USHORT bit fields, see below */ |
6.0 and higher | |||
0x3A (6.0); 0x42 (6.1); 0x56 (6.2); 0x66 (6.3); 0x62 |
0x6A (6.0); 0x76 (6.1); 0x8E (6.2); 0xAA (6.3); 0xA6 |
struct { USHORT AdriftMdls : 1; USHORT Spare1 : 15; }; |
6.0 to 6.1 | |
struct { UCHAR AdriftMdls : 1; UCHAR Spare1 : 7; }; |
6.2 and higher | |||
0x57 (6.2); 0x67 (6.3); 0x63 |
0x8F (6.2); 0xAB (6.3); 0xA7 |
UCHAR Spare2 : 8; |
6.2 and higher | |
0x3C (3.51 to 5.1) |
UCHAR Extended; |
3.51 to 5.1 | ||
0x3D (3.51 to 5.1) |
UCHAR HintSetToZero; |
3.51 to 5.1 | ||
0x3E (5.1) |
BOOLEAN BootPartition; |
5.1 only | next as bit field at 0x34 | |
0x68 (6.3); 0x64 |
0xAC (6.3); 0xA8 |
ULONG PageHashPages; |
6.3 and higher | |
0x6C (6.3); 0x68 |
0xB0 (6.3); 0xAC |
ULONG PageHashPagesPeak; |
6.3 and higher | |
0x70 (6.3); 0x6C |
0xB8 (6.3); 0xB0 |
ULONG *PageHash; |
6.3 and higher | |
0x40 (5.1); 0x38 (5.2); 0x3C (6.0); 0x44 (6.1); 0x58 (6.2); 0x74 (6.3); 0x70 |
0x70 (5.2 to 6.0); 0x78 (6.1); 0x90 (6.2); 0xC0 (6.3); 0xB8 |
HANDLE FileHandle; |
5.1 and higher | |
0x40 (6.0) | 0x80 (6.0) |
SLIST_HEADER AvailableList; |
6.0 only | |
0x48 (6.0) | 0x90 (6.0) |
SLIST_HEADER NeedProcessingList; |
6.0 only | |
0x48 (6.1); 0x5C (6.2); 0x78 (6.3); 0x74 |
0x80 (6.1); 0x98 (6.2); 0xC8 (6.3); 0xC0 |
KSPIN_LOCK Lock; |
6.1 and higher | |
0x4C (6.1); 0x60 (6.2); 0x7C (6.3); 0x78 |
0x88 (6.1); 0xA0 (6.2); 0xD0 (6.3); 0xC8 |
ETHREAD *LockOwner; |
6.1 and higher | |
0x7C | 0xD0 |
RTL_AVL_TREE FlowThroughReadRoot; |
10.0 and higher | |
0x80 | 0xD8 |
MI_PARTITION *Partition; |
10.0 and higher | |
0x84 | 0xE0 |
RTL_BALANCED_NODE FileObjectNode; |
10.0 and higher |
The MMPAGING_FILE is in non-paged pool, of course—and, starting with version 6.2, in non-paged no-execute pool. So too are various helper structures, e.g., those for the Entry array and the various bitmaps. The paging file’s name, however, is not accessed during paging I/O. It is kept just for information. The Buffer in PageFileName is in paged pool. Moreover, it just records what filename was given to the NtCreatePagingFile that created this MMPAGING_FILE. This filename need not still be valid when inspected later.
Even now that Windows 10 has an array of MMPAGING_FILE pointers for each memory partition, each array still has the age-old capacity of 0x10. To allow 32 bits for the PageFileNumber, which indexes the array, always was excessive and the opportunity was eventually taken to make bit fields of both it and the boolean BootPartition.
Mask | Definition | Versions | Remarks |
---|---|---|---|
0x000F |
ULONG PageFileNumber : 4; |
5.2 only | previously ULONG at 0x38 |
USHORT PageFileNumber : 4; |
6.0 and higher | ||
0x00F0 |
ULONG ReferenceCount : 4; |
5.2 only | |
0x0100 (5.2); 0x0010 (6.0 to 6.3) |
ULONG BootPartition : 1; |
5.2 only | previously BOOLEAN at 0x3E |
USHORT BootPartition : 1; |
6.0 to 6.3 | ||
0x0020 (6.2 to 6.3); 0x0010 |
USHORT WsSwapPagefile : 1; |
6.2 and higher | |
0x0040 (6.2 to 6.3); 0x0020 |
USHORT NoReservations : 1; |
6.2 and higher | |
0x0040 |
USHORT VirtualStorePagefile : 1; |
10.0 and higher | |
0x0080 |
USHORT SwapSupported : 1; |
10.0 and higher | |
0x0100 |
USHORT NodeInserted : 1; |
10.0 and higher | |
0x0200 |
USHORT StackNotified : 1; |
10.0 and higher | |
ULONG Reserved : 23; |
5.2 only | ||
USHORT Spare0 : 11; |
6.0 to 6.1 | ||
USHORT Spare0 : 9; |
6.2 to 6.3 | ||
USHORT Spare0 : 5; |
10.0 and higher |