From d85917d2bf831e0a652d1130799d1a246813015e Mon Sep 17 00:00:00 2001 From: Ritoban Dutta <124308320+ritoban23@users.noreply.github.com> Date: Tue, 28 Oct 2025 20:14:54 +0530 Subject: [PATCH 1/4] Remove deprecated underscore aliases (#3383) --- pwndbg/dbg/gdb/__init__.py | 41 -------------------------------------- 1 file changed, 41 deletions(-) diff --git a/pwndbg/dbg/gdb/__init__.py b/pwndbg/dbg/gdb/__init__.py index 2be0c341c..df3460901 100644 --- a/pwndbg/dbg/gdb/__init__.py +++ b/pwndbg/dbg/gdb/__init__.py @@ -1421,47 +1421,6 @@ class GDB(pwndbg.dbg_mod.Debugger): for line in pre_commands.strip().splitlines(): gdb.execute(line) - # See https://github.com/pwndbg/pwndbg/issues/2890#issuecomment-2813047212 - # Note: Remove this in a late 2025 or 2026 release? - for deprecated_cmd in ( - "vmmap_add", - "vmmap_clear", - "vmmap_load", - "vmmap_explore", - "vis_heap_chunks", - "heap_config", - "stack_explore", - "auxv_explore", - "log_level", - "find_fake_fast", - "malloc_chunk", - "top_chunk", - "try_free", - "save_ida", - "knft_dump", - "knft_list_chains", - "knft_list_exprs", - "knft_list_flowtables", - "knft_list_objects", - "knft_list_rules", - "knft_list_sets", - "knft_list_tables", - "patch_list", - "patch_revert", - "jemalloc_extent_info", - "jemalloc_find_extent", - "jemalloc_heap", - ): - fixed_cmd = deprecated_cmd.replace("_", "-") - gdb.execute( - f"alias -a {deprecated_cmd} = echo Use `{fixed_cmd}` instead (Pwndbg changed `_` to `-` in command names)\\n" - ) - - for deprecated_cmd, new_cmd in (("pcplist", "buddydump"),): - gdb.execute( - f"alias -a {deprecated_cmd} = echo deprecation warning for old name, use `{new_cmd}` instead\\n" - ) - # This may throw an exception, see pwndbg/pwndbg#27 try: gdb.execute("set disassembly-flavor intel") From e5ab2350499445daa2bef53eb3d26fc28a578cd9 Mon Sep 17 00:00:00 2001 From: k4lizen <124312252+k4lizen@users.noreply.github.com> Date: Wed, 29 Oct 2025 14:18:02 +0100 Subject: [PATCH 2/4] Add ks alias to klookup (#3385) * add ks alias to klookup * docs --- docs/commands/kernel/klookup.md | 2 +- pwndbg/commands/klookup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/commands/kernel/klookup.md b/docs/commands/kernel/klookup.md index 7199de83d..562225982 100644 --- a/docs/commands/kernel/klookup.md +++ b/docs/commands/kernel/klookup.md @@ -8,7 +8,7 @@ usage: klookup [-h] [-a] [symbol] Lookup kernel symbols -**Alias:** kallsyms +**Aliases:** kallsyms, ks ### Positional arguments |Positional Argument|Help| diff --git a/pwndbg/commands/klookup.py b/pwndbg/commands/klookup.py index 974837ef4..6d82302b1 100644 --- a/pwndbg/commands/klookup.py +++ b/pwndbg/commands/klookup.py @@ -15,7 +15,7 @@ parser.add_argument( ) -@pwndbg.commands.Command(parser, aliases=["kallsyms"], category=CommandCategory.KERNEL) +@pwndbg.commands.Command(parser, aliases=["kallsyms", "ks"], category=CommandCategory.KERNEL) @pwndbg.commands.OnlyWhenQemuKernel @pwndbg.commands.OnlyWhenPagingEnabled def klookup(symbol: str, apply: bool) -> None: From 39083a134c3c37a42cb11d62d8757eee9729466c Mon Sep 17 00:00:00 2001 From: marywinter3 <116124143+marywinter3@users.noreply.github.com> Date: Sat, 1 Nov 2025 01:04:38 +0100 Subject: [PATCH 3/4] Hexdump command (#3337) * Add option to dump memory as code * Change for loops * Change return * Add tests. * Fix bug with backslash --- docs/commands/memory/hexdump.md | 3 +- pwndbg/commands/hexdump.py | 57 +++++++++++++++++++------ tests/library/gdb/tests/test_hexdump.py | 36 ++++++++++++++++ 3 files changed, 82 insertions(+), 14 deletions(-) diff --git a/docs/commands/memory/hexdump.md b/docs/commands/memory/hexdump.md index 9b6c3ffc9..112962b38 100644 --- a/docs/commands/memory/hexdump.md +++ b/docs/commands/memory/hexdump.md @@ -2,7 +2,7 @@ # hexdump ```text -usage: hexdump [-h] [address] [count] +usage: hexdump [-h] [-C [{py,c}]] [address] [count] ``` @@ -19,6 +19,7 @@ Hexdumps data at the specified address or module name. |Short|Long|Help| | :--- | :--- | :--- | |-h|--help|show this help message and exit| +|-C|--code|Output as Python or C code data definition (default: py)| diff --git a/pwndbg/commands/hexdump.py b/pwndbg/commands/hexdump.py index ca73c6db1..246ac2640 100644 --- a/pwndbg/commands/hexdump.py +++ b/pwndbg/commands/hexdump.py @@ -53,6 +53,24 @@ def address_or_module_name(s) -> int: raise argparse.ArgumentTypeError("Unknown hexdump argument type.") +def format_c(data: bytes) -> str: + toks = [f"{b:#02x}" for b in data] + lines = [] + for i in range(0, len(toks), 16): + elem = ", ".join(toks[i : i + 16]) + lines.append(f" {elem},") + body = "\n".join(lines) + return f"static const unsigned char data[] = {{\n{body}\n}};\n" + + +def format_py(data: bytes) -> str: + lines = [] + for i in range(0, len(data), 16): + seg = "".join(f"\\x{b:02x}" for b in data[i : i + 16]) + lines.append(f' b"{seg}"') + return "data = (\n{}\n)\n".format("\n".join(lines)) + + parser = argparse.ArgumentParser( description="Hexdumps data at the specified address or module name." ) @@ -66,11 +84,20 @@ parser.add_argument( parser.add_argument( "count", nargs="?", default=pwndbg.config.hexdump_bytes, help="Number of bytes to dump" ) +parser.add_argument( + "-C", + "--code", + type=str, + nargs="?", + const="py", + choices=("py", "c"), + help="Output as Python or C code data definition (default: py)", +) @pwndbg.commands.Command(parser, category=CommandCategory.MEMORY) @pwndbg.commands.OnlyWhenRunning -def hexdump(address, count=pwndbg.config.hexdump_bytes) -> None: +def hexdump(address, count=pwndbg.config.hexdump_bytes, code: str | None = None) -> None: if hexdump.repeat: address = hexdump.last_address else: @@ -129,19 +156,23 @@ def hexdump(address, count=pwndbg.config.hexdump_bytes) -> None: print(e) return - result = pwndbg.hexdump.hexdump( - data, - address=address, - width=width, - group_width=group_width, - flip_group_endianness=flip_group_endianness, - offset=hexdump.offset, - ) - - for line in result: - print(line) + if code: + source = format_py(data) if code == "py" else format_c(data) + print(source) + hexdump.offset += len(data) + else: + result = pwndbg.hexdump.hexdump( + data, + address=address, + width=width, + group_width=group_width, + flip_group_endianness=flip_group_endianness, + offset=hexdump.offset, + ) + for line in result: + print(line) - hexdump.offset += count + hexdump.offset += len(data) hexdump.last_address = 0 diff --git a/tests/library/gdb/tests/test_hexdump.py b/tests/library/gdb/tests/test_hexdump.py index 4328bbf2c..bb0c4d3a5 100644 --- a/tests/library/gdb/tests/test_hexdump.py +++ b/tests/library/gdb/tests/test_hexdump.py @@ -158,3 +158,39 @@ def test_hexdump_limit_check(start_binary): # Reset to default for subsequent tests if any gdb.execute(f"set hexdump-limit-mb {default_limit_mb}") + + +def test_hexdump_code_py_format(start_binary): + start_binary(BINARY) + sp = pwndbg.aglib.regs.rsp + + pwndbg.aglib.memory.write(sp, b"abcdefgh\x01\x02\x03\x04\x05\x06\x07\x08" * 16) + + SIZE = 21 + out = gdb.execute(f"hexdump -C py $rsp {SIZE}", to_string=True) + + expected = ( + "data = (\n" + ' b"\\x61\\x62\\x63\\x64\\x65\\x66\\x67\\x68\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08"\n' + ' b"\\x61\\x62\\x63\\x64\\x65"\n' + ")\n" + ) + assert out.rstrip("\n") == expected.rstrip("\n") + + +def test_hexdump_code_c_format(start_binary): + start_binary(BINARY) + sp = pwndbg.aglib.regs.rsp + + pwndbg.aglib.memory.write(sp, b"abcdefgh\x01\x02\x03\x04\x05\x06\x07\x08" * 16) + + SIZE = 21 + out = gdb.execute(f"hexdump -C c $rsp {SIZE}", to_string=True) + + expected = ( + "static const unsigned char data[] = {\n" + " 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8,\n" + " 0x61, 0x62, 0x63, 0x64, 0x65,\n" + "};\n" + ) + assert out.rstrip("\n") == expected.rstrip("\n") From 30299571485b7bd6da54855ad33a84b4c091db76 Mon Sep 17 00:00:00 2001 From: Will Rosenberg Date: Sun, 2 Nov 2025 16:32:52 -0700 Subject: [PATCH 4/4] fix get_file() checking relative paths (#3386) * fix get_file() handling of relative paths * aglib get_file test * fix typo * lint formatting --- pwndbg/aglib/file.py | 4 ---- tests/library/gdb/tests/test_file.py | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 tests/library/gdb/tests/test_file.py diff --git a/pwndbg/aglib/file.py b/pwndbg/aglib/file.py index 84e900962..f34125fa9 100644 --- a/pwndbg/aglib/file.py +++ b/pwndbg/aglib/file.py @@ -82,10 +82,6 @@ def get_file(path: str, try_local_path: bool = False) -> str: The local path to the file """ has_target_prefix = path.startswith("target:") - has_good_prefix = path.startswith(("/", "./", "../")) or has_target_prefix - if not has_good_prefix: - raise OSError("get_file called with incorrect path", errno.ENOENT) - if has_target_prefix: path = path[7:] # len('target:') == 7 diff --git a/tests/library/gdb/tests/test_file.py b/tests/library/gdb/tests/test_file.py new file mode 100644 index 000000000..2ef5865c5 --- /dev/null +++ b/tests/library/gdb/tests/test_file.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +import os +import tempfile + +from pwndbg.aglib.file import get + + +def test_get(): + # Test different relative and absolute file path prefixes + cwd = os.getcwd() + test_file_prefixes = ["/", "./", f"../{os.path.basename(cwd)}/", ""] + with tempfile.TemporaryDirectory(dir=cwd) as tempdir: + path = os.path.join(tempdir, "test_file") + with open(path, "w") as f: + f.write("test") + for test_prefix in test_file_prefixes: + test_path = path if test_prefix == "/" else test_prefix + os.path.relpath(path) + assert get(test_path) == b"test"