diff --git a/pwndbg/commands/windbg.py b/pwndbg/commands/windbg.py index a95028948..6d9c2e00e 100644 --- a/pwndbg/commands/windbg.py +++ b/pwndbg/commands/windbg.py @@ -4,8 +4,8 @@ Compatibility functionality for Windbg users. import argparse import codecs -import math from builtins import str +from itertools import chain import gdb @@ -15,16 +15,7 @@ import pwndbg.gdblib.memory import pwndbg.gdblib.strings import pwndbg.gdblib.symbol import pwndbg.gdblib.typeinfo - - -def get_type(size): - return { - 1: pwndbg.gdblib.typeinfo.uint8, - 2: pwndbg.gdblib.typeinfo.uint16, - 4: pwndbg.gdblib.typeinfo.uint32, - 8: pwndbg.gdblib.typeinfo.uint64, - }[size] - +import pwndbg.hexdump parser = argparse.ArgumentParser(description="Starting at the specified address, dump N bytes.") parser.add_argument( @@ -141,50 +132,18 @@ def dX(size, address, count, to_string=False, repeat=False): """ Traditionally, windbg will display 16 bytes of data per line. """ - values = [] - if repeat: - count = dX.last_count - address = dX.last_address - else: - address = int(address) & pwndbg.gdblib.arch.ptrmask - count = int(count) - - type = get_type(size) - - for i in range(count): - try: - gval = pwndbg.gdblib.memory.poi(type, address + i * size) - # print(str(gval)) - values.append(int(gval)) - except gdb.MemoryError: - break - - if not values: - print("Could not access the provided address") - return - - n_rows = int(math.ceil(count * size / float(16))) - row_sz = int(16 / size) - rows = [values[i * row_sz : (i + 1) * row_sz] for i in range(n_rows)] - lines = [] - - # sys.stdout.write(repr(rows) + '\n') - - for i, row in enumerate(rows): - if not row: - continue - line = [enhex(pwndbg.gdblib.arch.ptrsize, address + (i * 16)), " "] - for value in row: - line.append(enhex(size, value)) - lines.append(" ".join(line)) + lines = list( + chain.from_iterable( + pwndbg.hexdump.hexdump( + data=None, size=size, count=count, address=address, repeat=repeat, dX_call=True + ) + ) + ) - if not to_string: + if not to_string and lines: print("\n".join(lines)) - dX.last_count = count - dX.last_address = address + len(rows) * 16 - return lines diff --git a/pwndbg/gdblib/typeinfo.py b/pwndbg/gdblib/typeinfo.py index 4ac9634bc..648005c26 100644 --- a/pwndbg/gdblib/typeinfo.py +++ b/pwndbg/gdblib/typeinfo.py @@ -87,3 +87,12 @@ def read_gdbvalue(type_name, addr): """Read the memory contents at addr and interpret them as a GDB value with the given type""" gdb_type = pwndbg.gdblib.typeinfo.load(type_name) return gdb.Value(addr).cast(gdb_type.pointer()).dereference() + + +def get_type(size): + return { + 1: pwndbg.gdblib.typeinfo.uint8, + 2: pwndbg.gdblib.typeinfo.uint16, + 4: pwndbg.gdblib.typeinfo.uint32, + 8: pwndbg.gdblib.typeinfo.uint64, + }[size] diff --git a/pwndbg/hexdump.py b/pwndbg/hexdump.py index 49c72865b..b005d0c3f 100644 --- a/pwndbg/hexdump.py +++ b/pwndbg/hexdump.py @@ -2,13 +2,17 @@ Hexdump implementation, ~= stolen from pwntools. """ +import math import string +import gdb import pwnlib.util.lists import pwndbg.color.hexdump as H import pwndbg.color.theme as theme import pwndbg.gdblib.config +import pwndbg.gdblib.typeinfo +from pwndbg.commands.windbg import enhex color_scheme = None printable = None @@ -66,51 +70,105 @@ def load_color_scheme(): def hexdump( - data, address=0, width=16, group_width=4, flip_group_endianess=False, skip=True, offset=0 + data, + address=0, + width=16, + group_width=4, + flip_group_endianess=False, + skip=True, + offset=0, + size=0, + count=0, + repeat=False, + dX_call=False, ): - 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)) - last_line = None - skipping = False - for i, line in enumerate(groupby(width, data, fill=-1)): - if skip and line == last_line: - if skipping: - continue + if not dX_call: + 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)) + last_line = None + skipping = False + for i, line in enumerate(groupby(width, data, fill=-1)): + if skip and line == last_line: + if skipping: + continue + + skipping = True + yield "..." + else: + skipping = False + last_line = line + + hexline = [] + + hexline.append(H.offset("+%04x " % ((i + offset) * width))) + hexline.append(H.address("%#08x " % (address + (i * width)))) + + 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_width - 1: + hexline.append(H.highlight_group_lsb(color_scheme[char])) + else: + hexline.append(color_scheme[char]) + hexline.append(str(config_byte_separator)) + hexline.append(" ") - skipping = True - yield "..." - else: - skipping = False - last_line = line - - hexline = [] - - hexline.append(H.offset("+%04x " % ((i + offset) * width))) - hexline.append(H.address("%#08x " % (address + (i * width)))) - - 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_width - 1: - hexline.append(H.highlight_group_lsb(color_scheme[char])) - else: - hexline.append(color_scheme[char]) - hexline.append(str(config_byte_separator)) - hexline.append(" ") - - hexline.append(H.separator("%s" % config_separator)) - for group in groupby(group_width, line): - for char in group: - hexline.append(printable[char]) hexline.append(H.separator("%s" % config_separator)) + 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) + + else: + + # Traditionally, windbg will display 16 bytes of data per line. + values = [] + + if repeat: + count = hexdump.last_count + address = hexdump.last_address + else: + address = int(address) & pwndbg.gdblib.arch.ptrmask + count = int(count) + + size_type = pwndbg.gdblib.typeinfo.get_type(size) + + for i in range(count): + try: + gval = pwndbg.gdblib.memory.poi(size_type, address + i * size) + values.append(int(gval)) + except gdb.MemoryError: + break + + if not values: + print("Could not access the provided address") + return + + n_rows = int(math.ceil(count * size / float(16))) + row_sz = int(16 / size) + rows = [values[i * row_sz : (i + 1) * row_sz] for i in range(n_rows)] + lines = [] + + for i, row in enumerate(rows): + if not row: + continue + line = [enhex(pwndbg.gdblib.arch.ptrsize, address + (i * 16)), " "] + for value in row: + line.append(enhex(size, value)) + lines.append(" ".join(line)) + + hexdump.last_count = count + hexdump.last_address = address + len(rows) * 16 - yield "".join(hexline) + yield lines