Skip to content

Repository files navigation

r2morph

r2morph

Metamorphic mutation engine with structured validation and reporting

PyPI Version Python Versions License CI Status Coverage

GitHub Stars GitHub Issues Buy Me a Coffee


Overview

r2morph is a metamorphic mutation engine that applies tracked binary transformations with validation, rollback, and machine-readable reports. The 0.4.0-alpha.3 support contract is intentionally narrow: Linux ELF x86-64 is the official target. Other formats and architectures remain preview or experimental.

Key Features

Feature Description
Tier 1 Passes NOP, instruction substitution, and register substitution on the official target
Declared Support Linux ELF x86-64; preview and experimental targets are tracked separately
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.12 or 3.13
  • 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
python -m pip install --editable ".[dev]"

The CI dependency manifest remains available for reproducing the extended analysis environment: python -m pip install -r requirements.txt followed by python -m pip install --editable ..


Support Matrix

Formats

Format Status Notes
ELF Official: Linux x86-64 Other ELF architectures are experimental
PE Preview/alpha No zero-defect guarantee
Mach-O Experimental No zero-defect guarantee

Architectures

Architecture NOP Substitute Register Expand Block Dead Code
x86_64 Linux ELF Tier 1 Tier 1 Tier 1 Experimental Experimental Experimental
x86 Experimental Experimental Experimental Experimental Experimental Experimental
AArch64/ARM Experimental Experimental Experimental Experimental Experimental Experimental

PE, Mach-O, ARM, and AArch64 evidence does not imply parity with Linux ELF x86-64 or equivalent CodeVirtualization support.

The machine-readable contract is docs/support-matrix.json: the generated matrix currently records 22/22 evidenced cells for the official ELF x86-64 target (100.0% evidence) and 7/242 evidenced cells for non-official targets (2.89% evidence). It currently classifies 3 passes as Tier 1 and 19 passes as experimental. The scheduled extended maturity smoke now records output-size, transform-duration, runtime-duration, and static metric summaries for every selected pass. The same summary still records 12 with no independent false-positive measurement, 12 with no independent decompiler-effectiveness measurement, 11 without contractual composition support, and no remaining affected-instruction catalogue gap. The reproducible GCC/Clang corpus and its build manifest live in the public r2morph-corpus repository.

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

Tier 1 (official target)

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 Surface 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 engine-only Injects semantically neutral code in padding regions
Control Flow Flattening engine-only Inserts opaque predicates and jump obfuscation
Opaque Predicates engine-only Writes opaque predicate instructions into basic blocks
Code Virtualization engine-only Translates instructions to VM bytecode with dispatcher
Anti-Disassembly engine-only Injects anti-disassembly snippets
Data Flow Mutation engine-only Data flow analysis-driven safe substitutions
Short Jump Patching engine-only Patches short jumps to equivalent sequences
Constant Unfolding engine-only Unfolds constant expressions into multi-instruction equivalents
Code Mobility engine-only Relocates blocks to code caves with trampolines
Function Outlining engine-only Distributes function chunks across code caves
API Hashing engine-only Hash trampolines obscuring PLT references
Import Obfuscation engine-only Jump stub indirection for import calls
Self-Modifying Code engine-only XOR-encrypts function bodies with runtime decryptor
Stack Strings engine-only Rebuilds string literals on the stack at runtime
String Obfuscation engine-only Encodes string data behind runtime reconstruction
Pattern Substitution engine-only Applies size-preserving byte-pattern substitutions
Polymorphic Engine engine-only Orchestrates iterative experimental mutation passes

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

The scheduled differential corpus runs --passes all, --require-applied, and --require-complete-evidence; complete evidence covers runtime, output size, transform duration, runtime duration, and static analyzer evidence while comparing exit code, stdout, stderr, created files, and declared observable effects across nine seed-derived inputs.

The current local adversarial analyzer fixture records 5 completed analyzer slots and 4 unavailable analyzer slots with reasons in docs/protection-adversarial-angr-local-2026-09-13-13214f9.json. Binary Ninja is an explicit analyzer slot; the current local fixture records binary-ninja as unavailable because module 'binaryninja' is unavailable. The VM review packet still has human_signoff: not-attested and release_decision: block-vm-milestone; memory, direct/indirect calls, returns, flags, FP/SIMD, varargs/ABI, unwinding, TLS/signals, SSA, and liveness paths remain explicit review scope, and unsupported instructions must fail closed instead of producing partial protected functions. Unsupported-instruction diagnostics must include instruction address, mnemonic, type, size, bounded opcode preview, capability, and reason. VM ISA/opcode diversification, dispatcher/handler alternatives, superinstructions, anti-tamper, and progressive bytecode protection remain explicit human-review scope before the virtualizer milestone can be marked complete. Current VM resistance artifacts cover 10 seeds with 255 handlers per seed, 0 exact normalized cross-seed handler matches, 12 handler stride values, and target handler stride diversity recorded in docs/protection-handler-clustering.json and docs/protection-bytecode-grammar.json.


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 fixtures/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.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Support the Project

If you find r2morph useful, consider supporting its development:

Buy Me A Coffee

License

This project is licensed under the MIT License - see the LICENSE file for details.

Attribution Required:


Made with dedication for the reverse engineering community

About

A metamorphic binary transformation engine based on r2pipe and radare2.

Topics

Resources

Stars

53 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages