Skip to content

Instantly share code, notes, and snippets.

@markhc
Created September 25, 2019 01:36
Show Gist options
  • Save markhc/511a6753e35e326b96c3dfaf445667c8 to your computer and use it in GitHub Desktop.
Save markhc/511a6753e35e326b96c3dfaf445667c8 to your computer and use it in GitHub Desktop.
///
/// directoryTableBase is the CR3 register value for the target process (the process that owns virtualAddress)
/// virtualAddress is the address to translate
///
std::uint64_t driver::translate_linear_address(std::uint64_t directoryTableBase, LPVOID virtualAddress)
{
auto va = (std::uint64_t)virtualAddress;
auto PML4 = (USHORT)((va >> 39) & 0x1FF); //<! PML4 Entry Index
auto DirectoryPtr = (USHORT)((va >> 30) & 0x1FF); //<! Page-Directory-Pointer Table Index
auto Directory = (USHORT)((va >> 21) & 0x1FF); //<! Page Directory Table Index
auto Table = (USHORT)((va >> 12) & 0x1FF); //<! Page Table Index
//
// Read the PML4 Entry. DirectoryTableBase has the base address of the table.
// It can be read from the CR3 register or from the kernel process object.
//
auto PML4E = read_physical_address<std::uint64_t>(directoryTableBase + PML4 * sizeof(ULONGLONG));
if(PML4E == 0)
return 0;
//
// The PML4E that we read is the base address of the next table on the chain,
// the Page-Directory-Pointer Table.
//
auto PDPTE = read_physical_address<std::uint64_t>((PML4E & 0xFFFFFFFFFF000) + DirectoryPtr * sizeof(ULONGLONG));
if(PDPTE == 0)
return 0;
//Check the PS bit
if((PDPTE & (1 << 7)) != 0) {
// If the PDPTE’s PS flag is 1, the PDPTE maps a 1-GByte page. The
// final physical address is computed as follows:
// — Bits 51:30 are from the PDPTE.
// — Bits 29:0 are from the original va address.
return (PDPTE & 0xFFFFFC0000000) + (va & 0x3FFFFFFF);
}
//
// PS bit was 0. That means that the PDPTE references the next table
// on the chain, the Page Directory Table. Read it.
//
auto PDE = read_physical_address<std::uint64_t>((PDPTE & 0xFFFFFFFFFF000) + Directory * sizeof(ULONGLONG));
if(PDE == 0)
return 0;
if((PDE & (1 << 7)) != 0) {
// If the PDE’s PS flag is 1, the PDE maps a 2-MByte page. The
// final physical address is computed as follows:
// — Bits 51:21 are from the PDE.
// — Bits 20:0 are from the original va address.
return (PDE & 0xFFFFFFFE00000) + (va & 0x1FFFFF);
}
//
// PS bit was 0. That means that the PDE references a Page Table.
//
auto PTE = read_physical_address<std::uint64_t>((PDE & 0xFFFFFFFFFF000) + Table * sizeof(ULONGLONG));
if(PTE == 0)
return 0;
//
// The PTE maps a 4-KByte page. The
// final physical address is computed as follows:
// — Bits 51:12 are from the PTE.
// — Bits 11:0 are from the original va address.
return (PTE & 0xFFFFFFFFFF000) + (va & 0xFFF);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment