'windbg kernel debugging - How to get the physical address
I have a module loaded at fffff801`16e00000 and want to get its physical address via !pte but windbg is saying "Levels not implemented for this platform", what gives?
I know how to do i manually by walknig the PML4, PDPT, PD and PT but why isn't this extension working? I'm kernel debugging a virtual machine
Solution 1:[1]
I had the same problem multiple times, and I could not figure it out. I don’t know if this will help you, but I made a WinDbg JS script to reproduce the !pte command for this specific case.
It works on 64 bits and only with 4 layer paging.
"use strict";
const system = x => host.namespace.Debugger.Utility.Control.ExecuteCommand(x);
const log = x => host.diagnostics.debugLog(`${x}\n`);
const convertStrToInt64 = str => host.parseInt64(str);
const replaceString = (string, search, replaceWith) => {
return string.split(search).join(replaceWith);
}
function isBitSet(Nr, Bit)
{
var mask = host.Int64(1).bitwiseShiftLeft(Bit);
return Nr.bitwiseAnd(mask).compareTo(0);
}
class PageEntry
{
constructor(Value)
{
this.present = isBitSet(Value, 0);
this.write = isBitSet(Value, 1);
this.supervisor = isBitSet(Value, 2);
this.access = isBitSet(Value, 5);
this.dirty = isBitSet(Value, 6);
this.largePage = isBitSet(Value, 7);
this.exec = isBitSet(Value, 63) == true ? 0 : 1;
this.value = Value;
var mask = host.Int64(1);
mask = mask.bitwiseShiftLeft(36).subtract(1)
this.pfn = Value.bitwiseShiftRight(12).bitwiseAnd(mask)
}
toString() {
var str = "";
str += "Value = " + this.value.toString() + "\n\t";
str += "P(" + this.present + "), ";
str += "W(" + this.write + "), ";
str += "E(" + this.exec + "), ";
str += "A(" + this.access + "), ";
str += "D(" + this.access + "), ";
str += "Large(" + this.largePage + ")\n\t";
str += "Pfn: " + this.pfn.toString();
return str;
}
}
function getLayerOffset(Adr, Layer)
{
var shift = 0;
switch (Layer)
{
case 4:
shift = 39;
break;
case 3:
shift = 30;
break;
case 2:
shift = 21;
break;
case 1:
shift = 12;
break;
default:
throw EvalError("Invalid layer");
}
return Adr.bitwiseShiftRight(shift).bitwiseAnd(0x1ff);
}
function paFromPfn(Pfn)
{
return Pfn.bitwiseShiftLeft(12)
}
function readDword64FromPa(PhysicalAddress)
{
var out = system("!dq " + PhysicalAddress.toString() + " L1")[0];
// output example: #1234abc 12341234`abcdabcd
// !sometimes the output from !dq has a space after #
out = out.split(" ");
var value = out[out.length - 1]
return convertStrToInt64("0x" + value);
}
function pageWalk(TablePa, Offset, Level)
{
if (Level == 0)
{
return;
}
var entryAdr = TablePa.add(Offset[Level-1].multiply(8));
var entryValue = readDword64FromPa(entryAdr);
var entry = new PageEntry(entryValue);
var nextLayerPa = paFromPfn(entry.pfn)
// print info
log("Level: " + Level.toString() + ", Entry Address: " + entryAdr.toString())
log(entry)
log("")
if (entry.present == 0)
{
log("Next layer not present");
return;
}
if (entry.largePage == 1)
{
log("Large page present");
return;
}
pageWalk(nextLayerPa, Offset, Level-1)
}
function getPml4AddressFromCr3(Cr3)
{
var mask = host.Int64(1);
var mask = mask.bitwiseShiftLeft(36).subtract(1)
var pml4Pfn = Cr3.bitwiseShiftRight(12).bitwiseAnd(mask)
return paFromPfn(pml4Pfn);
}
function translateAddress(VirtualAddress, Cr3Val=NaN)
{
log("Virtual address: " + VirtualAddress.toString())
var lv4 = getLayerOffset(VirtualAddress, 4);
var lv3 = getLayerOffset(VirtualAddress, 3);
var lv2 = getLayerOffset(VirtualAddress, 2);
var lv1 = getLayerOffset(VirtualAddress, 1);
if (isNaN(Cr3Val))
{
Cr3Val = host.currentThread.Registers.Kernel.cr3;
}
var pml4Adr = getPml4AddressFromCr3(Cr3Val);
log("Pml 4 address: " + pml4Adr.toString())
pageWalk(pml4Adr, [lv1, lv2, lv3, lv4], 4)
}
function initializeScript()
{
var app = [new host.apiVersionSupport(1, 7)];
app.push(new host.functionAlias(translateAddress, "pteV2"));
return app;
}
function invokeScript()
{
}
To use the script you run .scriptload script.js, then you can use the !pteV2(Virtual_Address) or !pteV2(Virtual_Address, Cr3_Value) instead of !pte.
I don’t have experience with js and the script is not well tested…
The script is on github too.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
