A metamorphic binary transformation engine based on r2pipe and radare2.
Author: Marc Rivero | @seifreed Contact: mriverolopez@gmail.com
r2morph is a powerful framework for analyzing and transforming binary executables through semantic-preserving mutations. It leverages radare2 and r2pipe to perform deep binary analysis and apply metamorphic transformations that change the binary signature while maintaining program semantics.
Perfect for:
- Security research and malware analysis
- Evasion technique testing
- Binary obfuscation research
- Defensive security tool development
- Deep Binary Analysis: Leverage radare2's powerful analysis engine
- Metamorphic Transformations: Apply semantic-preserving code mutations
- Modular Architecture: Extensible pipeline-based design
- Multi-Architecture: Support for PE/ELF/Mach-O on x86/x64/ARM
- Plugin System: Easy-to-create custom mutation passes
- Rich Analytics: Detailed statistics and reporting
- CLI + Python API: Powerful command-line and programmatic interfaces
- Validation & Testing: Automated validation, fuzzing, regression tests
- Relocation Management: Code cave finding, reference updates
- Anti-Detection Analysis: Evasion scoring, entropy analysis, similarity hashing
- ARM64/ARM32 Support: 180+ patterns for ARM architectures
- Advanced Mutations: Opaque predicates, dead code, control flow flattening
- Platform Support: Code signing for macOS/Windows, format-specific handlers
- Profile-Guided: Hot path detection, execution profiling
- Session Management: Checkpoints, rollback, versioning
- Memory-Efficient Mode: Automatic OOM prevention for large binaries (>50MB)
- Python 3.10 or higher
- radare2 installed on your system
git clone https://github.com/radareorg/radare2
cd radare2
sys/install.sh
pip install r2morph
git clone https://github.com/seifreed/r2morph.git
cd r2morph
pip install -e .
pip install -e ".[dev]"
r2morph input_binary output_binary
r2morph input.exe output.exe -m nop -m substitute -v
r2morph -i input.exe -o output.exe --aggressive
from r2morph import MorphEngine
from r2morph.mutations import NopInsertionPass, InstructionSubstitutionPass
with MorphEngine() as engine:
engine.load_binary("input.exe").analyze()
engine.add_mutation(NopInsertionPass())
engine.add_mutation(InstructionSubstitutionPass())
result = engine.run()
engine.save("output.exe")
print(f"Applied {result['total_mutations']} mutations")
- Instruction Substitution: Replace instructions with semantic equivalents (90+ patterns)
- NOP Insertion: Insert dead code at safe locations
- Register Reassignment: Swap equivalent registers
- Block Reordering: Rearrange code blocks (preserving control flow)
- Instruction Expansion: Expand simple instructions into complex equivalents
- Opaque Predicates: Inject always-true/false conditionals
- Dead Code Injection: Insert code that never executes (3 complexity levels)
- Control Flow Flattening: Transform CFG into dispatcher pattern
from r2morph import Binary
with Binary("/path/to/binary") as binary:
binary.analyze()
functions = binary.get_functions()
print(f"Found {len(functions)} functions")
arch = binary.get_arch_info()
print(f"Architecture: {arch['arch']} ({arch['bits']}-bit)")
from r2morph.validation import BinaryValidator, MutationFuzzer
validator = BinaryValidator()
result = validator.validate(original, mutated)
fuzzer = MutationFuzzer(num_tests=100)
fuzz_result = fuzzer.fuzz(original, mutated)
from r2morph.detection import EvasionScorer
scorer = EvasionScorer()
score = scorer.score(original, mutated)
print(score)
from r2morph import MorphSession
session = MorphSession()
session.start(original)
session.checkpoint("stage1")
session.apply_mutation(NopPass())
session.rollback_to("stage1")
session.finalize(output)
from r2morph.mutations.base import MutationPass
from r2morph.core.binary import Binary
class MyCustomMutation(MutationPass):
def __init__(self):
super().__init__(name="MyCustomMutation")
def apply(self, binary: Binary):
mutations_applied = 0
functions = binary.get_functions()
for func in functions:
pass
return {
"mutations_applied": mutations_applied,
"custom_metric": 42,
}
engine.add_mutation(MyCustomMutation())
See the examples/
directory for complete examples:
basic_analysis.py
: Simple binary analysismorph_binary.py
: Apply transformations to a binaryadvanced_analysis.py
: Advanced analysis featuresadvanced_mutations.py
: Using advanced mutations
r2morph automatically detects large binaries and enables memory-efficient mode to prevent OOM crashes:
- Triggers: Binaries >50MB or >3000 functions
- Batch Processing: r2 restarts every 1000 mutations to free memory
- Conservative Limits: Reduced mutations per function (2 instead of 5)
- Low-Memory r2 Config: Disables caching (
bin.cache=false
,io.cache=false
)
# Automatically handles large binaries (e.g., Qt6WebEngineCore.dll - 148MB)
r2morph large_binary.dll morphed.dll
# Output:
# Large binary detected (147.3 MB, 4261 functions)
# Enabling memory-efficient mode to prevent OOM crashes
# Batch checkpoint: 1000 mutations applied. Reloading r2 to free memory...
Memory-efficient mode is 100% transparent - no code changes needed. Just run r2morph normally and it will auto-detect and protect against OOM.
┌─────────────┐
│ Binary │ ← Load binary with r2pipe
└──────┬──────┘
│
▼
┌─────────────┐
│ Analysis │ ← Analyze with radare2
└──────┬──────┘
│
▼
┌─────────────┐
│ Pipeline │ ← Execute mutation passes
│ │
│ ┌────────┐ │
│ │ Pass 1 │ │
│ └────────┘ │
│ ┌────────┐ │
│ │ Pass 2 │ │
│ └────────┘ │
│ ┌────────┐ │
│ │ Pass N │ │
│ └────────┘ │
└──────┬──────┘
│
▼
┌─────────────┐
│ Output │ ← Save morphed binary
└─────────────┘
r2morph/
├── core/ # Binary abstraction, engine
│ ├── binary.py # Binary abstraction
│ ├── engine.py # Morphing engine
│ ├── function.py # Function representation
│ └── instruction.py # Instruction representation
├── mutations/ # 8 mutation passes + ARM rules
│ ├── base.py # Base mutation class
│ ├── nop_insertion.py # NOP insertion
│ ├── instruction_substitution.py # Instruction substitution
│ ├── register_substitution.py # Register reassignment
│ ├── block_reordering.py # Block reordering
│ ├── instruction_expansion.py # Instruction expansion
│ ├── opaque_predicates.py # Opaque predicates
│ ├── dead_code_injection.py # Dead code injection
│ ├── control_flow_flattening.py # CFG flattening
│ ├── arm_rules.py # ARM equivalence patterns
│ └── arm_expansion_rules.py # ARM expansion patterns
├── analysis/ # CFG, dependencies, diff analysis
│ ├── analyzer.py # Binary analyzer
│ ├── cfg.py # Control flow graph
│ ├── dependencies.py # Data dependencies
│ ├── invariants.py # Code invariants
│ └── diff_analyzer.py # Binary diff analysis
├── validation/ # Testing, fuzzing, regression
│ ├── validator.py # Binary validator
│ ├── fuzzer.py # Mutation fuzzer
│ └── regression.py # Regression tester
├── relocations/ # Code caves, reference updates
│ ├── manager.py # Relocation manager
│ ├── cave_finder.py # Code cave finder
│ └── reference_updater.py # Reference updater
├── detection/ # Evasion scoring, entropy
│ ├── evasion_scorer.py # Evasion scorer
│ ├── similarity_hasher.py # Fuzzy hashing
│ └── entropy_analyzer.py # Entropy analysis
├── platform/ # PE/ELF/Mach-O handlers, code signing
│ ├── codesign.py # Code signing
│ ├── pe_handler.py # PE format handler
│ ├── elf_handler.py # ELF format handler
│ └── macho_handler.py # Mach-O format handler
├── profiling/ # Hot path detection, profiling
│ ├── profiler.py # Execution profiler
│ └── hotpath_detector.py # Hot path detector
├── pipeline/ # Pipeline orchestration
│ └── pipeline.py # Pipeline management
├── utils/ # Utilities
│ ├── logging.py # Logging configuration
│ └── assembler.py # Assembly helpers
├── session.py # Checkpoint & rollback
└── cli.py # Command-line interface
- Create a new file in
r2morph/mutations/
- Subclass
MutationPass
- Implement the
apply()
method - Add to
r2morph/mutations/__init__.py
Example:
from r2morph.mutations.base import MutationPass
class MyMutation(MutationPass):
def __init__(self, config=None):
super().__init__(name="MyMutation", config=config)
def apply(self, binary):
return {"mutations_applied": 0}
This project is licensed under the MIT License - see the LICENSE file for details.
This tool is for research and educational purposes only. Users are responsible for ensuring they have proper authorization before analyzing or modifying any binary. The authors are not responsible for any misuse of this tool.
- Author: Marc Rivero | @seifreed
- Email: mriverolopez@gmail.com
- Issues: GitHub Issues
- Repository: https://github.com/seifreed/r2morph
If you use r2morph in your research, please cite:
@software{r2morph,
title = {r2morph: A Metamorphic Binary Transformation Engine},
author = {Marc Rivero},
year = {2025},
url = {https://github.com/seifreed/r2morph}
}