Exemplo n.º 1
0
def initial_hook(*a):
    if show_tip and not pwndbg.decorators.first_prompt:
        colored_tip = re.sub(
            "`(.*?)`", lambda s: message.warn(s.group()[1:-1]), get_tip_of_the_day()
        )
        print(
            message.prompt("------- tip of the day")
            + message.system(" (disable with %s)" % message.notice("set show-tips off"))
            + message.prompt(" -------")
        )
        print((colored_tip))
    pwndbg.decorators.first_prompt = True

    prompt_hook(*a)
    gdb.prompt_hook = prompt_hook
Exemplo n.º 2
0
import pwndbg.decorators
import pwndbg.events
import pwndbg.gdbutils
import pwndbg.memoize
from pwndbg.color import disable_colors
from pwndbg.color import message

funcs_list_str = ', '.join(message.notice('$' + f.name) for f in pwndbg.gdbutils.functions.functions)

hint_lines = (
    'loaded %i commands. Type %s for a list.' % (len(pwndbg.commands.commands), message.notice('pwndbg [filter]')),
    'created %s gdb functions (can be used with print/break)' % funcs_list_str
)

for line in hint_lines:
    print(message.prompt('pwndbg: ') + message.system(line))

cur = (gdb.selected_inferior(), gdb.selected_thread())


def prompt_hook(*a):
    global cur
    pwndbg.decorators.first_prompt = True

    new = (gdb.selected_inferior(), gdb.selected_thread())

    if cur != new:
        pwndbg.events.after_reload(start=False)
        cur = new

    if pwndbg.proc.alive and pwndbg.proc.thread_is_stopped:
Exemplo n.º 3
0
Arquivo: heap.py Projeto: yy221/pwndbg
def malloc_chunk(addr, fake=False, verbose=False, simple=False):
    """Print a malloc_chunk struct's contents."""
    # points to the real start of the chunk
    cursor = int(addr)

    allocator = pwndbg.heap.current
    ptr_size = allocator.size_sz

    size_field = pwndbg.memory.u(cursor + allocator.chunk_key_offset('size'))
    real_size = size_field & ~allocator.malloc_align_mask

    headers_to_print = []  # both state (free/allocated) and flags
    fields_to_print = set()  # in addition to addr and size
    out_fields = "Addr: {}\n".format(M.get(cursor))

    if fake:
        headers_to_print.append(message.on("Fake chunk"))
        verbose = True  # print all fields for fake chunks

    if simple:
        chunk = read_chunk(cursor)

        if not headers_to_print:
            headers_to_print.append(message.hint(M.get(cursor)))

        prev_inuse, is_mmapped, non_main_arena = allocator.chunk_flags(
            int(chunk['size']))
        if prev_inuse:
            headers_to_print.append(message.hint('PREV_INUSE'))
        if is_mmapped:
            headers_to_print.append(message.hint('IS_MMAPED'))
        if non_main_arena:
            headers_to_print.append(message.hint('NON_MAIN_ARENA'))

        print(' | '.join(headers_to_print))
        for key, val in chunk.items():
            print(message.system(key) + ": 0x{:02x}".format(int(val)))
        print('')
        return

    arena = allocator.get_arena_for_chunk(cursor)
    arena_address = None
    is_top = False
    if not fake and arena:
        arena_address = arena.address
        top_chunk = arena['top']
        if cursor == top_chunk:
            headers_to_print.append(message.off("Top chunk"))
            is_top = True

    if not is_top:
        fastbins = allocator.fastbins(arena_address) or {}
        smallbins = allocator.smallbins(arena_address) or {}
        largebins = allocator.largebins(arena_address) or {}
        unsortedbin = allocator.unsortedbin(arena_address) or {}
        if allocator.has_tcache():
            tcachebins = allocator.tcachebins(None)

        if real_size in fastbins.keys() and cursor in fastbins[real_size]:
            headers_to_print.append(message.on("Free chunk (fastbins)"))
            if not verbose:
                fields_to_print.add('fd')

        elif real_size in smallbins.keys() and cursor in bin_addrs(
                smallbins[real_size], "smallbins"):
            headers_to_print.append(message.on("Free chunk (smallbins)"))
            if not verbose:
                fields_to_print.update(['fd', 'bk'])

        elif real_size >= list(
                largebins.items())[0][0] and cursor in bin_addrs(
                    largebins[(list(
                        largebins.items())[allocator.largebin_index(real_size)
                                           - 64][0])], "largebins"):
            headers_to_print.append(message.on("Free chunk (largebins)"))
            if not verbose:
                fields_to_print.update(
                    ['fd', 'bk', 'fd_nextsize', 'bk_nextsize'])

        elif cursor in bin_addrs(unsortedbin['all'], "unsortedbin"):
            headers_to_print.append(message.on("Free chunk (unsortedbin)"))
            if not verbose:
                fields_to_print.update(['fd', 'bk'])

        elif allocator.has_tcache() and real_size in tcachebins.keys(
        ) and cursor + ptr_size * 2 in bin_addrs(tcachebins[real_size],
                                                 "tcachebins"):
            headers_to_print.append(message.on("Free chunk (tcache)"))
            if not verbose:
                fields_to_print.add('fd')

        else:
            headers_to_print.append(message.hint("Allocated chunk"))

    if verbose:
        fields_to_print.update(
            ['prev_size', 'size', 'fd', 'bk', 'fd_nextsize', 'bk_nextsize'])
    else:
        out_fields += "Size: 0x{:02x}\n".format(size_field)

    prev_inuse, is_mmapped, non_main_arena = allocator.chunk_flags(size_field)
    if prev_inuse:
        headers_to_print.append(message.hint('PREV_INUSE'))
    if is_mmapped:
        headers_to_print.append(message.hint('IS_MMAPED'))
    if non_main_arena:
        headers_to_print.append(message.hint('NON_MAIN_ARENA'))

    fields_ordered = [
        'prev_size', 'size', 'fd', 'bk', 'fd_nextsize', 'bk_nextsize'
    ]
    for field_to_print in fields_ordered:
        if field_to_print in fields_to_print:
            out_fields += message.system(
                field_to_print) + ": 0x{:02x}\n".format(
                    pwndbg.memory.u(
                        cursor + allocator.chunk_key_offset(field_to_print)))

    print(' | '.join(headers_to_print) + "\n" + out_fields)
Exemplo n.º 4
0
from pwndbg.color import disable_colors
from pwndbg.color import message
from pwndbg.tips import get_tip_of_the_day

funcs_list_str = ", ".join(
    message.notice("$" + f.name) for f in pwndbg.gdbutils.functions.functions
)

hint_lines = (
    "loaded %i commands. Type %s for a list."
    % (len(pwndbg.commands.commands), message.notice("pwndbg [filter]")),
    "created %s gdb functions (can be used with print/break)" % funcs_list_str,
)

for line in hint_lines:
    print(message.prompt("pwndbg: ") + message.system(line))

# noinspection PyPackageRequirements
show_tip = pwndbg.config.Parameter(
    "show-tips", True, "whether to display the tip of the day on startup"
)

cur = None


def initial_hook(*a):
    if show_tip and not pwndbg.decorators.first_prompt:
        colored_tip = re.sub(
            "`(.*?)`", lambda s: message.warn(s.group()[1:-1]), get_tip_of_the_day()
        )
        print(
Exemplo n.º 5
0
    def new_malloc_chunk(addr, fake=False, verbose=False, simple=False):
        idx, start, end, rest = (lambda idx, start, end, **rest:
                                 (idx, start, end, rest))(**scope)
        scope['idx'] += 1

        if start is not None and end is not None and idx not in range(
                start, end + 1):
            return

        ## original begin
        cursor = int(addr)

        allocator = pwndbg.heap.current
        ptr_size = allocator.size_sz

        size_field = pwndbg.memory.u(cursor +
                                     allocator.chunk_key_offset('size'))
        real_size = size_field & ~allocator.malloc_align_mask

        headers_to_print = []  # both state (free/allocated) and flags
        fields_to_print = set()  # in addition to addr and size
        out_fields = "Addr: {}\n".format(M.get(cursor))

        if fake:
            headers_to_print.append(message.on("Fake chunk"))
            verbose = True  # print all fields for fake chunks

        if simple:
            chunk = read_chunk(cursor)

            if not headers_to_print:
                headers_to_print.append(message.hint(M.get(cursor)))

            prev_inuse, is_mmapped, non_main_arena = allocator.chunk_flags(
                int(chunk['size']))
            if prev_inuse:
                headers_to_print.append(message.hint('PREV_INUSE'))
            if is_mmapped:
                headers_to_print.append(message.hint('IS_MMAPED'))
            if non_main_arena:
                headers_to_print.append(message.hint('NON_MAIN_ARENA'))

            print(' | '.join(headers_to_print))
            for key, val in chunk.items():
                print(message.system(key) + ": 0x{:02x}".format(int(val)))
            print('')
            return

        arena = allocator.get_arena_for_chunk(cursor)
        arena_address = None
        is_top = False
        if not fake and arena:
            arena_address = arena.address
            top_chunk = arena['top']
            if cursor == top_chunk:
                headers_to_print.append(message.off("Top".center(9, " ")))
                is_top = True

        if not is_top:
            fastbins = allocator.fastbins(arena_address) or {}
            smallbins = allocator.smallbins(arena_address) or {}
            largebins = allocator.largebins(arena_address) or {}
            unsortedbin = allocator.unsortedbin(arena_address) or {}
            if allocator.has_tcache():
                tcachebins = allocator.tcachebins(None)

            if real_size in fastbins.keys() and cursor in fastbins[real_size]:
                headers_to_print.append(message.on("F(fast)".center(9, " ")))
                if not verbose:
                    fields_to_print.add('fd')

            elif real_size in smallbins.keys() and cursor in bin_addrs(
                    smallbins[real_size], "smallbins"):
                headers_to_print.append(message.on("F(small)".center(9, " ")))
                if not verbose:
                    fields_to_print.update(['fd', 'bk'])

            elif real_size >= list(
                    largebins.items())[0][0] and cursor in bin_addrs(
                        largebins[(list(largebins.items())[
                            allocator.largebin_index(real_size) - 64][0])],
                        "largebins"):
                headers_to_print.append(message.on("F(large)".center(9, " ")))
                if not verbose:
                    fields_to_print.update(
                        ['fd', 'bk', 'fd_nextsize', 'bk_nextsize'])

            elif cursor in bin_addrs(unsortedbin['all'], "unsortedbin"):
                headers_to_print.append(message.on("F(unsort)".center(9, " ")))
                if not verbose:
                    fields_to_print.update(['fd', 'bk'])

            elif allocator.has_tcache() and real_size in tcachebins.keys(
            ) and cursor + ptr_size * 2 in bin_addrs(tcachebins[real_size],
                                                     "tcachebins"):
                headers_to_print.append(message.on("F(tcache)".center(9, " ")))
                if not verbose:
                    fields_to_print.add('fd')

            else:
                headers_to_print.append(
                    message.hint("Allocated".center(9, " ")))

        if verbose:
            fields_to_print.update([
                'prev_size', 'size', 'fd', 'bk', 'fd_nextsize', 'bk_nextsize'
            ])
        else:
            out_fields += "Size: 0x{:02x}\n".format(size_field)

        prev_inuse, is_mmapped, non_main_arena = allocator.chunk_flags(
            size_field)
        if prev_inuse:
            headers_to_print.append(message.hint('PREV_INUSE'))
        if is_mmapped:
            headers_to_print.append(message.hint('IS_MMAPED'))
        if non_main_arena:
            headers_to_print.append(message.hint('NON_MAIN_ARENA'))

        ## original end
        if not verbose:
            def ascii_char(byte):
                if byte >= 0x20 and byte < 0x7e:
                    return chr(byte)  # Ensure we return a str
                else:
                    return "."

            content = ""
            content += "[{:03d}] ".format(idx)

            content += M.get(cursor) + f" SIZE=0x{size_field:08x}"
            data = addr + pwndbg.arch.ptrsize * 2
            content += " DATA[" + hex(data) + "]"
            if size_field >= 0x20:
                bytes_read = pwndbg.memory.read(data, 0x20, partial=True)
            else:
                bytes_read = pwndbg.memory.read(data, size, partial=True)
            content += " |" + "".join([ascii_char(c) for c in bytes_read]) + "| "
            print(content + " | ".join(headers_to_print))
        else:
            print_chunk_detail(addr, size_field)
Exemplo n.º 6
0
def heap(addr=None, verbose=False):
    """Iteratively print chunks on a heap, default to the current thread's
    active heap.
    """
    allocator = pwndbg.heap.current
    heap_region = allocator.get_heap_boundaries(addr)
    arena = allocator.get_arena_for_chunk(
        addr) if addr else allocator.get_arena()

    top_chunk = arena['top']
    ptr_size = allocator.size_sz

    # Calculate where to start printing; if an address was supplied, use that,
    # if this heap belongs to the main arena, start at the beginning of the
    # heap's mapping, otherwise, compensate for the presence of a heap_info
    # struct and possibly an arena.
    if addr:
        cursor = int(addr)
    elif arena == allocator.main_arena:
        cursor = heap_region.start
    else:
        cursor = heap_region.start + allocator.heap_info.sizeof
        if pwndbg.vmmap.find(allocator.get_heap(
                heap_region.start)['ar_ptr']) == heap_region:
            # Round up to a 2-machine-word alignment after an arena to
            # compensate for the presence of the have_fastchunks variable
            # in GLIBC versions >= 2.27.
            cursor += (allocator.malloc_state.sizeof +
                       ptr_size) & ~allocator.malloc_align_mask

    # i686 alignment heuristic
    first_chunk_size = pwndbg.arch.unpack(
        pwndbg.memory.read(cursor + ptr_size, ptr_size))
    if first_chunk_size == 0:
        cursor += ptr_size * 2

    while cursor in heap_region:
        old_cursor = cursor
        size_field = pwndbg.memory.u(cursor +
                                     allocator.chunk_key_offset('size'))
        real_size = size_field & ~allocator.malloc_align_mask

        if cursor == top_chunk:
            out = message.off("Top chunk\n")
            out += "Addr: {}\nSize: 0x{:02x}".format(M.get(cursor), size_field)
            print(out)
            break

        fastbins = allocator.fastbins(arena.address)
        smallbins = allocator.smallbins(arena.address)
        largebins = allocator.largebins(arena.address)
        unsortedbin = allocator.unsortedbin(arena.address)
        if allocator.has_tcache():
            tcachebins = allocator.tcachebins(None)

        out = "Addr: {}\nSize: 0x{:02x}\n".format(M.get(cursor), size_field)

        if real_size in fastbins.keys() and cursor in fastbins[real_size]:
            out = message.on("Free chunk (fastbins)\n") + out
            if not verbose:
                out += message.system("fd: ") + "0x{:02x}\n".format(
                    pwndbg.memory.u(cursor + allocator.chunk_key_offset('fd')))
        elif real_size in smallbins.keys() and cursor in bin_addrs(
                smallbins[real_size], "smallbins"):
            out = message.on("Free chunk (smallbins)\n") + out
            if not verbose:
                out += message.system("fd: ") + "0x{:02x}\n".format(
                    pwndbg.memory.u(cursor + allocator.chunk_key_offset('fd')))
                out += message.system("bk: ") + "0x{:02x}\n".format(
                    pwndbg.memory.u(cursor + allocator.chunk_key_offset('bk')))
        elif real_size >= list(
                largebins.items())[0][0] and cursor in bin_addrs(
                    largebins[(list(
                        largebins.items())[allocator.largebin_index(real_size)
                                           - 64][0])], "largebins"):
            out = message.on("Free chunk (largebins)\n") + out
            if not verbose:
                out += message.system("fd: ") + "0x{:02x}\n".format(
                    pwndbg.memory.u(cursor + allocator.chunk_key_offset('fd')))
                out += message.system("bk: ") + "0x{:02x}\n".format(
                    pwndbg.memory.u(cursor + allocator.chunk_key_offset('bk')))
                out += message.system("fd_nextsize: ") + "0x{:02x}\n".format(
                    pwndbg.memory.u(cursor +
                                    allocator.chunk_key_offset('fd_nextsize')))
                out += message.system("bk_nextsize: ") + "0x{:02x}\n".format(
                    pwndbg.memory.u(cursor +
                                    allocator.chunk_key_offset('bk_nextsize')))
        elif cursor in bin_addrs(unsortedbin['all'], "unsortedbin"):
            out = message.on("Free chunk (unsortedbin)\n") + out
            if not verbose:
                out += message.system("fd: ") + "0x{:02x}\n".format(
                    pwndbg.memory.u(cursor + allocator.chunk_key_offset('fd')))
                out += message.system("bk: ") + "0x{:02x}\n".format(
                    pwndbg.memory.u(cursor + allocator.chunk_key_offset('bk')))
        elif allocator.has_tcache() and real_size in tcachebins.keys(
        ) and cursor + ptr_size * 2 in bin_addrs(tcachebins[real_size],
                                                 "tcachebins"):
            out = message.on("Free chunk (tcache)\n") + out
            if not verbose:
                out += message.system("fd: ") + "0x{:02x}\n".format(
                    pwndbg.memory.u(cursor + allocator.chunk_key_offset('fd')))
        else:
            out = message.hint("Allocated chunk\n") + out

        if verbose:
            out += message.system("fd: ") + "0x{:02x}\n".format(
                pwndbg.memory.u(cursor + allocator.chunk_key_offset('fd')))
            out += message.system("bk: ") + "0x{:02x}\n".format(
                pwndbg.memory.u(cursor + allocator.chunk_key_offset('bk')))
            out += message.system("fd_nextsize: ") + "0x{:02x}\n".format(
                pwndbg.memory.u(cursor +
                                allocator.chunk_key_offset('fd_nextsize')))
            out += message.system("bk_nextsize: ") + "0x{:02x}\n".format(
                pwndbg.memory.u(cursor +
                                allocator.chunk_key_offset('bk_nextsize')))

        print(out)
        cursor += real_size

        # Avoid an infinite loop when a chunk's size is 0.
        if cursor == old_cursor:
            break