Virtual Address(VA)
to its corresponding Physical Address(PA)
.Virtual Memory
which is mapped to Physical Memory
by the Memory Management Unit(MMU)
.PA
is the actual address of a memory cell in the physical RAM chip.MMU
is responsible for walking the page tables and translating a VA
(used by the CPU
) to its mapped PA
.4 kB(Normal Page)
, 2 MB(Large Page)
or 1 GB(Huge Page)
.Virtual Address Space(VAS)
is simply a software's view of memory. It is divided into 2 categories: User Virtual Address Space(User VAS)
- This VAS
is private and available per-process ergo all addresses in User VAS
are relative to the process. Kernel Virtual Address Space(Kernel VAS)
- This VAS
is shared between all processes(except PTE
and Session Space
) albeit it is not accessible from Ring-3/User-Mode
.VAS
of 2 ^ 64 = 16 EB
but due to current hardware limitations, Physical Addresses
are limited to 48 bits
. It is for this reason, a Canonical Address
had to be adopted where only 48 bits
of a VA
are used and the rest of the bits(48 - 63
) are sign-extended(more on this later).VAS
= 2 ^ 48 = 256 TB
which is divided equally among User VAS
and Kernel VAS
equal to 128 TB
.Physical Memory/RAM
= 256 TB
4-level paging
. The four paging structures(from highest to lowest respectively) are: Page Map Level 4(PML4)
Page Directory Pointer Table(PDPT)
Page Directory Table(PDT)
Page Table(PT)
512
entries(PxE
) each of size 8 bytes
and they are called: PML4E/PXE(In WinDBG)
, PDPE/PPE(In WinDbg)
, PDE
and PTE
respectively.nt!_MMPTE_HARDWARE
.Valid or P bit
- Must be set to 1
for the page table entry to be considered valid(entry may be used for address translation/page is present in RAM
)Owner or U/S bit
- If set to 1 or U
, it is a User-Mode page and if set to 0 or S
, it is a Supervisor/Kernel-Mode page LargePage or L bit
- If set to 1
, it is a Large Page(2 MB
) Write or R/W bit
- If set to 1 or W
, writing to page is enabled and if set to 0 or R
, it is a read-only page NoExecute or E bit
- If set to 1
, code cannot be executed on the pagePxE
which we haven't discussed yet i.e. Page Frame Number(PFN)
. PFN
denotes the PA
of the base of the next paging structure. I assure you that we will come back to this later when we do the page walk.VA
.VA
into various parts:VA
(from high to low) are: Sign Extend
- Bits 48 to 63 = 16 bits
for sign extension PML4 Offset
- Bits 39 to 47 = 9 bits
index into the PML4
paging structure PDPT Offset
- Bits 30 to 38 = 9 bits
index into the PDPT
paging structurePDP Offset
- Bits 21 to 29 = 9 bits
index into the PDT
paging structurePT Offset
- Bits 12 to 20 = 9 bits
index into the PT
paging structurePhysical Page Offset
- Bits 0 to 11 = 12 bits
index into the physical pageSign Extend
bits are used to represent a Canonical Address
which implies for User VAS
, Virtual Addresses
are sign-extended with 0
while for Kernel VAS
, Virtual Addresses
are sign-extended with 1
.Physical Page Offset
denotes the particular byte within the physical page determined by the PTE
.VA
:Physical Page Offset(lower 12 bits)
remains the same on both VA
and its corresponding PA
.VA
is actually a fusion of a Segment Number
and the Linear Address
as already discussed. However, Segmentation
is not relevant for address translation ergo we will not discuss it here.DirectoryTableBase(DTB)/DirBase(in WinDbg)
in _nt!_KPROCESS
(Kernel process object) structure that contains the PA
of the highest-level paging structure i.e. PML4
in x64 paging. This value is moved into the CR3
register every time a process context switch is made by the processor and it is from this privileged control register that the address translation begins.MMU
retrieves the PA
of the PML4
table base, it then selects a particular entry from the PML4
table based on the index given by the VA
.PFN
(already discussed before) which points to the starting PA
of the next paging structure i.e. PDPT
and this process is repeated for the remaining paging structures until we get to the PTE
which denotes the base address of a page in physical memory and it is then added with the Physical Page Offset
to get the actual PA
mapped by the VA
.PTE
maps 512 * 8 = 4 kB
of Physical Memory
, a PDE
can address 512 * 512 * 8 = 2 MB
of Physical Memory
, a PDPE
can address 512 * 512 * 512 = 1 GB
of Physical Memory
and finally a PML4E
can address up to 512 * 512 * 512 * 512 * 8 ~ 512 GB
of Physical Memory
.PDE
maps a Large Page/2 MB of contiguous physical memory
instead of pointing to a PT
(more on this later).VA
to PA
and ergo derive an arbitrary Ring 0/Kernel-Mode
virtual memory read/write primitive since we deal exclusively with VAs
and not PAs
.VA
to its mapped PA
using WinDbg
we have two methods. One of them is automatic and the other is semi-automatic. We will look at both of them in this section and lastly we'll also look at a completely manual address translation which shall come to use later when we discuss the code.kd
or lkd
. Both of them should work equally well for this purpose.VA
to PA
:<DTB>
is the Directory Table Base/DirBase
and <VA>
denotes the Virtual Address
we are interested in translating.VA
must be properly formatted(without ` symbol) for this command to work successfully. Also, this command does not need a process context switch.WinDbg
command for walking page tables:Page Frame Number
, multiply it with 0x1000
and finally add the offset from the base of the PFN
to get the PA
.VA
of the entries which are available using this command.!pte
uses the currently selected process's DirBase
as the base PA
of the PML4
table and walk the page tables.WinDbg
commands to walk the page tables for us but once again we might not have that luxury in a real-world scenario. This means that we must rely on our knowledge of address translation and manually walk the page tables. With that in mind, let's get initiated.Kernel DTB
or the PA
of the PML4
table base for Kernel since we are interested in the Kernel VAS
(there's already a session where this is discussed in detail):VA
to translate. We will be using nt!KeInsertQueueApc
:VA
to get the PML4
offset:PML4E/PXE
:PA
of the page table entry and then dump physical memory using !dq
.VA
to get the PDPT
offset:PDPE/PPE
:0xFFFFFFFFFF000
is the PA
mask for 4 kB
page.VA
to get the PDT
offset:PDE
:LargePage
bit is set in PDE
using:PA
like so:0xfffffffe00000
is the PA
mask for 2 MB
page and 0x1fffff
is the Physical Page Offset
mask for 2 MB page
.VA
to get the PT
offset:PTE
:VA
to get the Physical Page Offset
:0xFFF
is the Physical Page Offset
mask for 4 kB page
.PA
like so:PA
and VA
dumped by !db
and db
commands respectively.WinDbg
output dump:Large Page
translation:Kernel DTB
.VA
to its corresponding PA
:WinDbg
fu to verify our results):VA
as the one used in the manual address translation using WinDbg
so that we can verify the results.