Ejemplo n.º 1
0
def xinfo(address=None):
    address = address.cast(pwndbg.typeinfo.pvoid
                           )  # Fixes issues with function ptrs (xinfo malloc)
    addr = int(address)
    addr &= pwndbg.arch.ptrmask

    page = pwndbg.vmmap.find(addr)

    if page is None:
        print("\n  Virtual address {:#x} is not mapped.".format(addr))
        return

    print("Extended information for virtual address {}:".format(M.get(addr)))

    print("\n  Containing mapping:")
    print(M.get(address, text=str(page)))

    print("\n  Offset information:")

    if page.is_stack:
        xinfo_stack(page, addr)
    else:
        xinfo_default(page, addr)

    if page.is_memory_mapped_file:
        xinfo_mmap_file(page, addr)
Ejemplo n.º 2
0
def heap(addr=None):
    """
    Prints out all chunks in the main_arena, or the arena specified by `addr`.
    """
    main_arena = get_main_arena(addr)
    if main_arena == None:
        return

    heap_base = get_heap_bounds()[0]
    if heap_base == None:
        print(red('Could not find the heap'))
        return

    top = main_arena['top']
    last_remainder = main_arena['last_remainder']

    print(bold('Top Chunk: ') + M.get(top))
    print(bold('Last Remainder: ') + M.get(last_remainder))
    print()

    # Print out all chunks on the heap
    # TODO: Add an option to print out only free or allocated chunks
    addr = heap_base
    while addr <= top:
        chunk = malloc_chunk(addr)
        size = int(chunk['size'])

        # Clear the bottom 3 bits
        size &= ~7
        addr += size
Ejemplo n.º 3
0
def vmmap(gdbval_or_str=None, writable=False, executable=False):
    pages = pwndbg.vmmap.get()

    if gdbval_or_str:
        pages = list(filter(pages_filter(gdbval_or_str), pages))

    if not pages:
        print("There are no mappings for specified address or module.")
        return

    print(M.legend())

    if len(pages) == 1 and isinstance(gdbval_or_str, integer_types):
        page = pages[0]
        print(
            M.get(page.vaddr,
                  text=str(page) + " +0x%x" %
                  (int(gdbval_or_str) - page.vaddr)))
    else:
        for page in pages:
            if (executable and not page.execute) or (writable
                                                     and not page.write):
                continue
            print(M.get(page.vaddr, text=str(page)))

    if pwndbg.qemu.is_qemu():
        print(
            "\n[QEMU target detected - vmmap result might not be accurate; see `help vmmap`]"
        )
Ejemplo n.º 4
0
def heap(addr=None):
    """
    Prints out all chunks in the main_arena, or the arena specified by `addr`.
    """
    main_arena = get_main_arena(addr)
    if main_arena == None:
        return

    heap_base = get_heap_bounds()[0]
    if heap_base == None:
        print(red('Could not find the heap'))
        return

    top = main_arena['top']
    last_remainder = main_arena['last_remainder']

    print(bold('Top Chunk: ') + M.get(top))
    print(bold('Last Remainder: ') + M.get(last_remainder))
    print()

    # Print out all chunks on the heap
    # TODO: Add an option to print out only free or allocated chunks
    addr = heap_base
    while addr <= top:
        chunk = malloc_chunk(addr)
        size = int(chunk['size'])

        # Clear the bottom 3 bits
        size &= ~7
        if size == 0:
            break
        addr += size
Ejemplo n.º 5
0
def instruction(ins):
    asm = '%-06s %s' % (ins.mnemonic, ins.op_str)
    if pwndbg.config.syntax_highlight:
        asm = syntax_highlight(asm)
    is_branch = set(ins.groups) & capstone_branch_groups

    # Highlight the current line if enabled
    if pwndbg.config.highlight_pc and ins.address == pwndbg.regs.pc:
        asm = C.highlight(asm)

    # tl;dr is a branch?
    if ins.target not in (None, ins.address + ins.size):
        sym    = pwndbg.symbol.get(ins.target) or None
        target = M.get(ins.target)
        const  = ins.target_const
        hextarget = hex(ins.target)
        hexlen    = len(hextarget)

        # If it's a constant expression, color it directly in the asm.
        if const:
            asm = '%s <%s>' % (ljust_colored(asm, 36), target)
            asm = asm.replace(hex(ins.target), sym or target)

        # It's not a constant expression, but we've calculated the target
        # address by emulation or other means (for example showing ret instruction target)
        elif sym:
            asm = '%s <%s; %s>' % (ljust_colored(asm, 36), target, sym)

        # We were able to calculate the target, but there is no symbol
        # name for it.
        else:
            asm += '<%s>' % (target)

    # not a branch
    elif ins.symbol:
        if is_branch and not ins.target:
            asm = '%s <%s>' % (asm, ins.symbol)

            # XXX: not sure when this ever happens
            asm += '<-- file a pwndbg bug for this'
        else:
            inlined_sym = asm.replace(hex(ins.symbol_addr), ins.symbol)

            # display symbol as mem text if no inline replacement was made
            mem_text = ins.symbol if inlined_sym == asm else None
            asm = '%s <%s>' % (ljust_colored(inlined_sym, 36), M.get(ins.symbol_addr, mem_text))

    # Style the instruction mnemonic if it's a branch instruction.
    if is_branch:
        asm = asm.replace(ins.mnemonic, branch(ins.mnemonic), 1)

    # If we know the conditional is taken, mark it as taken.
    if ins.condition is None:
        asm = '  ' + asm
    elif ins.condition:
        asm = on('✔ ') + asm
    else:
        asm = '  ' + asm

    return asm
Ejemplo n.º 6
0
def instruction(ins):
    asm = '%-06s %s' % (ins.mnemonic, ins.op_str)
    # TODO: detect 'arm', 'x86,64' is only for Intel x86/64
    _highlighted, asm = pwndbg.color.syntax_highlight(asm, language='ARM')
    is_branch = set(ins.groups) & capstone_branch_groups

    # Highlight the current line if enabled
    if pwndbg.config.highlight_pc and ins.address == pwndbg.regs.pc:
        asm = C.highlight(asm)

    # tl;dr is a branch?
    if ins.target not in (None, ins.address + ins.size):
        sym = pwndbg.symbol.get(ins.target) or None
        target = M.get(ins.target)
        const = ins.target_const
        hextarget = hex(ins.target)
        hexlen = len(hextarget)

        # If it's a constant expression, color it directly in the asm.
        if const:
            asm = asm.replace(hex(ins.target), sym or target)

            if sym:
                asm = '%s <%s>' % (ljust_colored(asm, 36), target)

        # It's not a constant expression, but we've calculated the target
        # address by emulation.
        elif sym:
            asm = '%s <%s; %s>' % (ljust_colored(asm, 36), target, sym)

        # We were able to calculate the target, but there is no symbol
        # name for it.
        else:
            asm += '<%s>' % (target)

    # not a branch
    elif ins.symbol:
        if is_branch and not ins.target:
            asm = '%s <%s>' % (asm, ins.symbol)

            # XXX: not sure when this ever happens
            asm += '<-- file a pwndbg bug for this'
        else:
            asm = asm.replace(hex(ins.symbol_addr), ins.symbol)
            asm = '%s <%s>' % (ljust_colored(asm, 36), M.get(ins.symbol_addr))

    # Style the instruction mnemonic if it's a branch instruction.
    if is_branch:
        asm = asm.replace(ins.mnemonic, branch(ins.mnemonic), 1)

    # If we know the conditional is taken, mark it as green.
    if ins.condition is None:
        asm = '  ' + asm
    elif ins.condition:
        asm = green('✔ ') + asm
    else:
        asm = '  ' + asm

    return asm
Ejemplo n.º 7
0
def probeleak(address=None, count=0x40, max_distance=0x0):

    address = int(address)
    address &= pwndbg.arch.ptrmask
    ptrsize = pwndbg.arch.ptrsize
    count = max(int(count), ptrsize)
    off_zeros = int(math.ceil(math.log(count, 2) / 4))

    if count > address > 0x10000:  # in case someone puts in an end address and not a count (smh)
        print(
            message.warn(
                "Warning: you gave an end address, not a count. Substracting 0x%x from the count."
                % (address)))
        count -= address

    try:
        data = pwndbg.memory.read(address, count, partial=True)
    except gdb.error as e:
        print(message.error(str(e)))
        return

    if not data:
        print(
            message.error(
                "Couldn't read memory at 0x%x. See 'probeleak -h' for the usage."
                % (address, )))
        return

    found = False
    for i in range(0, len(data) - ptrsize + 1):
        p = pwndbg.arch.unpack(data[i:i + ptrsize])
        page = find_module(p, max_distance)
        if page:
            if not found:
                print(M.legend())
                found = True

            mod_name = page.objfile
            if not mod_name:
                mod_name = '[anon]'

            if p >= page.end:
                right_text = '(%s) %s + 0x%x + 0x%x (outside of the page)' % (
                    page.permstr, mod_name, page.memsz, p - page.end)
            elif p < page.start:
                right_text = '(%s) %s - 0x%x (outside of the page)' % (
                    page.permstr, mod_name, page.start - p)
            else:
                right_text = '(%s) %s + 0x%x' % (page.permstr, mod_name,
                                                 p - page.start)

            offset_text = '0x%0*x' % (off_zeros, i)
            p_text = '0x%0*x' % (int(ptrsize * 2), p)
            print('%s: %s = %s' % (offset_text, M.get(
                p, text=p_text), M.get(p, text=right_text)))
    if not found:
        print(
            message.hint('No leaks found at 0x%x-0x%x :(' %
                         (address, address + count)))
Ejemplo n.º 8
0
def print_line(name, addr, first, second, op, width=20):

    print("{} {} = {} {} {:#x}".format(
        name.rjust(width),
        M.get(addr),
        M.get(first) if not isinstance(first, str) else first.ljust(
            len(hex(addr).rstrip('L'))),
        op,
        second,
    ))
Ejemplo n.º 9
0
def probeleak(address=None, count=0x40, max_distance=0x0):

    address = int(address)
    address &= pwndbg.arch.ptrmask
    ptrsize = pwndbg.arch.ptrsize
    count   = max(int(count), ptrsize)
    off_zeros = int(math.ceil(math.log(count,2)/4))

    if count > address > 0x10000: # in case someone puts in an end address and not a count (smh)
        print(message.warn("Warning: you gave an end address, not a count. Substracting 0x%x from the count." % (address)))
        count -= address

    try:
        data = pwndbg.memory.read(address, count, partial=True)
    except gdb.error as e:
        print(message.error(str(e)))
        return

    if not data:
        print(message.error("Couldn't read memory at 0x%x. See 'probeleak -h' for the usage." % (address,)))
        return

    found = False
    for i in range(0, len(data) - ptrsize + 1):
        p = pwndbg.arch.unpack(data[i:i+ptrsize])
        page = find_module(p, max_distance)
        if page:
            if not found:
                print(M.legend())
                found = True

            mod_name = page.objfile
            if not mod_name:
                mod_name = '[anon]'

            if p >= page.end:
                right_text = '(%s) %s + 0x%x + 0x%x (outside of the page)' % (page.permstr, mod_name, page.memsz, p - page.end)
            elif p < page.start:
                right_text = '(%s) %s - 0x%x (outside of the page)' % (page.permstr, mod_name, page.start - p)
            else:
                right_text = '(%s) %s + 0x%x' % (page.permstr, mod_name, p - page.start)

            offset_text = '0x%0*x' % (off_zeros, i)
            p_text = '0x%0*x' % (int(ptrsize*2), p)
            text = '%s: %s = %s' % (offset_text, M.get(p, text=p_text), M.get(p, text=right_text))

            symbol = pwndbg.symbol.get(p)
            if symbol:
                text += ' (%s)' % symbol

            print(text)

    if not found:
        print(message.hint('No leaks found at 0x%x-0x%x :(' % (address, address+count)))
Ejemplo n.º 10
0
def malloc_chunk(addr):
    """
    Prints out the malloc_chunk at the specified address.
    """
    main_heap = pwndbg.heap.current

    if not isinstance(addr, six.integer_types):
        addr = int(addr)

    chunk = value_from_type('struct malloc_chunk', addr)
    size = int(chunk['size'])
    actual_size = size & ~7
    prev_inuse, is_mmapped, non_main_arena = main_heap.chunk_flags(size)
    arena = None
    if non_main_arena:
        arena = main_heap.get_heap(addr)['ar_ptr']

    fastbins = main_heap.fastbins(arena)
    header = M.get(addr)
    if prev_inuse:
        if actual_size in fastbins:
            header += yellow(' FASTBIN')
        else:
            header += yellow(' PREV_INUSE')
    if is_mmapped:
        header += yellow(' IS_MMAPED')
    if non_main_arena:
        header += yellow(' NON_MAIN_ARENA')
    print(header, chunk)

    return chunk
Ejemplo n.º 11
0
def malloc_chunk(addr, fake=False):
    """
    Prints out the malloc_chunk at the specified address.
    """
    main_heap = pwndbg.heap.current

    if not isinstance(addr, six.integer_types):
        addr = int(addr)

    chunk = read_chunk(addr)
    size = int(chunk['size'])
    actual_size = size & ~7
    prev_inuse, is_mmapped, non_main_arena = main_heap.chunk_flags(size)
    arena = None
    if not fake and non_main_arena:
        arena = main_heap.get_heap(addr)['ar_ptr']

    fastbins = [] if fake else main_heap.fastbins(arena)
    header = M.get(addr)
    if fake:
        header += message.prompt(' FAKE')
    if prev_inuse:
        if actual_size in fastbins:
            header += message.hint(' FASTBIN')
        else:
            header += message.hint(' PREV_INUSE')
    if is_mmapped:
        header += message.hint(' IS_MMAPED')
    if non_main_arena:
        header += message.hint(' NON_MAIN_ARENA')
    print(header, chunk["value"])

    return chunk
Ejemplo n.º 12
0
def format(value,
           limit=LIMIT,
           code=True,
           offset=0,
           hard_stop=None,
           hard_end=0):
    """
    Recursively dereferences an address into string representation, or convert the list representation
    of address dereferences into string representation.

    Arguments:
        value(int|list): Either the starting address to be sent to get, or the result of get (a list)
        limit(int): Number of valid pointers
        code(bool): Hint that indicates the value may be an instruction
        offset(int): Offset into the address to get the next pointer
        hard_stop(int): Value to stop on
        hard_end: Value to append when hard_stop is reached: null, value of hard stop, a string.

    Returns:
        A string representing pointers of each address and reference
        Strings format: 0x0804a10 —▸ 0x08061000 ◂— 0x41414141
    """
    limit = int(limit) + 1

    # Allow results from get function to be passed to format
    if type(value) == list:
        chain = value
    else:
        chain = get(value, limit, offset, hard_stop, hard_end)

    arrow_left = C.arrow(' %s ' % config_arrow_left)
    arrow_right = C.arrow(' %s ' % config_arrow_right)

    # Enhance the last entry
    # If there are no pointers (e.g. eax = 0x41414141), then enhance
    # the only element there is.
    if len(chain) == 1:
        enhanced = pwndbg.enhance.enhance(chain[-1], code=code)

    # Otherwise, the last element in the chain is the non-pointer value.
    # We want to enhance the last pointer value. If an offset was used
    # chain failed at that offset, so display that offset.
    elif len(chain) < limit:
        enhanced = pwndbg.enhance.enhance(chain[-2] + offset, code=code)

    else:
        enhanced = C.contiguous('%s' % config_contiguous)

    # Colorize the rest
    rest = []
    for link in chain[:-1]:
        symbol = pwndbg.symbol.get(link) or None
        if symbol:
            symbol = '%#x (%s)' % (link, symbol)
        rest.append(M.get(link, symbol))

    if len(chain) == 1:
        return enhanced

    return arrow_right.join(rest) + arrow_left + enhanced
Ejemplo n.º 13
0
def format(value, limit=LIMIT, code=True, offset=0):
    chain = get(value, limit, offset)
    arrow_left  = C.arrow(' %s ' % config_arrow_left)
    arrow_right = C.arrow(' %s ' % config_arrow_right)

    # Enhance the last entry
    # If there are no pointers (e.g. eax = 0x41414141), then enhance
    # the only element there is.
    if len(chain) == 1:
        enhanced = pwndbg.enhance.enhance(chain[-1], code=code)

    # Otherwise, the last element in the chain is the non-pointer value.
    # We want to enhance the last pointer value.
    elif len(chain) < limit:
        enhanced = pwndbg.enhance.enhance(chain[-2], code=code)

    else:
        enhanced = C.contiguous('%s' % config_contiguous)

    # Colorize the rest
    rest = []
    for link in chain[:-1]:
        symbol = pwndbg.symbol.get(link) or None
        if symbol:
            symbol = '%#x (%s)' % (link, symbol)
        rest.append(M.get(link, symbol))

    if len(chain) == 1:
        return enhanced

    return arrow_right.join(rest) + arrow_left + enhanced
Ejemplo n.º 14
0
def xinfo_mmap_file(page, addr):
    # If it's an address pointing into a memory mapped file, print offsets
    # to beginning of file in memory and on disk

    file_name = page.objfile
    objpages = filter(lambda p: p.objfile == file_name, pwndbg.vmmap.get())
    first = sorted(objpages, key = lambda p: p.vaddr)[0]

    # print offset from ELF base load address
    rva = addr - first.vaddr
    print_line("File (Base)", addr, first.vaddr, rva, "+")

    # find possible LOAD segments that designate memory and file backings
    containing_loads = [seg for seg in pwndbg.elf.get_containing_segments(file_name, first.vaddr, addr)
                        if seg['p_type'] == 'PT_LOAD']

    for segment in containing_loads:
        if segment['p_type'] == 'PT_LOAD' and addr < segment['x_vaddr_mem_end']:
            offset = addr - segment['p_vaddr']
            print_line('File (Segment)', addr, segment['p_vaddr'], offset, '+')
            break

    for segment in containing_loads:
        if segment['p_type'] == 'PT_LOAD' and addr < segment['x_vaddr_file_end']:
            file_offset = segment['p_offset'] + (addr - segment['p_vaddr'])
            print_line("File (Disk)", addr, file_name, file_offset, "+")
            break
    else:
        print('{} {} = [not file backed]'.format('File (Disk)'.rjust(20), M.get(addr)))

    containing_sections = pwndbg.elf.get_containing_sections(file_name, first.vaddr, addr)
    if len(containing_sections) > 0:
        print('\n Containing ELF sections:')
        for sec in containing_sections:
            print_line(sec['x_name'], addr, sec['sh_addr'], addr - sec['sh_addr'], '+')
Ejemplo n.º 15
0
Archivo: xinfo.py Proyecto: ysf/pwndbg
def xinfo_mmap_file(page, addr):
    # If it's an address pointing into a memory mapped file, print offsets
    # to beginning of file in memory and on disk

    file_name = page.objfile
    objpages = filter(lambda p: p.objfile == file_name, pwndbg.vmmap.get())
    first = sorted(objpages, key = lambda p: p.vaddr)[0]

    # print offset from ELF base load address
    rva = addr - first.vaddr
    print_line("File (Base)", addr, first.vaddr, rva, "+")

    # find possible LOAD segments that designate memory and file backings
    containing_loads = [seg for seg in pwndbg.elf.get_containing_segments(file_name, first.vaddr, addr)
                        if seg['p_type'] == 'PT_LOAD']

    for segment in containing_loads:
        if segment['p_type'] == 'PT_LOAD' and addr < segment['x_vaddr_mem_end']:
            offset = addr - segment['p_vaddr']
            print_line('File (Segment)', addr, segment['p_vaddr'], offset, '+')
            break

    for segment in containing_loads:
        if segment['p_type'] == 'PT_LOAD' and addr < segment['x_vaddr_file_end']:
            file_offset = segment['p_offset'] + (addr - segment['p_vaddr'])
            print_line("File (Disk)", addr, file_name, file_offset, "+")
            break
    else:
        print('{} {} = [not file backed]'.format('File (Disk)'.rjust(20), M.get(addr)))

    containing_sections = pwndbg.elf.get_containing_sections(file_name, first.vaddr, addr)
    if len(containing_sections) > 0:
        print('\n Containing ELF sections:')
        for sec in containing_sections:
            print_line(sec['x_name'], addr, sec['sh_addr'], addr - sec['sh_addr'], '+')
Ejemplo n.º 16
0
def malloc_chunk(addr,fake=False):
    """
    Prints out the malloc_chunk at the specified address.
    """
    main_heap = pwndbg.heap.current

    if not isinstance(addr, six.integer_types):
        addr = int(addr)

    chunk = read_chunk(addr)
    size = int(chunk['size'])
    actual_size = size & ~7
    prev_inuse, is_mmapped, non_main_arena = main_heap.chunk_flags(size)
    arena = None
    if not fake and non_main_arena:
        arena = main_heap.get_heap(addr)['ar_ptr']

    fastbins = [] if fake else main_heap.fastbins(arena)
    header = M.get(addr)
    if fake:
        header += message.prompt(' FAKE')
    if prev_inuse:
        if actual_size in fastbins:
            header += message.hint(' FASTBIN')
        else:
            header += message.hint(' PREV_INUSE')
    if is_mmapped:
        header += message.hint(' IS_MMAPED')
    if non_main_arena:
        header += message.hint(' NON_MAIN_ARENA')
    print(header, chunk["value"])

    return chunk
Ejemplo n.º 17
0
def format(value, limit=LIMIT, code=True, offset=0):
    chain = get(value, limit, offset)
    arrow_left = C.arrow(' %s ' % config_arrow_left)
    arrow_right = C.arrow(' %s ' % config_arrow_right)

    # Enhance the last entry
    # If there are no pointers (e.g. eax = 0x41414141), then enhance
    # the only element there is.
    if len(chain) == 1:
        enhanced = pwndbg.enhance.enhance(chain[-1], code=code)

    # Otherwise, the last element in the chain is the non-pointer value.
    # We want to enhance the last pointer value.
    elif len(chain) < limit:
        enhanced = pwndbg.enhance.enhance(chain[-2], code=code)

    else:
        enhanced = C.contiguous('%s' % config_contiguous)

    # Colorize the rest
    rest = []
    for link in chain[:-1]:
        symbol = pwndbg.symbol.get(link) or None
        if symbol:
            symbol = '%#x (%s)' % (link, symbol)
        rest.append(M.get(link, symbol))

    if len(chain) == 1:
        return enhanced

    return arrow_right.join(rest) + arrow_left + enhanced
Ejemplo n.º 18
0
def minfo(address=None):
    pages = pwndbg.vmmap.get()
    prev_end = 0

    print(M.legend())
    for page in pages:
        if prev_end < page.vaddr:
            print(short_page_str(pwndbg.memory.Page(prev_end, page.vaddr - prev_end, 0, 0, '(empty)')))
        prev_end = page.vaddr + page.memsz
        print(M.get(page.vaddr, text=short_page_str(page)))
Ejemplo n.º 19
0
def vmmap(pages_filter=None):
    pages = list(filter(pages_filter, pwndbg.vmmap.get()))

    if not pages:
        print('There are no mappings for specified address or module.')
        return

    print(M.legend())
    for page in pages:
        print(M.get(page.vaddr, text=str(page)))
Ejemplo n.º 20
0
def print_chunk_detail(addr, size):
    def get_type(size):
        return {
            4: pwndbg.typeinfo.uint32,
            8: pwndbg.typeinfo.uint64,
        }[size]

    def enhex(size, value, fill=True):
        value = value & pwndbg.arch.ptrmask
        x = "%x" % abs(value)
        if fill:
            x = x.rjust(size * 2, '0')
        return x

    values = []
    address = addr & pwndbg.arch.ptrmask
    type = get_type(pwndbg.arch.ptrsize)
    count = int((size & ~7) / pwndbg.arch.ptrsize)

    for i in range(count):
        try:
            gval = pwndbg.memory.poi(type, address + i * pwndbg.arch.ptrsize)
            values.append(int(gval))
        except gdb.MemoryError:
            break

    n_rows = int(math.ceil(count * pwndbg.arch.ptrsize / float(16)))
    row_sz = 2
    rows = [values[i * row_sz:(i + 1) * row_sz] for i in range(n_rows)]
    lines = []

    repeat_row = None
    appended = False
    for i, row in enumerate(rows):
        if not row:
            continue
        if row == repeat_row and size > 0x100 and i != len(rows) - 1:
            if not appended:
                lines.append('.' * 6)
                appended = True
            continue
        if i == 0:
            line = [M.get(address), '   ']
        else:
            line = [
                '0x' +
                enhex(pwndbg.arch.ptrsize, address + (i * 16), fill=False),
                '   '
            ]
        for value in row:
            line.append(enhex(pwndbg.arch.ptrsize, value))
        lines.append(' '.join(line))
        repeat_row = row
        appended = False
    print('\n'.join(lines))
Ejemplo n.º 21
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)
Ejemplo n.º 22
0
def print_search_hit(address):
    """Prints out a single search hit.

    Arguments:
        address(int): Address to print
    """
    if not address:
        return

    vmmap = pwndbg.vmmap.find(address)
    if vmmap:
        region = os.path.basename(vmmap.objfile)
    else:
        region = '[mapped]'

    region = region.ljust(15)

    region = M.get(address, region)
    addr = M.get(address)
    display = pwndbg.enhance.enhance(address)
    print(region, addr, display)
Ejemplo n.º 23
0
def print_search_hit(address):
    """Prints out a single search hit.

    Arguments:
        address(int): Address to print
    """
    if not address:
        return

    vmmap = pwndbg.vmmap.find(address)
    if vmmap:
        region = os.path.basename(vmmap.objfile)
    else:
        region = '[mapped]'

    region = region.ljust(15)

    region = M.get(address, region)
    addr = M.get(address)
    display = pwndbg.enhance.enhance(address)
    print(region,addr,display)
Ejemplo n.º 24
0
def vmmap(pages_filter=None):
    pages = list(filter(pages_filter, pwndbg.vmmap.get()))

    if not pages:
        print('There are no mappings for specified address or module.')
        return

    print(M.legend())
    for page in pages:
        print(M.get(page.vaddr, text=str(page)))

    if pwndbg.qemu.is_qemu():
        print("\n[QEMU target detected - vmmap result might not be accurate; see `help vmmap`]")
Ejemplo n.º 25
0
def xinfo(address=None):
    addr = int(address)
    addr &= pwndbg.arch.ptrmask

    page = pwndbg.vmmap.find(addr)

    if page is None:
        print("\n  Virtual address {:#x} is not mapped.".format(addr))
        return

    print("Extended information for virtual address {}:".format(M.get(addr)))

    print("\n  Containing mapping:")
    print(M.get(address, text=str(page)))

    print("\n  Offset information:")

    if page.is_stack:
        xinfo_stack(page, addr)
    else:
        xinfo_default(page, addr)

    if page.is_memory_mapped_file:
        xinfo_mmap_file(page, addr)
Ejemplo n.º 26
0
def heap(addr=None):
    """
    Prints out all chunks in the main_arena, or the arena specified by `addr`.
    """

    main_heap = pwndbg.heap.current
    main_arena = main_heap.get_arena(addr)

    if main_arena is None:
        return

    heap_region = main_heap.get_region(addr)

    if heap_region is None:
        print(red('Could not find the heap'))
        return

    top = main_arena['top']
    last_remainder = main_arena['last_remainder']

    print(bold('Top Chunk: ') + M.get(top))
    print(bold('Last Remainder: ') + M.get(last_remainder))
    print()

    # Print out all chunks on the heap
    # TODO: Add an option to print out only free or allocated chunks
    addr = heap_region.vaddr
    while addr <= top:
        chunk = malloc_chunk(addr)
        size = int(chunk['size'])

        # Clear the bottom 3 bits
        size &= ~7
        if size == 0:
            break
        addr += size
Ejemplo n.º 27
0
def print_search(value, *a, **kw):
    hits = set()

    for address in pwndbg.search.search(value, *a, **kw):
        if not address:
            continue

        if address in hits:
            continue

        hits.add(address)

        vmmap = pwndbg.vmmap.find(address)
        if vmmap:
            region = os.path.basename(vmmap.objfile)
        else:
            region = '[mapped]'

        region = region.ljust(15)

        region = M.get(address, region)
        addr = M.get(address)
        display = pwndbg.enhance.enhance(address)
        print(region,addr,display)
Ejemplo n.º 28
0
def locate(address=0x0):
    if address == 0x0:
        print("Invalid argument provided. Please give a valid address such as 0x")
        return
    pages = list(filter(None, pwndbg.vmmap.get()))
    print(M.legend())

    
    for page in pages:
        if address >= page.vaddr and address <= page.vaddr + page.memsz:
            texta = str(page) + " + " + hex(int(address-page.vaddr))
            print(M.get(page.vaddr, text=texta))

    if pwndbg.qemu.is_qemu():
        print("\n[QEMU target detected - locate result might not be accurate; see `help vmmap`]")
Ejemplo n.º 29
0
def malloc_chunk(addr, fake=False):
    """
    Prints out the malloc_chunk at the specified address.
    """
    main_heap = pwndbg.heap.current

    if not isinstance(addr, six.integer_types):
        addr = int(addr)

    chunk = read_chunk(addr)
    size = int(chunk['size'])
    actual_size = size & ~7
    prev_inuse, is_mmapped, non_main_arena = main_heap.chunk_flags(size)
    arena = None
    if not fake and non_main_arena:
        arena = main_heap.get_heap(addr)['ar_ptr']

    fastbins = [] if fake else main_heap.fastbins(arena)
    header = M.get(addr)
    if fake:
        header += message.prompt(' FAKE')
    if prev_inuse:
        if actual_size in fastbins:
            header += message.hint(' FASTBIN')
        else:
            header += message.hint(' PREV_INUSE')
    if is_mmapped:
        header += message.hint(' IS_MMAPED')
    if non_main_arena:
        header += message.hint(' NON_MAIN_ARENA')
    ## edit start
    chunk_str = '{\n'
    for key in chunk["value"].type.keys():
        if (str(key) == "prev_size" or str(key) == "size"):
            chunk_str += '  %s = %s [%s]\n' % (str(key),
                                               hex(int(chunk["value"][key])),
                                               int(chunk["value"][key]))
        else:
            chunk_str += '  %s = %s\n' % (str(key),
                                          hex(int(chunk["value"][key])))
    chunk_str += '}'

    print(header, chunk_str)
    ## edit end

    return chunk
Ejemplo n.º 30
0
def probeleak(address=None, count=0x40):

    address = int(address)
    address &= pwndbg.arch.ptrmask
    count   = max(int(count), 0)
    ptrsize = pwndbg.arch.ptrsize
    off_zeros = int(math.ceil(math.log(count,2)/4))

    if count > address > 0x10000: # in case someone puts in an end address and not a count (smh)
        count -= address

    if count % ptrsize > 0:
        newcount = count - (count % ptrsize)
        print(message.warning("Warning: count 0x%x is not a multiple of 0x%x; truncating to 0x%x." % (count, ptrsize, newcount)))
        count = newcount

    try:
        data = pwndbg.memory.read(address, count, partial=True)
    except gdb.error as e:
        print(message.error(str(e)))
        return

    if not data:
        print(message.error("Couldn't read memory at 0x%x" % (address,)))
        return

    found = False
    for i in range(0, count, ptrsize):
        p = pwndbg.arch.unpack(data[i:i+ptrsize])
        page = find_module(p)
        if page:
            if not found:
                print(M.legend())
                found = True

            mod_name = page.objfile
            if not mod_name:
                mod_name = '[anon]'
            fmt = '+0x{offset:0{n1}x}: 0x{ptr:0{n2}x} = {page}'
            right_text = ('(%s) %s + 0x%x') % (page.permstr, mod_name, p - page.vaddr + page.offset)
            print(fmt.format(n1=off_zeros, n2=ptrsize*2, offset=i, ptr=p, page=M.get(p, text=right_text)))
    if not found:
        print(message.hint('No leaks found at 0x{:x}-0x{:x} :('.format(address, address+count)))
Ejemplo n.º 31
0
def get_rec_addr_string(addr,visited_map):
    page = pwndbg.vmmap.find(addr)
    arrow_right = C.arrow(' %s ' % config_arrow_right)

    if not page is None:
        if not addr in visited_map:
            return ""
        
        parent_info = visited_map[addr]
        parent = parent_info[0]
        parent_base_addr = parent_info[1]
        if parent - parent_base_addr < 0:
            curText = hex(parent_base_addr) + hex(parent - parent_base_addr)
        else:
            curText = hex(parent_base_addr) + "+" + hex(parent - parent_base_addr)
        if parent_base_addr == addr:
            return ""
        return get_rec_addr_string(parent_base_addr,visited_map) + M.get(parent_base_addr,text=curText) + arrow_right
    else:
        return ""
Ejemplo n.º 32
0
def vmmap(map=None):
    """
    Print the virtal memory map, or the specific mapping for the
    provided address / module name.
    """
    int_map = None
    str_map = None

    if isinstance(map, six.string_types):
        str_map = map
    elif isinstance(map, six.integer_types + (gdb.Value, )):
        int_map = int(map)

    print(M.legend())

    for page in pwndbg.vmmap.get():
        if str_map and str_map not in page.objfile:
            continue
        if int_map and int_map not in page:
            continue

        print(M.get(page.vaddr, text=str(page)))
Ejemplo n.º 33
0
def vmmap(map=None):
    """
    Print the virtal memory map, or the specific mapping for the
    provided address / module name.
    """
    int_map = None
    str_map = None

    if isinstance(map, six.string_types):
        str_map = map
    elif isinstance(map, six.integer_types + (gdb.Value,)):
        int_map = int(map)

    print(M.legend())

    for page in pwndbg.vmmap.get():
        if str_map and str_map not in page.objfile:
            continue
        if int_map and int_map not in page:
            continue

        print(M.get(page.vaddr, text=str(page)))
Ejemplo n.º 34
0
def malloc_chunk(addr):
    """
    Prints out the malloc_chunk at the specified address.
    """
    if not isinstance(addr, six.integer_types):
        addr = int(addr)

    chunk = value_from_type('struct malloc_chunk', addr)
    size = int(chunk['size'])
    prev_inuse = (size & PREV_INUSE) == 1
    is_mmaped = (size & IS_MMAPED) == 1
    non_main_arena = (size & NON_MAIN_ARENA) == 1

    header = M.get(addr)
    if prev_inuse:
        header += yellow(' PREV_INUSE')
    if is_mmaped:
        header += yellow(' IS_MMAPED')
    if non_main_arena:
        header += yellow(' NON_MAIN_ARENA')
    print(header)
    print(chunk)

    return chunk
Ejemplo n.º 35
0
def malloc_chunk(addr):
    """
    Prints out the malloc_chunk at the specified address.
    """
    if not isinstance(addr, six.integer_types):
        addr = int(addr)

    chunk = value_from_type('struct malloc_chunk', addr)
    size = int(chunk['size'])
    prev_inuse = (size & PREV_INUSE) == 1
    is_mmaped = (size & IS_MMAPED) == 1
    non_main_arena = (size & NON_MAIN_ARENA) == 1

    header = M.get(addr)
    if prev_inuse:
        header += yellow(' PREV_INUSE')
    if is_mmaped:
        header += yellow(' IS_MMAPED')
    if non_main_arena:
        header += yellow(' NON_MAIN_ARENA')
    print(header)
    print(chunk)

    return chunk
Ejemplo n.º 36
0
def leakfind(address=None,
             page_name=None,
             max_offset=0x40,
             max_depth=0x4,
             stride=0x1,
             negative_offset=0x0):
    if address is None:
        raise argparse.ArgumentTypeError('No starting address provided.')

    foundPages = pwndbg.vmmap.find(address)

    if not foundPages:
        raise argparse.ArgumentTypeError('Starting address is not mapped.')

    if not pwndbg.memory.peek(address):
        raise argparse.ArgumentTypeError(
            'Unable to read from starting address.')

    max_depth = int(max_depth)
    # Just warn the user that a large depth might be slow.
    # Probably worth checking offset^depth < threshold. Do this when more benchmarking is established.
    if max_depth > 8:
        print("leakfind may take a while to run on larger depths.")

    stride = int(stride)
    address = int(address)
    max_offset = int(max_offset)
    negative_offset = int(negative_offset)

    # The below map stores a map of child address->(parent_address,parent_start_address)
    # In the above tuple, parent_address is the exact address with a pointer to the child adddress.
    # parent_start_address is an address that a previous address pointed to.
    # We need to store both so that we can nicely create our leak chain.
    visited_map = {}
    visited_set = {int(address)}
    address_queue = Queue()
    address_queue.put(int(address))
    depth = 0
    time_to_depth_increase = 0

    # Run a bfs
    # TODO look into performance gain from checking if an address is mapped before calling pwndbg.memory.pvoid()
    # TODO also check using pwndbg.memory.read for possible performance boosts.
    while address_queue.qsize() > 0 and depth < max_depth:
        if time_to_depth_increase == 0:
            depth = depth + 1
            time_to_depth_increase = address_queue.qsize()
        cur_start_addr = address_queue.get()
        time_to_depth_increase -= 1
        for cur_addr in range(cur_start_addr - negative_offset,
                              cur_start_addr + max_offset, stride):
            try:
                result = int(pwndbg.memory.pvoid(cur_addr))
                if result in visited_map or result in visited_set:
                    continue
                visited_map[result] = (
                    cur_addr, cur_start_addr
                )  # map is of form child->(parent,parent_start)
                address_queue.put(result)
                visited_set.add(result)
            except gdb.error:
                # That means the memory was unmapped. Just skip it if we can't read it.
                break

    # A map of length->list of lines. Used to let us print in a somewhat nice manner.
    output_map = {}
    arrow_right = C.arrow(' %s ' % config_arrow_right)

    for child in visited_map:
        child_page = pwndbg.vmmap.find(child)
        if child_page is not None:
            if page_name is not None and page_name not in child_page.objfile:
                continue
            line = get_rec_addr_string(
                child, visited_map) + M.get(child) + " " + M.get(
                    child, text=child_page.objfile)
            chain_length = line.count(arrow_right)
            if chain_length in output_map:
                output_map[chain_length].append(line)
            else:
                output_map[chain_length] = [line]

    # Output sorted by length of chain
    for chain_length in output_map:
        for line in output_map[chain_length]:
            print(line)

    if pwndbg.qemu.is_qemu():
        print(
            "\n[QEMU target detected - leakfind result might not be accurate; see `help vmmap`]"
        )
Ejemplo n.º 37
0
def ds(address, max):
    address = int(address)
    address &= pwndbg.arch.ptrmask
    print(M.get(address), repr(pwndbg.strings.get(address, max, whatever=True)))
Ejemplo n.º 38
0
def format(value, limit=LIMIT, code=True, offset=0, hard_stop=None, hard_end=0):
    """
    Recursively dereferences an address into string representation, or convert the list representation
    of address dereferences into string representation.

    Arguments:
        value(int|list): Either the starting address to be sent to get, or the result of get (a list)
        limit(int): Number of valid pointers
        code(bool): Hint that indicates the value may be an instruction
        offset(int): Offset into the address to get the next pointer
        hard_stop(int): Value to stop on
        hard_end: Value to append when hard_stop is reached: null, value of hard stop, a string.

    Returns:
        A string representing pointers of each address and reference
        Strings format: 0x0804a10 —▸ 0x08061000 ◂— 0x41414141
    """
    limit = int(limit)

    # Allow results from get function to be passed to format
    if isinstance(value, list):
        chain = value
    else:
        chain = get(value, limit, offset, hard_stop, hard_end)

    arrow_left  = C.arrow(' %s ' % config_arrow_left)
    arrow_right = C.arrow(' %s ' % config_arrow_right)

    # Colorize the chain
    rest = []
    for link in chain:
        symbol = pwndbg.symbol.get(link) or None
        if symbol:
            symbol = '%#x (%s)' % (link, symbol)
        rest.append(M.get(link, symbol))

    # If the dereference limit is zero, skip any enhancements.
    if limit == 0:
        return rest[0]
    # Otherwise replace last element with the enhanced information.
    rest = rest[:-1]

    # Enhance the last entry
    # If there are no pointers (e.g. eax = 0x41414141), then enhance
    # the only element there is.
    if len(chain) == 1:
        enhanced = pwndbg.enhance.enhance(chain[-1], code=code)

    # Otherwise, the last element in the chain is the non-pointer value.
    # We want to enhance the last pointer value. If an offset was used
    # chain failed at that offset, so display that offset.
    elif len(chain) < limit + 1:
        enhanced = pwndbg.enhance.enhance(chain[-2] + offset, code=code)

    else:
        enhanced = C.contiguous('%s' % config_contiguous)

    if len(chain) == 1:
        return enhanced

    return arrow_right.join(rest) + arrow_left + enhanced
Ejemplo n.º 39
0
Archivo: heap.py Proyecto: 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)
Ejemplo n.º 40
0
def print_line(name, addr, first, second, op, width = 20):

    print("{} {} = {} {} {:#x}".format(name.rjust(width), M.get(addr),
        M.get(first) if type(first) is not str else first.ljust(len(hex(addr))),
        op, second,))
Ejemplo n.º 41
0
def instruction(ins):
    asm = '%-06s %s' % (ins.mnemonic, ins.op_str)
    if pwndbg.config.syntax_highlight:
        asm = syntax_highlight(asm)
    is_branch = set(ins.groups) & capstone_branch_groups

    # Highlight the current line if enabled
    if pwndbg.config.highlight_pc and ins.address == pwndbg.regs.pc:
        asm = C.highlight(asm)

    # tl;dr is a branch?
    if ins.target not in (None, ins.address + ins.size):
        sym    = pwndbg.symbol.get(ins.target) or None
        target = M.get(ins.target)
        const  = ins.target_const

        # Use format string instead of hex() to avoid suffix 'l' or 'L'
        hextarget = '0x%x' % ins.target
        hexlen    = len(hextarget)

        # If it's a constant expression, color it directly in the asm.
        if const:
            # TODO: Also colorize the address starts with '$' and '#'
            asm = asm.replace(hextarget, sym or target)

            if sym:
                asm = '%s <%s>' % (ljust_colored(asm, 36), target)

        # It's not a constant expression, but we've calculated the target
        # address by emulation.
        elif sym:
            asm = '%s <%s; %s>' % (ljust_colored(asm, 36), target, sym)

        # We were able to calculate the target, but there is no symbol
        # name for it.
        else:
            asm += '<%s>' % (target)

    # not a branch
    elif ins.symbol:
        if is_branch and not ins.target:
            asm = '%s <%s>' % (asm, ins.symbol)

            # XXX: not sure when this ever happens
            asm += '<-- file a pwndbg bug for this'
        else:
            asm = asm.replace(hex(ins.symbol_addr), ins.symbol)
            asm = '%s <%s>' % (ljust_colored(asm, 36), M.get(ins.symbol_addr))

    # Style the instruction mnemonic if it's a branch instruction.
    if is_branch:
        asm = asm.replace(ins.mnemonic, branch(ins.mnemonic), 1)

    # If we know the conditional is taken, mark it as taken.
    if ins.condition is None:
        asm = '  ' + asm
    elif ins.condition:
        asm = on('✔ ') + asm
    else:
        asm = '  ' + asm

    return asm
Ejemplo n.º 42
0
def print_line(name, addr, first, second, op, width = 20):

    print("{} {} = {} {} {:#x}".format(name.rjust(width), M.get(addr),
        M.get(first) if not isinstance(first, str) else first.ljust(len(hex(addr).rstrip('L'))),
        op, second,))