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
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
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 []
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 []
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 []