Cleanup hexdump implementation

pull/1284/head
Gulshan Singh 3 years ago
parent 084eb36813
commit 2220918866

@ -26,7 +26,7 @@ config_separator = theme.add_color_param(
config_highlight_group_lsb = theme.add_param(
"hexdump-highlight-group-lsb",
"underline",
"highlight LSB of each group. Applies only if hexdump-adjust-group-endianess"
"highlight LSB of each group. Applies only if hexdump-use-big-endian"
" actually changes byte order.",
)

@ -13,7 +13,7 @@ pwndbg.gdblib.config.add_param("hexdump-width", 16, "line width of hexdump comma
pwndbg.gdblib.config.add_param("hexdump-bytes", 64, "number of bytes printed by hexdump command")
pwndbg.gdblib.config.add_param(
"hexdump-group-width",
4,
-1,
"number of bytes grouped in hexdump command (If -1, the architecture's pointer size is used)",
)
pwndbg.gdblib.config.add_param(
@ -57,7 +57,7 @@ parser.add_argument(
@pwndbg.commands.ArgparsedCommand(parser)
@pwndbg.commands.OnlyWhenRunning
def hexdump(address=None, count=pwndbg.gdblib.config.hexdump_bytes):
def hexdump(address, count=pwndbg.gdblib.config.hexdump_bytes):
if hexdump.repeat:
address = hexdump.last_address
hexdump.offset += 1
@ -65,16 +65,31 @@ def hexdump(address=None, count=pwndbg.gdblib.config.hexdump_bytes):
hexdump.offset = 0
address = int(address)
address &= pwndbg.gdblib.arch.ptrmask
if address > pwndbg.gdblib.arch.ptrmask:
new_address = address & pwndbg.gdblib.arch.ptrmask
print(
message.warn("0x%x is larger than the maximum address, truncating to 0x%x instead"),
address,
new_address,
)
address = new_address
count = max(int(count), 0)
width = int(pwndbg.gdblib.config.hexdump_width)
group_width = int(pwndbg.gdblib.config.hexdump_group_width)
group_width = pwndbg.gdblib.typeinfo.ptrsize if group_width == -1 else group_width
# TODO: What if arch endian is big, and use_big_endian is false?
flip_group_endianess = (
pwndbg.gdblib.config.hexdump_group_use_big_endian and pwndbg.gdblib.arch.endian == "little"
)
if count > address > 0x10000:
# The user may have input the start and end range to dump instead of the
# starting address and the number of bytes to dump. If the address is above
# some minimum address, and the count is larger than that address, we assume
# this is the case and correct it
if address > 0x10000 and count > address:
count -= address
try:
@ -84,17 +99,19 @@ def hexdump(address=None, count=pwndbg.gdblib.config.hexdump_bytes):
print(e)
return
for i, line in enumerate(
pwndbg.hexdump.hexdump(
data,
address=address,
width=width,
group_width=group_width,
flip_group_endianess=flip_group_endianess,
offset=hexdump.offset,
)
):
result = pwndbg.hexdump.hexdump(
data,
address=address,
width=width,
group_width=group_width,
flip_group_endianess=flip_group_endianess,
offset=hexdump.offset,
)
for i, line in enumerate(result):
print(line)
# If this command is entered again with no arguments, remember where we left off printing
# TODO: This is broken if the user inputs a count less than the width
hexdump.offset += i

@ -2,9 +2,10 @@
Hexdump implementation, ~= stolen from pwntools.
"""
import copy
import string
import pwnlib.util.lists
import pwndbg.color.hexdump as H
import pwndbg.color.theme as theme
import pwndbg.gdblib.config
@ -13,12 +14,8 @@ color_scheme = None
printable = None
def groupby(array, count, fill=None):
array = copy.copy(array)
while fill and len(array) % count:
array.append(fill)
for i in range(0, len(array), count):
yield array[i : i + count]
def groupby(width, array, fill=None):
return pwnlib.util.lists.group(width, array, underfull_action="fill", fill_value=fill)
config_colorize_ascii = theme.add_param(
@ -41,7 +38,7 @@ def load_color_scheme():
global color_scheme, printable
#
# We want to colorize the hex characters and only print out
# printable values on the righ hand side.
# printable values on the right hand side.
#
color_scheme = {i: H.normal("%02x" % i) for i in range(256)}
printable = {i: H.normal(".") for i in range(256)}
@ -73,32 +70,37 @@ def hexdump(
):
if not color_scheme or not printable:
load_color_scheme()
# If there's nothing to print, just print the offset and address and return
if len(data) == 0:
yield H.offset("+%04x " % len(data)) + H.address("%#08x " % (address + len(data)))
# Don't allow iterating over this generator again
return
data = list(bytearray(data))
base = address
last_line = None
skipping = False
for i, line in enumerate(groupby(data, width, -1)):
for i, line in enumerate(groupby(width, data, fill=-1)):
if skip and line == last_line:
if not skipping:
skipping = True
yield "..."
continue
if skipping:
continue
skipping = True
yield "..."
else:
skipping = False
last_line = line
hexline = []
if address:
hexline.append(H.offset("+%04x " % ((i + offset) * width)))
hexline.append(H.address("%#08x " % (base + (i * width))))
hexline.append(H.offset("+%04x " % ((i + offset) * width)))
hexline.append(H.address("%#08x " % (address + (i * width))))
for group in groupby(line, group_width):
group_length = len(group)
for group in groupby(group_width, line):
group = reversed(group) if flip_group_endianess else group
for idx, char in enumerate(group):
if flip_group_endianess and idx == group_length - 1:
if flip_group_endianess and idx == group_width - 1:
hexline.append(H.highlight_group_lsb(color_scheme[char]))
else:
hexline.append(color_scheme[char])
@ -106,22 +108,9 @@ def hexdump(
hexline.append(" ")
hexline.append(H.separator("%s" % config_separator))
for group in groupby(line, group_width):
for group in groupby(group_width, line):
for char in group:
hexline.append(printable[char])
hexline.append(H.separator("%s" % config_separator))
yield ("".join(hexline))
# skip empty footer if we printed something
if last_line:
return
hexline = []
if address:
hexline.append(H.offset("+%04x " % len(data)))
hexline.append(H.address("%#08x " % (base + len(data))))
yield "".join(hexline)
yield "".join(hexline)

@ -18,7 +18,7 @@ def run_tests(stack, use_big_endian, expected):
# Test empty hexdump
result = gdb.execute("hexdump 0", to_string=True)
assert result == "0x000000 \n"
assert result == "+0000 0x000000 \n"
results = []
# TODO: Repetition is not working in tests

Loading…
Cancel
Save