Created
September 25, 2019 01:36
-
-
Save markhc/511a6753e35e326b96c3dfaf445667c8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// | |
/// 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