improved testing / output

pull/3051/head
jxuanli 7 months ago
parent 761df50148
commit d40fa8602f

@ -743,6 +743,12 @@ def paging_enabled() -> bool:
def uses_5lvl_paging() -> bool: def uses_5lvl_paging() -> bool:
if not has_debug_syms():
pages = pwndbg.aglib.vmmap.get()
for page in pages:
if page.start & (1 << 63) > 0:
return page.start < (0xFFF << (4 * 13))
return False
ops = arch_ops() ops = arch_ops()
if ops: if ops:
return ops.uses_5lvl_paging() return ops.uses_5lvl_paging()

@ -10,8 +10,8 @@ from pwndbg.commands import CommandCategory
from pwndbg.lib.regs import BitFlags from pwndbg.lib.regs import BitFlags
parser = argparse.ArgumentParser(description="Performs pagewalk.") parser = argparse.ArgumentParser(description="Performs pagewalk.")
parser.add_argument("vaddr", type=int, help="virtual address to walk") parser.add_argument("vaddr", type=str, help="virtual address to walk")
parser.add_argument("--pgd", dest="entry", type=int, default=None, help="") parser.add_argument("--pgd", dest="entry", type=str, default=None, help="")
pageflags = BitFlags([("NX", 63), ("PS", 7), ("A", 5), ("W", 1), ("P", 0)]) pageflags = BitFlags([("NX", 63), ("PS", 7), ("A", 5), ("W", 1), ("P", 0)])
@ -38,6 +38,7 @@ def pg_indices(vaddr, nr_level):
@pwndbg.commands.OnlyWhenQemuKernel @pwndbg.commands.OnlyWhenQemuKernel
@pwndbg.commands.OnlyWhenPagingEnabled @pwndbg.commands.OnlyWhenPagingEnabled
def pagewalk(vaddr, entry=None): def pagewalk(vaddr, entry=None):
vaddr = int(pwndbg.dbg.selected_frame().evaluate_expression(vaddr))
# https://blog.zolutal.io/understanding-paging/ # https://blog.zolutal.io/understanding-paging/
base = pwndbg.aglib.kernel.physmap_base() base = pwndbg.aglib.kernel.physmap_base()
level = 4 level = 4
@ -61,7 +62,7 @@ def pagewalk(vaddr, entry=None):
if entry is None: if entry is None:
entry = pwndbg.aglib.regs["cr3"] entry = pwndbg.aglib.regs["cr3"]
else: else:
entry = pwndbg.dbg.selected_frame().evaluate_expression(entry) entry = int(pwndbg.dbg.selected_frame().evaluate_expression(entry))
if entry > base: if entry > base:
# user inputted a physmap address as pointer to pgd # user inputted a physmap address as pointer to pgd
entry -= base entry -= base
@ -76,11 +77,11 @@ def pagewalk(vaddr, entry=None):
idx = (vaddr & (0x1FF << shift)) >> shift idx = (vaddr & (0x1FF << shift)) >> shift
entry = 0 entry = 0
try: try:
table = pwndbg.aglib.memory.get_typed_pointer("ulong", cur) table = pwndbg.aglib.memory.get_typed_pointer("unsigned long", cur)
entry = int(table[idx]) entry = int(table[idx])
print_pagetable_entry(names[i], entry, cur) print_pagetable_entry(names[i], entry, cur)
except Exception as e: except Exception as e:
print(M.warn(f"Exception {e} while page walking")) print(M.warn(f"Exception while page walking: {e}"))
entry = 0 entry = 0
if entry == 0: if entry == 0:
print(M.warn("address is not mapped")) print(M.warn("address is not mapped"))

@ -187,18 +187,23 @@ def test_command_pagewalk():
# no kbase? fine # no kbase? fine
pages = pwndbg.aglib.vmmap.get() pages = pwndbg.aglib.vmmap.get()
address = pages[0].start address = pages[0].start
if not pwndbg.aglib.kernel.has_debug_syms():
# even if no debug symbols, still gracefully handle it
res = gdb.execute(f"pagewalk {hex(address)}")
# now let's guess the phymap base and should work as intended
res = gdb.execute("set guess-physmap on")
res = gdb.execute(f"pagewalk {hex(address)}", to_string=True) res = gdb.execute(f"pagewalk {hex(address)}", to_string=True)
assert "PMD" in res # Page Size is only set for PMDe or PTe assert "PMD" in res # Page Size is only set for PMDe or PTe
res = res.splitlines()[-1] res = res.splitlines()[-1]
match = re.find(r"0x[0-9a-fA-F]{16}", res) match = re.findall(r"0x[0-9a-fA-F]{16}", res)[0]
physmap_addr = int(match, 16) physmap_addr = int(match, 16)
# compare the first 0x100 bytes of the page (e.g. first kernel image page) with its physmap conterpart # compare the first 0x100 bytes of the page (e.g. first kernel image page) with its physmap conterpart
expected = pwndbg.aglib.memory.read(address, 0x100) expected = pwndbg.aglib.memory.read(address, 0x100)
actual = pwndbg.aglib.memory.read(physmap_addr, 0x100) actual = pwndbg.aglib.memory.read(physmap_addr, 0x100)
assert all(expected[i] == actual[i] for i in range(0x100)) assert all(expected[i] == actual[i] for i in range(0x100))
# make sure that when using cr3 for pgd, it still works # make sure that when using cr3 for pgd, it still works
res2 = gdb.execute(f"pagewalk {address} --pgd $cr3", to_string=True) res2 = gdb.execute(f"pagewalk {hex(address)} --pgd $cr3", to_string=True).splitlines()[-1]
assert res == res2 assert res == res2
# test non nonexistent address # test non nonexistent address
res = gdb.execute("pagewalk 0", to_string=True) res = gdb.execute("pagewalk 0", to_string=True)
assert res == "address is not mapped" assert res.splitlines()[-1] == "address is not mapped"

Loading…
Cancel
Save