# Retrieving MmPhysicalMemoryBlock regardless of the NT version

URL: https://www.msuiche.com/posts/retrieving-mmphysicalmemoryblock-regardless-of-the-nt-version/
Date: 2008-09-17
Author: Matt Suiche
Tags: dfir


---


Here is a method I’m using in the next version of Win32DD (1.2), to retrieve MmPhysicalMemoryBlock regardless of the NT Version. The main problem with `KDDEBUGGER_DATA64` structure is the version dependency. Then, we have to rebuild this field by ourselves.
To retrieve physical memory runs, I’m using `MmGetPhysicalMemoryRanges()` *undocumented* function. This function usage had been documented by Mark Russinovich in 1999, in the [Volume 1 Number 5 edition of the Sysinternals Newsletter](https://archive.is/o/E0vgN/blogs.technet.com/sysinternals/archive/1999/10/20/452896.aspx).

Actually, this function is defined in DDK. Even if, MSDN [says](https://archive.is/o/E0vgN/msdn.microsoft.com/en-us/library/ms801987.aspx):
> The following routines are reserved for system use. Do not use them in your driver.

```cpp
#if (NTDDI_VERSION >= NTDDI_WIN2K)
NTKERNELAPI
PPHYSICAL_MEMORY_RANGE
MmGetPhysicalMemoryRanges (
    VOID
    );
#endif
```

`MmPhysicalMemoryBlock` is a structure that provides information regarding the physical memory ranges used by the system and also total physical memory size. These uses motivated me to write `MmGetPhysicalMemoryBlock()`.
```cpp
[..]]
    // NT 5.1 Addition
    ULONG64   MmPhysicalMemoryBlock;
[..]
```
As we can read in the `KDDEBUGGER_DATA64` definition, `MmPhysicalMemoryBlock` field is an NT 5.1 Addition.
## definition.
```cpp
typedef struct _PHYSICAL_MEMORY_RUN {
    PFN_NUMBER BasePage;
    PFN_NUMBER PageCount;
} PHYSICAL_MEMORY_RUN, *PPHYSICAL_MEMORY_RUN;
 
typedef struct _PHYSICAL_MEMORY_DESCRIPTOR {
    ULONG NumberOfRuns;
    PFN_NUMBER NumberOfPages; // NumberOfPages * PAGE_SIZE is physical memory size.
    PHYSICAL_MEMORY_RUN Run[1]; // NumberOfRuns is the total entries.
} PHYSICAL_MEMORY_DESCRIPTOR, *PPHYSICAL_MEMORY_DESCRIPTOR;
 
PPHYSICAL_MEMORY_DESCRIPTOR
MmGetPhysicalMemoryBlock(
        VOID
);
```

## code.

```cpp
/*++
Function Name: MmGetPhysicalMemoryBlock
 
Overview:
        – This function aims at retrieving MmPhysicalMemoryBlock, regardless
        of the host version.
 
        The caller has to free the memory block.
 
Parameters:
        –
 
Environment:
        – Kernel Mode. PASSIVE_LEVEL.
 
Return Values:
        – PPHYSICAL_MEMORY_DESCRIPTOR
–*/
PPHYSICAL_MEMORY_DESCRIPTOR
MmGetPhysicalMemoryBlock(VOID
                         )
{
PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
PPHYSICAL_MEMORY_RANGE MmPhysicalMemoryRange;
ULONG MemoryBlockSize;
PFN_NUMBER NumberOfPages;
ULONG NumberOfRuns;
ULONG Run;
 
    //
    // PHYSICAL_MEMORY_DESCRIPTOR isn’t exported into KDDEBUGGER_DATA64
    // NT 5.0 and below. But MmGetPhysicalMemoryRanges() computes
    // PHYSICAL_MEMORY_RANGE with PHYSICAL_MEMORY_DESCRIPTOR. Then,
    // We can easily rewrite PHYSICAL_MEMORY_DESCRIPTOR.
    //
    MmPhysicalMemoryRange = MmGetPhysicalMemoryRanges();
 
    //
    // Invalid ?
    //
    if (MmPhysicalMemoryRange == NULL) return NULL;
 
    //
    // Compute the number of runs and the number of pages
    //
    NumberOfRuns = 0;
    NumberOfPages = 0;
    while ((MmPhysicalMemoryRange[NumberOfRuns].BaseAddress.QuadPart != 0) &&
           (MmPhysicalMemoryRange[NumberOfRuns].NumberOfBytes.QuadPart != 0))
    {
        NumberOfRuns++;
        NumberOfPages += (PFN_NUMBER)BYTES_TO_PAGES(
            MmPhysicalMemoryRange[NumberOfRuns].NumberOfBytes.QuadPart);
    }
 
    //
    // Invalid ?
    //
    if (NumberOfRuns == 0) return NULL;
 
    //
    // Compute the size of the pool to allocate and then allocate
    //
    MemoryBlockSize = sizeof(ULONG) +
        sizeof(PFN_NUMBER) +
        sizeof(PHYSICAL_MEMORY_RUN) * NumberOfRuns;
 
    MmPhysicalMemoryBlock = ExAllocatePoolWithTag(NonPagedPool,
                                                  MemoryBlockSize,
                                                  ‘  mM’);
 
    //
    // Define PHYSICAL_MEMORY_DESCRIPTOR Header.=
    //
    MmPhysicalMemoryBlock->NumberOfRuns = NumberOfRuns;
    MmPhysicalMemoryBlock->NumberOfPages = NumberOfPages;
 
    for (Run = 0; Run < NumberOfRuns; Run++)
    {
        //
        // BasePage
        //
        MmPhysicalMemoryBlock->Run[Run].BasePage =
            (PFN_NUMBER)MI_CONVERT_PHYSICAL_TO_PFN(
            MmPhysicalMemoryRange[NumberOfRuns].BaseAddress.QuadPart
 
            );
 
        //
        // PageCount
        //
        MmPhysicalMemoryBlock->Run[Run].PageCount =
            (PFN_NUMBER)BYTES_TO_PAGES(
            MmPhysicalMemoryRange[Run].NumberOfBytes.QuadPart
            );
    }
 
    return MmPhysicalMemoryBlock;
}
```
