From d40fa8602f7ebe55678fa84f96abe46e606f8030 Mon Sep 17 00:00:00 2001 From: jxuanli Date: Fri, 30 May 2025 02:19:48 -0700 Subject: [PATCH] improved testing / output --- pwndbg/aglib/kernel/__init__.py | 6 ++++++ pwndbg/commands/pagewalk.py | 11 ++++++----- tests/qemu-tests/tests/system/test_commands_kernel.py | 11 ++++++++--- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/pwndbg/aglib/kernel/__init__.py b/pwndbg/aglib/kernel/__init__.py index 99df83c97..d927baddb 100644 --- a/pwndbg/aglib/kernel/__init__.py +++ b/pwndbg/aglib/kernel/__init__.py @@ -743,6 +743,12 @@ def paging_enabled() -> 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() if ops: return ops.uses_5lvl_paging() diff --git a/pwndbg/commands/pagewalk.py b/pwndbg/commands/pagewalk.py index 3d55657ab..b09bbd91c 100644 --- a/pwndbg/commands/pagewalk.py +++ b/pwndbg/commands/pagewalk.py @@ -10,8 +10,8 @@ from pwndbg.commands import CommandCategory from pwndbg.lib.regs import BitFlags parser = argparse.ArgumentParser(description="Performs pagewalk.") -parser.add_argument("vaddr", type=int, help="virtual address to walk") -parser.add_argument("--pgd", dest="entry", type=int, default=None, help="") +parser.add_argument("vaddr", type=str, help="virtual address to walk") +parser.add_argument("--pgd", dest="entry", type=str, default=None, help="") 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.OnlyWhenPagingEnabled def pagewalk(vaddr, entry=None): + vaddr = int(pwndbg.dbg.selected_frame().evaluate_expression(vaddr)) # https://blog.zolutal.io/understanding-paging/ base = pwndbg.aglib.kernel.physmap_base() level = 4 @@ -61,7 +62,7 @@ def pagewalk(vaddr, entry=None): if entry is None: entry = pwndbg.aglib.regs["cr3"] else: - entry = pwndbg.dbg.selected_frame().evaluate_expression(entry) + entry = int(pwndbg.dbg.selected_frame().evaluate_expression(entry)) if entry > base: # user inputted a physmap address as pointer to pgd entry -= base @@ -76,11 +77,11 @@ def pagewalk(vaddr, entry=None): idx = (vaddr & (0x1FF << shift)) >> shift entry = 0 try: - table = pwndbg.aglib.memory.get_typed_pointer("ulong", cur) + table = pwndbg.aglib.memory.get_typed_pointer("unsigned long", cur) entry = int(table[idx]) print_pagetable_entry(names[i], entry, cur) except Exception as e: - print(M.warn(f"Exception {e} while page walking")) + print(M.warn(f"Exception while page walking: {e}")) entry = 0 if entry == 0: print(M.warn("address is not mapped")) diff --git a/tests/qemu-tests/tests/system/test_commands_kernel.py b/tests/qemu-tests/tests/system/test_commands_kernel.py index 3296d95b2..cdfd37437 100644 --- a/tests/qemu-tests/tests/system/test_commands_kernel.py +++ b/tests/qemu-tests/tests/system/test_commands_kernel.py @@ -187,18 +187,23 @@ def test_command_pagewalk(): # no kbase? fine pages = pwndbg.aglib.vmmap.get() 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) assert "PMD" in res # Page Size is only set for PMDe or PTe 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) # 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) actual = pwndbg.aglib.memory.read(physmap_addr, 0x100) assert all(expected[i] == actual[i] for i in range(0x100)) # 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 # test non nonexistent address res = gdb.execute("pagewalk 0", to_string=True) - assert res == "address is not mapped" + assert res.splitlines()[-1] == "address is not mapped"