Beispiel #1
0
def memoize():
    pwndbg.memoize.memoize.caching = not pwndbg.memoize.memoize.caching

    status = message.off(
        'OFF (pwndbg will work slower, use only for debugging pwndbg)')
    if pwndbg.memoize.memoize.caching:
        status = message.on('ON')

    print("Caching is now %s" % status)
Beispiel #2
0
def aslr(state=None):
    if state:
        gdb.execute('set disable-randomization %s' % options[state],
                    from_tty=False,
                    to_string=True)

        if pwndbg.proc.alive:
            print("Change will take effect when the process restarts")

    aslr, method = pwndbg.vmmap.check_aslr()

    if aslr is True:
        status = message.on('ON')
    elif aslr is False:
        status = message.off('OFF')
    else:
        status = message.off('???')

    print("ASLR is %s (%s)" % (status, method))
Beispiel #3
0
def top_chunk(addr=None):
    """Print relevant information about an arena's top chunk, default to the
    current thread's arena.
    """
    allocator = pwndbg.heap.current
    arena = allocator.get_arena(addr)
    address = arena['top']
    size = pwndbg.memory.u(int(address) + allocator.chunk_key_offset('size'))

    out = message.off("Top chunk\n") + "Addr: {}\nSize: 0x{:02x}".format(M.get(address), size)
    print(out)
Beispiel #4
0
def aslr(state=None):
    """
    Check the current ASLR status, or turn it on/off.

    Does not take effect until the program is restarted.
    """
    if state:
        gdb.execute('set disable-randomization %s' % options[state], 
                    from_tty=False, to_string=True)

        if pwndbg.proc.alive:
            print("Change will take effect when the process restarts")

    aslr = pwndbg.vmmap.check_aslr()
    status = message.off('OFF')

    if aslr:
        status = message.on('ON')

    print("ASLR is %s" % status)
Beispiel #5
0
def aslr(state=None):
    """
    Check the current ASLR status, or turn it on/off.

    Does not take effect until the program is restarted.
    """
    if state:
        gdb.execute('set disable-randomization %s' % options[state],
                    from_tty=False,
                    to_string=True)

        if pwndbg.proc.alive:
            print("Change will take effect when the process restarts")

    aslr = pwndbg.vmmap.check_aslr()
    status = message.off('OFF')

    if aslr:
        status = message.on('ON')

    print("ASLR is %s" % status)
Beispiel #6
0
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)
Beispiel #7
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)
Beispiel #8
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