!pte (display page-level address and entries)
Description of the '!pte' command in HyperDbg.

Command

!pte

Syntax

!pte [VirtualAddress (hex)] [pid ProcessId (hex)]

Description

Displays the PML4E, PDPTE, PDE, PTE for the specified address.

Parameters

[VirtualAddress (hex)]
The virtual address of where we want to read its page-level entries.
[pid ProcessId (hex)] (optional)
The Process Id of where you want to convert the address based on it.
If you don't specify the pid, then the default pid is the current process (HyperDbg) process layout of memory.
In the Debugger Mode, the pid (parameter) is ignored. If you want to view another process memory, use the '.process' command to switch to another process memory layout.

Examples

The following command shows the page-level entries nt!ExAllocatePoolWithTag.
1
HyperDbg> !pte nt!ExAllocatePoolWithTag
2
VA fffff801639b1030
3
PML4E (PXE) at ffffeaf57abd5f80 contains 0000000005109063
4
PDPT (PPE) at ffffeaf57abf0028 contains 000000000510a063
5
PDE at ffffeaf57e0058e0 contains 0a000000034000a1
6
PDE is a large page, so it doesn't have a PTE
Copied!
The following command shows the page-level entries nt!ExAllocatePoolWithTag+5.
1
HyperDbg> !pte nt!ExAllocatePoolWithTag+5
2
VA fffff801639b1035
3
PML4E (PXE) at ffffeaf57abd5f80 contains 0000000005109063
4
PDPT (PPE) at ffffeaf57abf0028 contains 000000000510a063
5
PDE at ffffeaf57e0058e0 contains 0a000000034000a1
6
PDE is a large page, so it doesn't have a PTE
Copied!
The following command shows the page-level entries fffff80040f00c28.
1
HyperDbg> !pte fffff80040f00c28
2
VA fffff80040f00c28
3
PML4E (PXE) at ffff83c1e0f07f80 contains 0000000004108063
4
PDPT (PPE) at ffff83c1e0ff0008 contains 000000000411c063
5
PDE at ffff83c1fe001038 contains 0000000004124063
6
PTE at ffff83fc00207800 contains 8900000006470863
Copied!
The following command shows the page-level entries fffff8003ad6f010. Note that some entries might have a large PDE and no PTE.
1
HyperDbg> !pte fffff8003ad6f010
2
VA fffff8003ad6f010
3
PML4E (PXE) at ffff83c1e0f07f80 contains 0000000004108063
4
PDPT (PPE) at ffff83c1e0ff0000 contains 0000000004109063
5
PDE at ffff83c1fe000eb0 contains 00000000028008e3
6
PDE is a large page, so it doesn't have a PTE
Copied!

IOCTL

This function works by calling DeviceIoControl with IOCTL = IOCTL_DEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS, you have to send it in the following structure.
1
typedef struct _DEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS
2
{
3
UINT64 VirtualAddress;
4
UINT32 ProcessId;
5
6
UINT64 Pml4eVirtualAddress;
7
UINT64 Pml4eValue;
8
9
UINT64 PdpteVirtualAddress;
10
UINT64 PdpteValue;
11
12
UINT64 PdeVirtualAddress;
13
UINT64 PdeValue;
14
15
UINT64 PteVirtualAddress;
16
UINT64 PteValue;
17
18
UINT32 KernelStatus;
19
20
} DEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS,
21
*PDEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS;
Copied!
You should only fill the VirtualAddress of the above structure when the IOCTL returns from the kernel, other parts of this structure are filled with valid entry virtual addresses and the entry value itself.
If you want to convert based on another process memory layout, then put its process ID. Otherwise, put the current process id on it. ProcessId is ignored in debugger mode.
You can map the value to each entry's structure (Look at Intel SDM for more information).
Also, the structures are available in MemoryMapper.h but they might be outdated.

Remarks

If the VirtualAddress and Value of entry for PDE and PTE from the kernel IOCTL are the same, the entry has a LARGE PDE and doesn't have PTE.
This command is guaranteed to keep debuggee in a halt state (in Debugger Mode); thus, nothing will change during its execution.

Requirements

None
None