|
|
|
|
@ -17,10 +17,9 @@ import pwndbg.rizin
|
|
|
|
|
if pwndbg.dbg.is_gdblib_available():
|
|
|
|
|
import pwndbg.gdblib.symbol
|
|
|
|
|
|
|
|
|
|
from pwndbg.color import message
|
|
|
|
|
|
|
|
|
|
r2decompiler = pwndbg.config.add_param(
|
|
|
|
|
"r2decompiler",
|
|
|
|
|
decompiler = pwndbg.config.add_param(
|
|
|
|
|
"decompiler",
|
|
|
|
|
"radare2",
|
|
|
|
|
"framework that your ghidra plugin installed",
|
|
|
|
|
param_class=pwndbg.lib.config.PARAM_ENUM,
|
|
|
|
|
@ -28,18 +27,6 @@ r2decompiler = pwndbg.config.add_param(
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pwndbg.config.trigger(r2decompiler)
|
|
|
|
|
def set_r2decompiler() -> None:
|
|
|
|
|
if r2decompiler.value in ["radare2", "rizin"]:
|
|
|
|
|
return
|
|
|
|
|
print(
|
|
|
|
|
message.warn(
|
|
|
|
|
f"Invalid r2decompiler: `{r2decompiler.value}`, please select from radare2 or rizin"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
r2decompiler.revert_default()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def decompile(func=None):
|
|
|
|
|
"""
|
|
|
|
|
Return the source of the given function decompiled by ghidra.
|
|
|
|
|
@ -49,22 +36,24 @@ def decompile(func=None):
|
|
|
|
|
|
|
|
|
|
Raises Exception if any fatal error occurs.
|
|
|
|
|
"""
|
|
|
|
|
func_specified = func is not None
|
|
|
|
|
try:
|
|
|
|
|
if r2decompiler == "radare2":
|
|
|
|
|
r2 = pwndbg.radare2.r2pipe()
|
|
|
|
|
# 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")
|
|
|
|
|
else:
|
|
|
|
|
assert r2decompiler == "rizin"
|
|
|
|
|
r2 = pwndbg.rizin.rzpipe()
|
|
|
|
|
# Lc -> list core plugins
|
|
|
|
|
if "ghidra" not in r2.cmd("Lc"):
|
|
|
|
|
raise Exception("rizin plugin rzghidra must be installed and available from rz")
|
|
|
|
|
if decompiler == "radare2":
|
|
|
|
|
r = pwndbg.radare2.r2pipe()
|
|
|
|
|
elif decompiler == "rizin":
|
|
|
|
|
r = pwndbg.rizin.rzpipe()
|
|
|
|
|
except ImportError:
|
|
|
|
|
raise Exception("r2pipe or rzpipe not available, but required for r2/rz->ghidra bridge")
|
|
|
|
|
|
|
|
|
|
if pwndbg.aglib.qemu.is_qemu_kernel():
|
|
|
|
|
pc = pwndbg.aglib.regs[pwndbg.aglib.regs.current.pc]
|
|
|
|
|
if func is None:
|
|
|
|
|
func = pwndbg.aglib.symbol.resolve_addr(pc)
|
|
|
|
|
if func is not None:
|
|
|
|
|
func = func.split("+")[0]
|
|
|
|
|
if func is not None:
|
|
|
|
|
func = f"sym.{func}"
|
|
|
|
|
|
|
|
|
|
if not func:
|
|
|
|
|
func = (
|
|
|
|
|
hex(pwndbg.aglib.regs[pwndbg.aglib.regs.current.pc])
|
|
|
|
|
@ -72,12 +61,14 @@ def decompile(func=None):
|
|
|
|
|
else "main"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
src = r2.cmdj("pdgj @ " + func)
|
|
|
|
|
r.cmd(f"afr @ {func}")
|
|
|
|
|
src = r.cmdj("pdgj @ " + func)
|
|
|
|
|
if not src:
|
|
|
|
|
raise Exception(f"Decompile command failed, check if '{func}' is a valid target")
|
|
|
|
|
|
|
|
|
|
current_line_marker = "/*%%PWNDBG_CODE_MARKER%%*/"
|
|
|
|
|
source = src.get("code", "")
|
|
|
|
|
closest_line = 1
|
|
|
|
|
|
|
|
|
|
# If not running there is no current pc to mark
|
|
|
|
|
if pwndbg.aglib.proc.alive:
|
|
|
|
|
@ -85,6 +76,8 @@ def decompile(func=None):
|
|
|
|
|
|
|
|
|
|
closest = 0
|
|
|
|
|
for off in (a.get("offset", 0) for a in src.get("annotations", [])):
|
|
|
|
|
if off == 0 and pc > 0x1000:
|
|
|
|
|
continue
|
|
|
|
|
if abs(pc - closest) > abs(pc - off):
|
|
|
|
|
closest = off
|
|
|
|
|
pos_annotations = sorted(
|
|
|
|
|
@ -94,7 +87,7 @@ def decompile(func=None):
|
|
|
|
|
|
|
|
|
|
# Append code prefix marker for the current line and replace it later
|
|
|
|
|
if pos_annotations:
|
|
|
|
|
curline = source.count("\n", 0, pos_annotations[0]["start"])
|
|
|
|
|
curline = closest_line = source.count("\n", 0, pos_annotations[0]["start"])
|
|
|
|
|
source = source.split("\n")
|
|
|
|
|
line = source[curline]
|
|
|
|
|
if line.startswith(" "):
|
|
|
|
|
@ -114,4 +107,16 @@ def decompile(func=None):
|
|
|
|
|
|
|
|
|
|
# Replace code prefix marker after syntax highlighting
|
|
|
|
|
source = source.replace(current_line_marker, C.prefix(pwndbg.config.code_prefix), 1)
|
|
|
|
|
|
|
|
|
|
if not func_specified:
|
|
|
|
|
source = source.split("\n")
|
|
|
|
|
n = int(pwndbg.config.context_code_lines)
|
|
|
|
|
|
|
|
|
|
# Compute the line range
|
|
|
|
|
start = max(closest_line - 1 - n // 2, 0)
|
|
|
|
|
end = min(closest_line - 1 + n // 2 + 1, len(source))
|
|
|
|
|
|
|
|
|
|
# split the code
|
|
|
|
|
source = source[start:end]
|
|
|
|
|
source = "\n".join(source)
|
|
|
|
|
return source
|
|
|
|
|
|