Hexdump command (#3337)

* Add option to dump memory as code

* Change for loops

* Change return

* Add tests.

* Fix bug with backslash
pull/3389/head
marywinter3 1 month ago committed by GitHub
parent e5ab235049
commit 39083a134c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -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)|
<!-- END OF AUTOGENERATED PART. Do not modify this line or the line below, they mark the end of the auto-generated part of the file. If you want to extend the documentation in a way which cannot easily be done by adding to the command help description, write below the following line. -->
<!-- ------------\>8---- ----\>8---- ----\>8------------ -->

@ -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

@ -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")

Loading…
Cancel
Save