R2morph
A metamorphic binary transformation engine based on r2pipe and radare2.
Install / Use
/learn @seifreed/R2morphREADME
Overview
r2morph is a mutation-first engine for applying metamorphic binary transformations with explicit validation, rollback, and machine-readable reports. It leverages radare2 and r2pipe to analyze binaries, apply tracked mutations, and verify the result before export.
Key Features
| Feature | Description |
|---------|-------------|
| Tracked Mutations | Every applied mutation can be recorded with addresses, bytes, and disassembly |
| Validation Pipeline | Structural validation in the engine, optional runtime validation, rollback on failure |
| Machine-Readable Reports | Export JSON reports for CI, regression checks, and auditability |
| CLI + Python API | Run as mutate, validate, report, or embed as a library |
| radare2-backed Analysis | Reuse radare2/r2pipe for disassembly and binary metadata |
| Experimental Modules | Devirtualization, enhanced analysis, instrumentation, and anti-analysis helpers remain secondary/experimental |
Installation
Prerequisites
- Python 3.10+
- radare2 installed
Install radare2
git clone https://github.com/radareorg/radare2
cd radare2
sys/install.sh
Install r2morph
# Basic installation
pip install r2morph
# Enhanced analysis capabilities
pip install "r2morph[enhanced]"
# All optional features
pip install "r2morph[all]"
Development Install
git clone https://github.com/seifreed/r2morph.git
cd r2morph
pip install -e .
# Dev tooling
pip install -e ".[dev]"
Product Focus
r2morph is being focused around a single product:
load binary -> apply tracked mutations -> validate -> export binary + report
The stable core is mutation + validation. Advanced reversing workflows remain available in the repository, but are secondary and should be treated as experimental.
See docs/ROADMAP.md for the implementation roadmap and current phase status.
Support Matrix
Stable Core
| Area | Supported | Stability |
|------|-----------|-----------|
| Formats | ELF | Stable |
| Architectures | x86_64 | Stable |
| Mutations | nop, substitute, register | Stable |
| Validators | structural, runtime | Stable / Supported |
| Output | JSON report + mutated binary | Stable |
Experimental / Secondary
| Area | Supported | Stability |
|------|-----------|-----------|
| Formats | PE, Mach-O | Experimental |
| Mutations | expand, block, opaque, dead-code, cff | Experimental |
| Validation | symbolic equivalence | Experimental |
| Analysis | devirtualization, Frida, anti-analysis, packer analysis | Experimental |
Quick Start
# Stable mutate + validate flow
r2morph input_binary output_binary
# Explicit mutate command with report
r2morph mutate input_binary -o output_binary --report mutation_report.json
# Reproducible stable mutation run
r2morph mutate input_binary -o output_binary --seed 1337
# Runtime validation of an original/mutated pair
r2morph validate input_binary output_binary
# Runtime validation with a reusable corpus
r2morph validate input_binary output_binary --corpus dataset/runtime_corpus.json
Usage
Command Line Interface
# Stable default flow
r2morph input_binary output_binary
# Stable tracked mutation flow
r2morph mutate input_binary -o output_binary -m nop -m substitute -m register
# Reproducible mutation selection
r2morph mutate input_binary -o output_binary --seed 1337
# Experimental symbolic precheck mode
r2morph mutate input_binary -o output_binary --validation-mode symbolic
# Allow a limited symbolic pass explicitly
r2morph mutate input_binary -o output_binary --validation-mode symbolic \
--allow-limited-symbolic -m register
# Degrade a limited symbolic pass to runtime validation instead of blocking
r2morph mutate input_binary -o output_binary --validation-mode symbolic \
--limited-symbolic-policy degrade-runtime -m register
# Export a machine-readable report
r2morph mutate input_binary -o output_binary --report report.json
# Fail the CLI run unless the final report reaches a minimum symbolic severity
r2morph mutate input_binary -o output_binary --report report.json \
--min-severity bounded-only
# Fail unless a specific pass reaches the required local severity
r2morph mutate input_binary -o output_binary --report report.json \
--require-pass-severity InstructionSubstitution=bounded-only
# Short mutation aliases also work in pass severity gating
r2morph mutate input_binary -o output_binary --report report.json \
--require-pass-severity nop=not-requested
# The generated report preserves gate requests and outcomes in `gate_evaluation`
# Validate a mutated binary against the original
r2morph validate input_binary output_binary
# Validate with a JSON corpus of runtime cases
r2morph validate input_binary output_binary --corpus dataset/runtime_corpus.json
# Ignore trailing whitespace differences in stdout/stderr
r2morph validate input_binary output_binary --corpus dataset/runtime_corpus.json --normalize-whitespace
# Run mutate with runtime validation backed by a real corpus
r2morph mutate input_binary -o output_binary \
--validation-mode runtime \
--runtime-corpus dataset/runtime_corpus.json
# Display a saved report with symbolic coverage summaries and mismatch triage when available
r2morph report report.json
# Use the saved report as a CI gate
r2morph report report.json --require-results --min-severity mismatch
# Triage only runs where persisted CLI gates failed
r2morph report report.json --only-failed-gates --summary-only
# The summary includes compact gate failure causes for fast triage
# Restrict persisted gate failures to one expected severity
r2morph report report.json --only-failed-gates --only-expected-severity clean --summary-only
# Restrict persisted gate failures to one pass
r2morph report report.json --only-failed-gates --only-pass-failure NopInsertion --summary-only
# Stable mutation aliases work for gate triage too
r2morph report report.json --only-failed-gates --only-pass-failure nop --summary-only
# Triage only symbolic observable mismatches
r2morph report report.json --only-mismatches
# Restrict the report to one pass, optionally combined with mismatch triage
r2morph report report.json --only-pass InstructionSubstitution --only-mismatches
# Stable mutation aliases also work in pass filtering
r2morph report report.json --only-pass nop
# Filter directly by symbolic status
r2morph report report.json --only-status bounded-step-observable-mismatch
# Show only reports where the effective validation mode was degraded
r2morph report report.json --only-degraded
# The report summary includes the degraded pass set and symbolic confidence for each cause
# Show only the textual summary for terminal triage
r2morph report report.json --summary-only
# Export a filtered report JSON for CI or post-processing
r2morph report report.json --only-pass InstructionSubstitution --output filtered-report.json
# Fail in CI when a filtered view has no matching mutations
r2morph report report.json --only-pass InstructionSubstitution --require-results
# Fail in CI when a filtered gate view has no matching failures
r2morph report report.json --only-failed-gates --only-expected-severity clean --require-results
r2morph report report.json --only-failed-gates --only-pass-failure nop --require-results
# The exported JSON includes `filtered_summary` for the active view
r2morph report report.json --only-status bounded-step-passed --output filtered-report.json
# `filtered_summary.symbolic_statuses` exposes the status distribution for the current view
r2morph report report.json --only-pass InstructionSubstitution --output filtered-report.json
# Gate-focused filtered views also preserve `gate_failures`, `gate_failure_priority`,
# `gate_failure_severity_priority`, and normalized `report_filters`
r2morph report report.json --only-failed-gates --only-pass-failure nop --output filtered-report.json
Report Filter Quick Reference
| Filter | Purpose | Example |
| --- | --- | --- |
| --only-pass <pass-or-alias> | Restrict mutations to one pass in the current view | r2morph report report.json --only-pass nop |
| `--only-statu
