Esempio n. 1
0
def context_expressions(target=sys.stdout, with_banner=True, width=None):
    if not expressions:
        return []
    banner = [pwndbg.ui.banner("expressions", target=target, width=width)]
    output = []
    if width is None:
        _height, width = pwndbg.ui.get_window_size(target=target)
    for exp, cmd in sorted(expressions):
        try:
            # value = gdb.parse_and_eval(exp)
            value = str(cmd(exp))
        except gdb.error as err:
            value = str(err)
        value = value.split("\n")
        lines = []
        for line in value:
            if width and len(line) + len(exp) + 3 > width:
                n = width - (len(exp) + 3) - 1  # 1 Padding...
                lines.extend(line[i:i + n] for i in range(0, len(line), n))
            else:
                lines.append(line)

        fmt = C.highlight(exp)
        lines[0] = "{} = {}".format(fmt, lines[0])
        lines[1:] = [" " * (len(exp) + 3) + line for line in lines[1:]]
        output.extend(lines)
    return banner + output if with_banner else output
Esempio n. 2
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
Esempio n. 3
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
Esempio n. 4
0
def get_filename_and_formatted_source():
    """
    Returns formatted, lines limited and highlighted source as list
    or if it isn't there - an empty list
    """
    sal = gdb.selected_frame().find_sal()  # gdb.Symtab_and_line

    # Check if source code is available
    if sal.symtab is None:
        return "", []

    # Get the full source code
    closest_line = sal.line
    filename = sal.symtab.fullname()

    try:
        source = get_highlight_source(filename)
    except IOError:
        return "", []

    if not source:
        return "", []

    n = int(source_code_lines)

    # Compute the line range
    start = max(closest_line - 1 - n // 2, 0)
    end = min(closest_line - 1 + n // 2 + 1, len(source))
    num_width = len(str(end))

    # split the code
    source = source[start:end]

    # Compute the prefix_sign length
    prefix_sign = pwndbg.config.code_prefix
    prefix_width = len(prefix_sign)

    # Format the output
    formatted_source = []
    for line_number, code in enumerate(source, start=start + 1):
        fmt = " {prefix_sign:{prefix_width}} {line_number:>{num_width}} {code}"
        if pwndbg.config.highlight_source and line_number == closest_line:
            fmt = C.highlight(fmt)

        line = fmt.format(
            prefix_sign=C.prefix(prefix_sign)
            if line_number == closest_line else "",
            prefix_width=prefix_width,
            line_number=line_number,
            num_width=num_width,
            code=code,
        )
        formatted_source.append(line)

    return filename, formatted_source
Esempio n. 5
0
def context_code():
    try:
        symtab = gdb.selected_frame().find_sal().symtab
        linetable = symtab.linetable()

        closest_pc = -1
        closest_line = -1
        for line in linetable:
            if line.pc <= pwndbg.regs.pc and line.pc > closest_pc:
                closest_line = line.line
                closest_pc = line.pc

        if closest_line < 0:
            return []

        source = gdb.execute('list %i' % closest_line,
                             from_tty=False,
                             to_string=True)

        # If it starts on line 1, it's not really using the
        # correct source code.
        if not source or closest_line <= 1:
            return []

        # highlight the current code line
        source_lines = source.splitlines()
        if pwndbg.config.highlight_source:
            for i in range(len(source_lines)):
                if source_lines[i].startswith('%s\t' % closest_line):
                    source_lines[i] = C.highlight(source_lines[i])
                    break

        banner = [pwndbg.ui.banner("source")]
        banner.extend(source_lines)
        return banner
    except:
        pass

    if not pwndbg.ida.available():
        return []

    try:
        name = pwndbg.ida.GetFunctionName(pwndbg.regs.pc)
        addr = pwndbg.ida.LocByName(name)
        lines = pwndbg.ida.decompile(addr)
        return lines.splitlines()
    except:
        pass

    return []
Esempio n. 6
0
def context_source():
    try:
        symtab = gdb.selected_frame().find_sal().symtab
        linetable = symtab.linetable()

        closest_pc = -1
        closest_line = -1
        for line in linetable:
            if line.pc <= pwndbg.regs.pc and line.pc > closest_pc:
                closest_line = line.line
                closest_pc   = line.pc

        if closest_line < 0:
            return []

        source = gdb.execute('list %i' % closest_line, from_tty=False, to_string=True)

        # If it starts on line 1, it's not really using the
        # correct source code.
        if not source or closest_line <= 1:
            return []

        # highlight the current code line
        source_lines = source.splitlines()
        if pwndbg.config.highlight_source:
            for i in range(len(source_lines)):
                if source_lines[i].startswith('%s\t' % closest_line):
                    source_lines[i] = C.highlight(source_lines[i])
                    break

        banner = [pwndbg.ui.banner("code")]
        banner.extend(source_lines)
        return banner
    except:
        pass

    if not pwndbg.ida.available():
        return []

    try:
        name = pwndbg.ida.GetFunctionName(pwndbg.regs.pc)
        addr = pwndbg.ida.LocByName(name)
        lines = pwndbg.ida.decompile(addr)
        return lines.splitlines()
    except:
        pass

    return []
Esempio n. 7
0
File: nearpc.py Progetto: ysf/pwndbg
def nearpc(pc=None, lines=None, to_string=False, emulate=False):
    """
    Disassemble near a specified address.
    """

    # Repeating nearpc (pressing enter) makes it show next addresses
    # (writing nearpc explicitly again will reset its state)
    if nearpc.repeat:
        pc = nearpc.next_pc

    result = []

    # Fix the case where we only have one argument, and
    # it's a small value.
    if lines is None and (pc is None or int(pc) < 0x100):
        lines = pc
        pc = None

    if pc is None:
        pc = pwndbg.regs.pc

    if lines is None:
        lines = nearpc_lines // 2

    pc = int(pc)
    lines = int(lines)

    # Check whether we can even read this address
    if not pwndbg.memory.peek(pc):
        result.append(message.error('Invalid address %#x' % pc))

    # # Load source data if it's available
    # pc_to_linenos = collections.defaultdict(lambda: [])
    # lineno_to_src = {}
    # frame = gdb.selected_frame()
    # if frame:
    #     sal = frame.find_sal()
    #     if sal:
    #         symtab = sal.symtab
    #         objfile = symtab.objfile
    #         sourcefilename = symtab.filename
    #         with open(sourcefilename, 'r') as sourcefile:
    #             lineno_to_src = {i:l for i,l in enumerate(sourcefile.readlines())}

    #         for line in symtab.linetable():
    #             pc_to_linenos[line.pc].append(line.line)
    instructions = pwndbg.disasm.near(pc,
                                      lines,
                                      emulate=emulate,
                                      show_prev_insns=not nearpc.repeat)

    if pwndbg.memory.peek(pc) and not instructions:
        result.append(message.error('Invalid instructions at %#x' % pc))

    # In case $pc is in a new map we don't know about,
    # this will trigger an exploratory search.
    pwndbg.vmmap.find(pc)

    # Gather all addresses and symbols for each instruction
    symbols = [pwndbg.symbol.get(i.address) for i in instructions]
    addresses = ['%#x' % i.address for i in instructions]

    nearpc.next_pc = instructions[-1].address + instructions[
        -1].size if instructions else 0

    # Format the symbol name for each instruction
    symbols = ['<%s> ' % sym if sym else '' for sym in symbols]

    # Pad out all of the symbols and addresses
    if pwndbg.config.left_pad_disasm and not nearpc.repeat:
        symbols = ljust_padding(symbols)
        addresses = ljust_padding(addresses)

    prev = None

    first_pc = True

    # Print out each instruction
    for address_str, symbol, instr in zip(addresses, symbols, instructions):
        asm = D.instruction(instr)
        prefix_sign = pwndbg.config.nearpc_prefix

        # Show prefix only on the specified address and don't show it while in repeat-mode
        # or when showing current instruction for the second time
        show_prefix = instr.address == pc and not nearpc.repeat and first_pc
        prefix = ' %s' % (prefix_sign if show_prefix else ' ' *
                          len(prefix_sign))
        prefix = N.prefix(prefix)

        pre = pwndbg.ida.Anterior(instr.address)
        if pre:
            result.append(N.ida_anterior(pre))

        # Colorize address and symbol if not highlighted
        # symbol is fetched from gdb and it can be e.g. '<main+8>'
        if instr.address != pc or not pwndbg.config.highlight_pc or nearpc.repeat:
            address_str = N.address(address_str)
            symbol = N.symbol(symbol)
        elif pwndbg.config.highlight_pc and first_pc:
            prefix = C.highlight(prefix)
            address_str = C.highlight(address_str)
            symbol = C.highlight(symbol)
            first_pc = False

        line = ' '.join((prefix, address_str, symbol, asm))

        # If there was a branch before this instruction which was not
        # contiguous, put in some ellipses.
        if prev and prev.address + prev.size != instr.address:
            result.append(N.branch_marker('%s' % nearpc_branch_marker))

        # Otherwise if it's a branch and it *is* contiguous, just put
        # and empty line.
        elif prev and any(g in prev.groups
                          for g in (CS_GRP_CALL, CS_GRP_JUMP, CS_GRP_RET)):
            if len('%s' % nearpc_branch_marker_contiguous) > 0:
                result.append('%s' % nearpc_branch_marker_contiguous)

        # For syscall instructions, put the name on the side
        if instr.address == pc:
            syscall_name = pwndbg.arguments.get_syscall_name(instr)
            if syscall_name:
                line += ' <%s>' % N.syscall_name(syscall_name)

        # For Comment Function
        try:
            line += " " * 10 + C.comment(
                pwndbg.commands.comments.file_lists[pwndbg.proc.exe][hex(
                    instr.address)])
        except:
            pass

        result.append(line)

        # For call instructions, attempt to resolve the target and
        # determine the number of arguments.
        if show_args:
            result.extend([
                '%8s%s' % ('', arg)
                for arg in pwndbg.arguments.format_args(instruction=instr)
            ])

        prev = instr

    if not to_string:
        print('\n'.join(result))

    return result
Esempio n. 8
0
def nearpc(pc=None, lines=None, to_string=False, emulate=False):
    """
    Disassemble near a specified address.
    """
    # Fix the case where we only have one argument, and
    # it's a small value.
    if lines is None and (pc is None or int(pc) < 0x100):
        lines = pc
        pc = None

    if pc is None:
        pc = pwndbg.regs.pc

    if lines is None:
        lines = 5

    pc = int(pc)
    lines = int(lines)

    # # Load source data if it's available
    # pc_to_linenos = collections.defaultdict(lambda: [])
    # lineno_to_src = {}
    # frame = gdb.selected_frame()
    # if frame:
    #     sal = frame.find_sal()
    #     if sal:
    #         symtab = sal.symtab
    #         objfile = symtab.objfile
    #         sourcefilename = symtab.filename
    #         with open(sourcefilename, 'r') as sourcefile:
    #             lineno_to_src = {i:l for i,l in enumerate(sourcefile.readlines())}

    #         for line in symtab.linetable():
    #             pc_to_linenos[line.pc].append(line.line)
    result = []
    instructions = pwndbg.disasm.near(pc, lines, emulate=emulate)

    # In case $pc is in a new map we don't know about,
    # this will trigger an exploratory search.
    pwndbg.vmmap.find(pc)

    # Gather all addresses and symbols for each instruction
    symbols = [pwndbg.symbol.get(i.address) for i in instructions]
    addresses = ['%#x' % i.address for i in instructions]

    # Format the symbol name for each instruction
    symbols = ['<%s> ' % sym if sym else '' for sym in symbols]

    # Pad out all of the symbols and addresses
    if pwndbg.config.left_pad_disasm:
        symbols = ljust_padding(symbols)
        addresses = ljust_padding(addresses)

    prev = None

    # Print out each instruction
    for address_str, s, i in zip(addresses, symbols, instructions):
        asm = D.instruction(i)
        prefix = ' %s' % (pwndbg.config.nearpc_prefix if i.address == pc else
                          ' ' * len(pwndbg.config.nearpc_prefix.value))
        prefix = N.prefix(prefix)
        if pwndbg.config.highlight_pc:
            prefix = C.highlight(prefix)

        pre = pwndbg.ida.Anterior(i.address)
        if pre:
            result.append(N.ida_anterior(pre))

        # Colorize address and symbol if not highlighted
        if i.address != pc or not pwndbg.config.highlight_pc:
            address_str = N.address(address_str)
            s = N.symbol(s)
        elif pwndbg.config.highlight_pc:
            address_str = C.highlight(address_str)
            s = C.highlight(s)

        line = ' '.join((prefix, address_str, s, asm))

        # If there was a branch before this instruction which was not
        # contiguous, put in some ellipses.
        if prev and prev.address + prev.size != i.address:
            result.append(N.branch_marker('%s' % nearpc_branch_marker))

        # Otherwise if it's a branch and it *is* contiguous, just put
        # and empty line.
        elif prev and any(g in prev.groups
                          for g in (CS_GRP_CALL, CS_GRP_JUMP, CS_GRP_RET)):
            if len('%s' % nearpc_branch_marker_contiguous) > 0:
                result.append('%s' % nearpc_branch_marker_contiguous)

        # For syscall instructions, put the name on the side
        if i.address == pc:
            syscall_name = pwndbg.arguments.get_syscall_name(i)
            if syscall_name:
                line += ' <%s>' % N.syscall_name(syscall_name)

        result.append(line)

        # For call instructions, attempt to resolve the target and
        # determine the number of arguments.
        for arg, value in pwndbg.arguments.get(i):
            code = False if arg.type == 'char' else True
            pretty = pwndbg.chain.format(value, code=code)
            result.append('%8s%-10s %s' %
                          ('', N.argument(arg.name) + ':', pretty))

        prev = i

    if not to_string:
        print('\n'.join(result))

    return result
Esempio n. 9
0
def nearpc(pc=None, lines=None, to_string=False, emulate=False):
    """
    Disassemble near a specified address.
    """
    # Fix the case where we only have one argument, and
    # it's a small value.
    if lines is None and (pc is None or int(pc) < 0x100):
        lines = pc
        pc    = None

    if pc is None:
        pc = pwndbg.regs.pc

    if lines is None:
        lines = 5

    pc    = int(pc)
    lines = int(lines)

    # # Load source data if it's available
    # pc_to_linenos = collections.defaultdict(lambda: [])
    # lineno_to_src = {}
    # frame = gdb.selected_frame()
    # if frame:
    #     sal = frame.find_sal()
    #     if sal:
    #         symtab = sal.symtab
    #         objfile = symtab.objfile
    #         sourcefilename = symtab.filename
    #         with open(sourcefilename, 'r') as sourcefile:
    #             lineno_to_src = {i:l for i,l in enumerate(sourcefile.readlines())}

    #         for line in symtab.linetable():
    #             pc_to_linenos[line.pc].append(line.line)
    result = []
    instructions = pwndbg.disasm.near(pc, lines, emulate=emulate)

    # In case $pc is in a new map we don't know about,
    # this will trigger an exploratory search.
    pwndbg.vmmap.find(pc)

    # Gather all addresses and symbols for each instruction
    symbols = [pwndbg.symbol.get(i.address) for i in instructions]
    addresses = ['%#x' % i.address for i in instructions]

    # Format the symbol name for each instruction
    symbols = ['<%s> ' % sym if sym else '' for sym in symbols]

    # Pad out all of the symbols and addresses
    if pwndbg.config.left_pad_disasm:
        symbols   = ljust_padding(symbols)
        addresses = ljust_padding(addresses)

    prev = None

    # Print out each instruction
    for address_str, s, i in zip(addresses, symbols, instructions):
        asm    = D.instruction(i)
        prefix = ' %s' % (pwndbg.config.nearpc_prefix if i.address == pc else ' ' * len(pwndbg.config.nearpc_prefix.value))
        prefix = N.prefix(prefix)
        if pwndbg.config.highlight_pc:
            prefix = C.highlight(prefix)

        pre = pwndbg.ida.Anterior(i.address)
        if pre:
            result.append(N.ida_anterior(pre))

        # Colorize address and symbol if not highlighted
        if i.address != pc or not pwndbg.config.highlight_pc:
            address_str = N.address(address_str)
            s = N.symbol(s)
        elif pwndbg.config.highlight_pc:
            address_str = C.highlight(address_str)
            s = C.highlight(s)

        line   = ' '.join((prefix, address_str, s, asm))

        # If there was a branch before this instruction which was not
        # contiguous, put in some ellipses.
        if prev and prev.address + prev.size != i.address:
            result.append(N.branch_marker('%s' % nearpc_branch_marker))

        # Otherwise if it's a branch and it *is* contiguous, just put
        # and empty line.
        elif prev and any(g in prev.groups for g in (CS_GRP_CALL, CS_GRP_JUMP, CS_GRP_RET)):
            if len('%s' % nearpc_branch_marker_contiguous) > 0:
                result.append('%s' % nearpc_branch_marker_contiguous)

        # For syscall instructions, put the name on the side
        if i.address == pc:
            syscall_name = pwndbg.arguments.get_syscall_name(i)
            if syscall_name:
                line += ' <%s>' % N.syscall_name(syscall_name)

        result.append(line)

        # For call instructions, attempt to resolve the target and
        # determine the number of arguments.
        for arg, value in pwndbg.arguments.get(i):
            code   = False if arg.type == 'char' else True
            pretty = pwndbg.chain.format(value, code=code)
            result.append('%8s%-10s %s' % ('', N.argument(arg.name) + ':', pretty))

        prev = i


    if not to_string:
        print('\n'.join(result))

    return result
Esempio n. 10
0
def context_code():
    try:
        # Compute the closest pc and line number
        symtab = gdb.selected_frame().find_sal().symtab
        linetable = symtab.linetable()

        closest_pc = -1
        closest_line = -1
        for line in linetable:
            if closest_pc < line.pc <= pwndbg.regs.pc:
                closest_line = line.line
                closest_pc = line.pc

        if closest_line < 0:
            return []

        # Get the full source code
        filename = symtab.fullname()
        source = get_highlight_source(filename)

        # If it starts on line 1, it's not really using the
        # correct source code.
        if not source or closest_line <= 1:
            return []

        n = int(source_code_lines)

        # Compute the line range
        start = max(closest_line - 1 - n // 2, 0)
        end = min(closest_line - 1 + n // 2 + 1, len(source))
        num_width = len(str(end))

        # split the code
        source = source[start:end]

        # Compute the prefix_sign length
        prefix_sign = pwndbg.config.code_prefix
        prefix_width = len(prefix_sign)

        # Format the output
        formatted_source = []
        for line_number, code in enumerate(source, start=start + 1):
            fmt = ' {prefix_sign:{prefix_width}} {line_number:>{num_width}} {code}'
            if pwndbg.config.highlight_source and line_number == closest_line:
                fmt = C.highlight(fmt)

            line = fmt.format(prefix_sign=C.prefix(prefix_sign)
                              if line_number == closest_line else '',
                              prefix_width=prefix_width,
                              line_number=line_number,
                              num_width=num_width,
                              code=code)
            formatted_source.append(line)

        banner = [pwndbg.ui.banner("Source (code)")]
        banner.extend(formatted_source)
        return banner
    except:
        pass

    if not pwndbg.ida.available():
        return []

    name = pwndbg.ida.GetFunctionName(pwndbg.regs.pc)
    addr = pwndbg.ida.LocByName(name)
    # May be None when decompilation failed or user loaded wrong binary in IDA
    code = pwndbg.ida.decompile(addr)

    if code:
        return [pwndbg.ui.banner("Hexrays pseudocode")] + code.splitlines()
    else:
        return []
Esempio n. 11
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
Esempio n. 12
0
def nearpc(pc=None, lines=None, to_string=False, emulate=False):
    """
    Disassemble near a specified address.
    """

    # Repeating nearpc (pressing enter) makes it show next addresses
    # (writing nearpc explicitly again will reset its state)
    if nearpc.repeat:
        pc = nearpc.next_pc

    result = []

    # Fix the case where we only have one argument, and
    # it's a small value.
    if lines is None and (pc is None or int(pc) < 0x100):
        lines = pc
        pc    = None

    if pc is None:
        pc = pwndbg.regs.pc

    if lines is None:
        lines = nearpc_lines // 2

    pc    = int(pc)
    lines = int(lines)

    # Check whether we can even read this address
    if not pwndbg.memory.peek(pc):
        result.append(message.error('Invalid address %#x' % pc))

    # # Load source data if it's available
    # pc_to_linenos = collections.defaultdict(lambda: [])
    # lineno_to_src = {}
    # frame = gdb.selected_frame()
    # if frame:
    #     sal = frame.find_sal()
    #     if sal:
    #         symtab = sal.symtab
    #         objfile = symtab.objfile
    #         sourcefilename = symtab.filename
    #         with open(sourcefilename, 'r') as sourcefile:
    #             lineno_to_src = {i:l for i,l in enumerate(sourcefile.readlines())}

    #         for line in symtab.linetable():
    #             pc_to_linenos[line.pc].append(line.line)
    instructions = pwndbg.disasm.near(pc, lines, emulate=emulate, show_prev_insns=not nearpc.repeat)

    if pwndbg.memory.peek(pc) and not instructions:
        result.append(message.error('Invalid instructions at %#x' % pc))

    # In case $pc is in a new map we don't know about,
    # this will trigger an exploratory search.
    pwndbg.vmmap.find(pc)

    # Gather all addresses and symbols for each instruction
    symbols = [pwndbg.symbol.get(i.address) for i in instructions]
    addresses = ['%#x' % i.address for i in instructions]

    nearpc.next_pc = instructions[-1].address + instructions[-1].size if instructions else 0

    # Format the symbol name for each instruction
    symbols = ['<%s> ' % sym if sym else '' for sym in symbols]

    # Pad out all of the symbols and addresses
    if pwndbg.config.left_pad_disasm and not nearpc.repeat:
        symbols   = ljust_padding(symbols)
        addresses = ljust_padding(addresses)

    prev = None

    # Print out each instruction
    for address_str, symbol, instr in zip(addresses, symbols, instructions):
        asm    = D.instruction(instr)
        prefix_sign  = pwndbg.config.nearpc_prefix

        # Show prefix only on the specified address and don't show it while in repeat-mode
        show_prefix = instr.address == pc and not nearpc.repeat
        prefix = ' %s' % (prefix_sign if show_prefix else ' ' * len(prefix_sign))
        prefix = N.prefix(prefix)

        pre = pwndbg.ida.Anterior(instr.address)
        if pre:
            result.append(N.ida_anterior(pre))

        # Colorize address and symbol if not highlighted
        # symbol is fetched from gdb and it can be e.g. '<main+8>'
        if instr.address != pc or not pwndbg.config.highlight_pc or nearpc.repeat:
            address_str = N.address(address_str)
            symbol = N.symbol(symbol)
        elif pwndbg.config.highlight_pc:
            prefix = C.highlight(prefix)
            address_str = C.highlight(address_str)
            symbol = C.highlight(symbol)

        line   = ' '.join((prefix, address_str, symbol, asm))

        # If there was a branch before this instruction which was not
        # contiguous, put in some ellipses.
        if prev and prev.address + prev.size != instr.address:
            result.append(N.branch_marker('%s' % nearpc_branch_marker))

        # Otherwise if it's a branch and it *is* contiguous, just put
        # and empty line.
        elif prev and any(g in prev.groups for g in (CS_GRP_CALL, CS_GRP_JUMP, CS_GRP_RET)):
            if len('%s' % nearpc_branch_marker_contiguous) > 0:
                result.append('%s' % nearpc_branch_marker_contiguous)

        # For syscall instructions, put the name on the side
        if instr.address == pc:
            syscall_name = pwndbg.arguments.get_syscall_name(instr)
            if syscall_name:
                line += ' <%s>' % N.syscall_name(syscall_name)

        result.append(line)

        # For call instructions, attempt to resolve the target and
        # determine the number of arguments.
        if show_args:
            result.extend(['%8s%s' % ('', arg) for arg in pwndbg.arguments.format_args(instruction=instr)])

        prev = instr

    if not to_string:
        print('\n'.join(result))

    return result
Esempio n. 13
0
def context_code():
    try:
        # Compute the closest pc and line number
        symtab = gdb.selected_frame().find_sal().symtab
        linetable = symtab.linetable()

        closest_pc = -1
        closest_line = -1
        for line in linetable:
            if closest_pc < line.pc <= pwndbg.regs.pc:
                closest_line = line.line
                closest_pc   = line.pc

        if closest_line < 0:
            return []

        # Get the full source code
        filename = symtab.fullname()
        source = get_highlight_source(filename)

        # If it starts on line 1, it's not really using the
        # correct source code.
        if not source or closest_line <= 1:
            return []

        n = int(source_code_lines)

        # Compute the line range
        start = max(closest_line - 1 - n//2, 0)
        end = min(closest_line - 1 + n//2 + 1, len(source))
        num_width = len(str(end))

        # split the code
        source = source[start:end]

        # Compute the prefix_sign length
        prefix_sign = pwndbg.config.code_prefix
        prefix_width = len(prefix_sign)

        # Format the output
        formatted_source = []
        for line_number, code in enumerate(source, start=start + 1):
            fmt = ' {prefix_sign:{prefix_width}} {line_number:>{num_width}} {code}'
            if pwndbg.config.highlight_source and line_number == closest_line:
                fmt = C.highlight(fmt)

            line = fmt.format(
                prefix_sign=C.prefix(prefix_sign) if line_number == closest_line else '',
                prefix_width=prefix_width,
                line_number=line_number,
                num_width=num_width,
                code=code
            )
            formatted_source.append(line)

        banner = [pwndbg.ui.banner("Source (code)"), 'In file: %s' % filename]
        banner.extend(formatted_source)
        return banner
    except:
        pass

    if not pwndbg.ida.available():
        return []

    name = pwndbg.ida.GetFunctionName(pwndbg.regs.pc)
    addr = pwndbg.ida.LocByName(name)
    # May be None when decompilation failed or user loaded wrong binary in IDA
    code = pwndbg.ida.decompile(addr)

    if code:
        return [pwndbg.ui.banner("Hexrays pseudocode")] + code.splitlines()
    else:
        return []
Esempio n. 14
0
def context_code():
    try:
        # Compute the closest pc and line number
        symtab = gdb.selected_frame().find_sal().symtab
        linetable = symtab.linetable()

        closest_pc = -1
        closest_line = -1
        for line in linetable:
            if closest_pc < line.pc <= pwndbg.regs.pc:
                closest_line = line.line
                closest_pc   = line.pc

        if closest_line < 0:
            return []

        # Get the full source code
        filename = symtab.fullname()
        source = get_highlight_source(filename)

        # If it starts on line 1, it's not really using the
        # correct source code.
        if not source or closest_line <= 1:
            return []

        n = int(source_code_lines)

        # Compute the line range
        start = max(closest_line - 1 - n//2, 0)
        end = min(closest_line - 1 + n//2 + 1, len(source))
        num_width = len(str(end))

        # split the code
        source = source[start:end]

        # Compute the prefix_sign length
        # TODO: remove this if the config setter can make sure everything is unicode.
        # This is needed because the config value may be utf8 byte string.
        # It is better to convert to unicode at setter of config and then we will not need this.
        prefix_sign = pwndbg.config.code_prefix
        value = prefix_sign.value
        if isinstance(value, bytes):
            value = codecs.decode(value, 'utf-8')
        prefix_width = len(value)

        # Convert config class to str to make format() work
        prefix_sign = str(prefix_sign)

        # Format the output
        formatted_source = []
        for line_number, code in enumerate(source, start=start + 1):
            fmt = ' {prefix_sign:{prefix_width}} {line_number:>{num_width}} {code}'
            if pwndbg.config.highlight_source and line_number == closest_line:
                fmt = C.highlight(fmt)

            line = fmt.format(
                prefix_sign=C.prefix(prefix_sign) if line_number == closest_line else '',
                prefix_width=prefix_width,
                line_number=line_number,
                num_width=num_width,
                code=code
            )
            formatted_source.append(line)

        banner = [pwndbg.ui.banner("Source (code)")]
        banner.extend(formatted_source)
        return banner
    except:
        pass

    if not pwndbg.ida.available():
        return []

    name = pwndbg.ida.GetFunctionName(pwndbg.regs.pc)
    addr = pwndbg.ida.LocByName(name)
    # May be None when decompilation failed or user loaded wrong binary in IDA
    code = pwndbg.ida.decompile(addr)

    if code:
        return [pwndbg.ui.banner("Hexrays pseudocode")] + code.splitlines()
    else:
        return []