Skip to content

Multiarchitecture support and bugfixes - #40

Merged
845977 merged 8 commits into
reverseame:multiarchfrom
845977:master
Sep 1, 2026
Merged

Multiarchitecture support and bugfixes#40
845977 merged 8 commits into
reverseame:multiarchfrom
845977:master

Conversation

@845977

@845977 845977 commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Added support for AArch64 and RISC-V architectures. Implemented several improvements in gadget finding and filtering and refactored ropchain.py and gadfinder.py to remove circular dependencies (now ropchain -> gadfinder -> operation.py).
ROPLANG operands are now defined positionally, and operations with multiple sources and/or destinations are correctly tracked.

845977 and others added 8 commits August 25, 2026 12:13
… matrix

Extend rop3 beyond x86 to a multi-architecture gadget finder, rework the
operation matcher around explicit per-architecture operand roles, and broaden
the binary-format coverage. Documentation and the test suite are updated to
match.

- AArch64 (ARM64) and RISC-V (RV64, including the compressed RVC extension)
  join x86 and x86-64. Architecture is detected from the binary; RV32 is
  explicitly rejected.
- `rop3/archs/aarch64_arch.py` and `rop3/archs/riscv_arch.py` implement the
  Architecture ABC (registers, terminations, alignment, written-register
  derivation). RISC-V derives written registers from the instruction encoding
  because capstone does not implement `regs_access()` for it.
- Framed gadget search (`--frame`/`--no-frame`, on by default): on AArch64 and
  RISC-V, where the return address lives in a register, only gadgets that
  restore it from the stack are kept. No effect on x86. JOP gadgets are never
  gated by framing. Framed architectures scan serially regardless of `--jobs`.
- Instruction alignment is architecture-aware (4-byte on AArch64/RISC-V, 2-byte
  under RVC), and `--depth` now defaults per architecture instead of a fixed 5
  bytes. The scan engine lives in `rop3/search.py` (galileo + aligned sweeps).

- PE now detects i386, AMD64 and ARM64; Mach-O detects i386, x86_64 and arm64
  (thin and fat, with `--arch` selecting a slice); ELF adds AArch64 and RISC-V.
- `--verbose` prints a per-binary summary (format, architecture, bit width,
  instruction alignment and executable sections); exposed on the library as
  `Rop3.describe()`.

- Operations take positional, n-ary operands: `--op mov --operands rdi rax`
  (op1, op2, op3, ...) and `Rop3.find_op(op, operands=[...])`, replacing the old
  `--dst`/`--src` pair.
- ROPLang definitions (`rop3/roplang/*.yaml`) are per architecture, with explicit
  `dst`/`src` operand roles and an `available: false` marker for operations an
  architecture cannot realize (the carry-flag operations `eqc`, `ltc`,
  `gcf-eqc`, `gcf-ltc` are unavailable on RISC-V). Composite operations chain
  other operations through `operation:` references.
- `rop3/operation.py` is reworked: matching anchors an operation's first
  instruction after the architecture's frame prologue and allows the remaining
  instructions to be separated; dst/src register sets are computed from the
  operation's role metadata; and "contradictory" gadgets (destination
  overwritten before the terminator) are rejected during the match, with
  `--keep-contradictory` to disable it.
- New flags: `--ret-imm` (include `ret <imm>`/`retf <imm>` terminators, off by
  default), `--reg-aliases` (let sub-registers stand in for their full
  register), and `--tuple` output.

- New `tests/test_roplang_gadgets.py`: a cross-architecture matrix that checks
  every ROPLang operation on x86, x86-64, AArch64 and RISC-V. Primitive
  (single-gadget) operations are matched against a representative gadget;
  composite operations are checked for availability and realizations; a
  completeness test guarantees no operation is silently skipped. RISC-V carry
  operations are asserted unavailable rather than searched.
- New per-architecture and per-format suites: `tests/test_aarch64.py`,
  `tests/test_riscv.py`, `tests/test_pe.py`, `tests/test_info.py`, plus in-memory
  Mach-O/PE builders in `tests/conftest.py` (no committed binary fixtures).
- `tests/test_search.py` covers the extracted scan engine.
- Fix-guarding assertions (immediate operands not leaking into src, stores not
  flagged contradictory, stack-pointer ops not contradictory) are folded into
  the relevant behavior tests instead of standalone regression cases.

- README rewritten: supported architecture/format matrix, framed search,
  n-ary operands and composite operations, updated option list, library and
  interactive examples.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@845977
845977 merged commit 8b6605f into reverseame:multiarch Sep 1, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant