Metamorphic binary mutation engine with structural validation
Project description
r2morph
Metamorphic mutation engine with structured validation and reporting
Overview
r2morph is a metamorphic mutation engine that applies tracked binary transformations with validation, rollback, and machine-readable reports. It uses radare2 for analysis and supports 18 mutation passes across 4 architectures.
Key Features
| Feature | Description |
|---|---|
| 18 Mutation Passes | From stable NOP/substitute/register to experimental CFF, virtualization, and self-modifying code |
| 4 Architectures | x86_64, x86, ARM64, ARM32 |
| 3 Binary Formats | ELF (stable), PE and Mach-O (experimental, via LIEF) |
| 4 Validation Modes | Structural, runtime, symbolic (angr), CFG integrity |
| Session Management | Checkpoint/rollback system preserving binary state across mutation passes |
| SARIF 2.1.0 Reports | OASIS SARIF with MITRE ATT&CK taxonomy, fingerprints, code flows |
| JSON Reports | Documented schema, metadata, timing, gate evaluation |
| Detection Suite | Packer signatures, entropy analysis, pattern matching, similarity hashing |
| Devirtualization | VM handler analysis, MBA simplification (Z3-based) |
Installation
Prerequisites
- Python 3.10+
- radare2 installed
Install radare2
git clone https://github.com/radareorg/radare2
cd radare2
sys/install.sh
Install r2morph
pip install r2morph # Basic
pip install "r2morph[enhanced]" # + angr, lief, z3
pip install "r2morph[all]" # + frida, hypothesis
Development Install
git clone https://github.com/seifreed/r2morph.git
cd r2morph
pip install -e ".[dev]"
Support Matrix
Formats
| Format | Status | Section Creation | Notes |
|---|---|---|---|
| ELF | Stable | Via LIEF | Full section handling, relocations, code caves |
| PE | Experimental | Via LIEF | Section creation, checksum fixing |
| Mach-O | Experimental | Via LIEF | Load command parsing, Fat binary support |
Architectures
| Architecture | NOP | Substitute | Register | Expand | Block | Dead Code |
|---|---|---|---|---|---|---|
| x86_64 | Yes | Yes | Yes | Yes | Yes | Yes |
| x86 | Yes | Yes | Yes | Yes | Yes | Yes |
| ARM64 | Yes | Yes | Yes | Yes | Yes | Yes |
| ARM32 | Yes | Yes | Yes | Yes | Yes | Yes |
Instruction Equivalence Rules
- x86/x86_64: 100+ rules in
x86_rules.yaml- bidirectional groups covering zero registers, self-moves, flag-preserving patterns, XOR/SUB equivalence - ARM32: 10+ groups in
arm_rules.yaml- zero, increment, decrement, self-move, shift, negate, double, compare for r0-r11 - ARM64: Register classes defined in
arm64_rules.yaml
Mutation Passes
Stable (tested, production-ready)
| Pass | CLI Flag | Description |
|---|---|---|
| NOP Insertion | -m nop |
Inserts benign NOP equivalents at safe locations |
| Instruction Substitution | -m substitute |
Replaces instructions with semantically equivalent alternatives |
| Register Substitution | -m register |
Substitutes registers via liveness analysis |
Experimental (working, limited testing)
| Pass | CLI Flag | Description |
|---|---|---|
| Instruction Expansion | -m expand |
Expands single instructions into longer equivalent sequences |
| Block Reordering | -m block |
Reorders basic blocks with jump patching |
| Dead Code Injection | -m dead-code |
Injects semantically neutral code in padding regions |
| Control Flow Flattening | -m cff |
Inserts opaque predicates and jump obfuscation |
| Opaque Predicates | -m opaque |
Writes opaque predicate instructions into basic blocks |
| Code Virtualization | -m code-virtualization |
Translates instructions to VM bytecode with dispatcher |
| Anti-Disassembly | -m anti-disassembly |
Injects anti-disassembly snippets |
| Data Flow Mutation | -m data-flow |
Data flow analysis-driven safe substitutions |
| Short Jump Patching | -m short-jump |
Patches short jumps to equivalent sequences |
| Constant Unfolding | -m constant-unfolding |
Unfolds constant expressions into multi-instruction equivalents |
| Code Mobility | -m code-mobility |
Relocates blocks to code caves with trampolines |
| Function Outlining | -m function-outlining |
Distributes function chunks across code caves |
| API Hashing | -m api-hashing |
Hash trampolines obscuring PLT references |
| Import Obfuscation | -m import-obfuscation |
Jump stub indirection for import calls |
| Self-Modifying Code | -m self-modifying |
XOR-encrypts function bodies with runtime decryptor |
Validation
| Mode | Flag | Status | Description |
|---|---|---|---|
| Structural | --validation-mode structural |
Stable | Binary format integrity checks (always runs) |
| Runtime | --validation-mode runtime |
Stable | Compares original vs mutated execution (exit code, stdout, stderr, files) |
| Symbolic | --validation-mode symbolic |
Experimental | Bounded symbolic step via angr (ELF x86_64, advisory) |
| CFG Integrity | Automatic | Experimental | Reachability and edge preservation checks |
Quick Start
# Mutate with stable passes
r2morph mutate input.elf -o output.elf -m nop -m substitute -m register
# SARIF report for CI/CD
r2morph mutate input.elf -o output.elf --format sarif --report mutations.sarif
# Reproducible run
r2morph mutate input.elf -o output.elf --seed 1337
# Runtime validation
r2morph validate original.elf mutated.elf --corpus dataset/runtime_corpus.json
# CI gate: fail if severity below threshold
r2morph mutate input.elf -o output.elf --report report.json --min-severity bounded-only
# Display and filter reports
r2morph report report.json --only-pass nop --summary-only
r2morph report report.json --format sarif -o report.sarif
CLI Reference
Commands
| Command | Description |
|---|---|
r2morph mutate |
Apply mutations, validate, export binary + report |
r2morph validate |
Compare original vs mutated binary behavior |
r2morph report |
Display, filter, or convert a saved report |
r2morph analyze |
Analyze binary structure and functions |
r2morph functions |
List functions in a binary |
r2morph version |
Show version |
Report Filters
| Filter | Purpose |
|---|---|
--format <json|sarif> |
Output format (JSON default, SARIF 2.1.0) |
--only-pass <name> |
Restrict to one mutation pass |
--only-mismatches |
Show only symbolic observable mismatches |
--only-failed-gates |
Show only failed severity gates |
--only-degraded |
Show only degraded validation modes |
--summary-only |
Print textual triage summary only |
--output <file> |
Export filtered JSON |
--require-results |
Exit 1 when filtered view is empty |
--min-severity <sev> |
Require minimum severity in view |
SARIF 2.1.0 Integration
Reports in SARIF format include:
- MITRE ATT&CK taxonomy - T1027 (Obfuscated Files), T1027.001 (Binary Padding), T1027.002 (Software Packing)
- Partial fingerprints (SHA256) for deduplication across CI runs
- Code flows showing mutation chains per function
- Related locations linking mutations to validation failures
- Disassembly snippets in the rendered field alongside hex bytes
- Fix suggestions with byte-level replacements
Compatible with GitHub Code Scanning, Azure DevOps, SonarQube, and any SARIF 2.1.0 consumer.
Python API
from r2morph import MorphEngine
from r2morph.mutations import NopInsertionPass, InstructionSubstitutionPass, RegisterSubstitutionPass
with MorphEngine() as engine:
engine.load_binary("input.elf").analyze()
engine.add_mutation(NopInsertionPass())
engine.add_mutation(InstructionSubstitutionPass())
engine.add_mutation(RegisterSubstitutionPass())
result = engine.run(validation_mode="structural", report_path="report.json")
engine.save("output.elf")
print(f"Applied {result['total_mutations']} mutations")
Detection & Analysis
| Module | Capability |
|---|---|
| Obfuscation Detector | Commercial packer signatures (VMProtect, Themida, UPX, etc.), confidence scoring |
| Entropy Analyzer | Section entropy analysis for packing/encryption detection |
| Pattern Matcher | Anti-debug, anti-VM, string encryption, import hiding detection |
| Similarity Hasher | Fuzzy hashing for binary comparison (ssdeep-style) |
| Control Flow Detector | CFF, opaque predicates, VM dispatch, MBA expression detection |
| Packer Signatures | 50+ categorized signature database |
Devirtualization (Experimental)
| Module | Status | Notes |
|---|---|---|
| VM Handler Analyzer | Working | Pattern-based handler classification |
| MBA Solver | Working | Z3 SMT solver, max 8 variables, timeout-bounded |
| CFO Simplifier | Framework | Pattern library defined, application incomplete |
| Binary Rewriter | Framework | Patch/relocation infrastructure |
Instrumentation (Experimental)
Frida integration for dynamic analysis: process spawning, script injection, API call logging, anti-analysis detection. Requires frida package.
Report Schema
JSON reports follow a documented schema at r2morph/reporting/report_schema.json. Each report includes:
- metadata: tool version, timestamp, duration, platform
- input/output: binary path, architecture, format, function count
- passes: per-pass mutation counts, timing, diff summaries
- mutations: flat list with address, bytes, disassembly, function, section
- validation: mode, results, symbolic coverage
- gate_evaluation: severity gate outcomes for CI
- summary: aggregated statistics
Requirements
- Python 3.10+
- radare2
- Optional:
lief(PE/Mach-O/section creation),angr(symbolic validation),frida(instrumentation),z3-solver(MBA simplification)
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Support the Project
If you find r2morph useful, consider supporting its development:
License
This project is licensed under the MIT License - see the LICENSE file for details.
Attribution Required:
- Author: Marc Rivero | @seifreed
- Repository: github.com/seifreed/r2morph
Made with dedication for the reverse engineering community
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file r2morph-0.3.0.tar.gz.
File metadata
- Download URL: r2morph-0.3.0.tar.gz
- Upload date:
- Size: 508.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0f7dbcc092ff4a6b24fb89634190777632141e24b08047cb0fd1b387244094e
|
|
| MD5 |
813c93a8c4a2926755ca37bb67f6a92f
|
|
| BLAKE2b-256 |
23ec5c4f0f2f2a0bb5d3157a3bb8745c2d90f32d9f192b0f538d2a16a373289f
|
Provenance
The following attestation bundles were made for r2morph-0.3.0.tar.gz:
Publisher:
release.yml on seifreed/r2morph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
r2morph-0.3.0.tar.gz -
Subject digest:
d0f7dbcc092ff4a6b24fb89634190777632141e24b08047cb0fd1b387244094e - Sigstore transparency entry: 1190780523
- Sigstore integration time:
-
Permalink:
seifreed/r2morph@4e3e3248bdfb59edbdfe988ccfef40050c7639b3 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/seifreed
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4e3e3248bdfb59edbdfe988ccfef40050c7639b3 -
Trigger Event:
push
-
Statement type:
File details
Details for the file r2morph-0.3.0-py3-none-any.whl.
File metadata
- Download URL: r2morph-0.3.0-py3-none-any.whl
- Upload date:
- Size: 594.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3898204bac384711cec16208395f36aac2de5878078980391fb5d100bca26383
|
|
| MD5 |
49c9cff7ef6da8f0e3889f93bfc22206
|
|
| BLAKE2b-256 |
8d84f51cdd2d738b89c14b95f04c8b4b2f9f5ac0fda96037dbab2274dc0fca50
|
Provenance
The following attestation bundles were made for r2morph-0.3.0-py3-none-any.whl:
Publisher:
release.yml on seifreed/r2morph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
r2morph-0.3.0-py3-none-any.whl -
Subject digest:
3898204bac384711cec16208395f36aac2de5878078980391fb5d100bca26383 - Sigstore transparency entry: 1190780544
- Sigstore integration time:
-
Permalink:
seifreed/r2morph@4e3e3248bdfb59edbdfe988ccfef40050c7639b3 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/seifreed
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4e3e3248bdfb59edbdfe988ccfef40050c7639b3 -
Trigger Event:
push
-
Statement type: