Ejemplo n.º 1
0
def decompile(func=None):
    """
    Return the source of the given function decompiled by ghidra.

    If no function is given, decompile the function within the current pc.
    This function requires radare2, r2pipe and r2ghidra.

    Raises Exception if any fatal error occures.
    """
    try:
        r2 = pwndbg.radare2.r2pipe()
    except ImportError:
        raise Exception('r2pipe not available, but required for r2->ghidra bridge')

    # LD -> list supported decompilers (e cmd.pdc=?)
    # Outputs for example: pdc\npdg
    if "pdg" not in r2.cmd("LD").split("\n"):
        raise Exception('radare2 plugin r2ghidra must be installed and available from r2')

    if not func:
        func = hex(pwndbg.regs[pwndbg.regs.current.pc]) if pwndbg.proc.alive else 'main'

    src = r2.cmdj("pdgj @" + func)
    if not src:
        raise Exception("Decompile command failed, check if '{}' is a valid target".format(func))

    current_line_marker = '/*%%PWNDBG_CODE_MARKER%%*/'
    source = src.get("code", "")

    # If not running there is no current pc to mark
    if pwndbg.proc.alive:
        pc = pwndbg.regs[pwndbg.regs.current.pc]

        closest = 0
        for off in (a.get("offset", 0) for a in src.get("annotations", [])):
            if abs(pc - closest) > abs(pc - off):
                closest = off
        pos_annotations = sorted([a for a in src.get("annotations", []) if a.get("offset") == closest], key=lambda a: a["start"])

        # Append code prefix marker for the current line and replace it later
        if pos_annotations:
            curline = source.count("\n", 0, pos_annotations[0]["start"])
            source = source.split("\n")
            line = source[curline]
            if line.startswith('    '):
                line = line[min(4, len(pwndbg.config.code_prefix) + 1):]
            source[curline] = current_line_marker + ' ' + line
            source = "\n".join(source)

    if pwndbg.config.syntax_highlight:
        # highlighting depends on the file extension to guess the language, so try to get one...
        src_filename = pwndbg.symbol.selected_frame_source_absolute_filename()
        if not src_filename:
            filename = gdb.current_progspace().filename
            src_filename = filename + ".c" if os.path.basename(filename).find(".") < 0 else filename
        source = H.syntax_highlight(source, src_filename)

    # Replace code prefix marker after syntax highlighting
    source = source.replace(current_line_marker, C.prefix(pwndbg.config.code_prefix), 1)
    return source
Ejemplo n.º 2
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
Ejemplo n.º 3
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 []
Ejemplo n.º 4
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 []
Ejemplo n.º 5
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 []