██████╗ ██████╗ ██████╗ ██████╗ █████╗
██╔════╝██╔═══██╗██╔══██╗██╔══██╗██╔══██╗
██║ ██║ ██║██████╔╝██████╔╝███████║
██║ ██║ ██║██╔══██╗██╔══██╗██╔══██║
╚██████╗╚██████╔╝██████╔╝██║ ██║██║ ██║
╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝
Post-compilation x86-64 binary obfuscator for Windows PE executables and DLLs.
Cobra operates directly on compiled .exe and .dll binaries — no source code, no recompilation, no compiler plugins. Hand it a PE binary and it produces an obfuscated copy with a new .cobra code section containing transformed function bodies.
Supports binaries compiled with GCC (MinGW), Clang, MSVC, Rust, and Go.
Destroys the natural control flow graph by replacing it with a dispatcher-based state machine. Each basic block becomes a case in a central switch, with transitions driven by a state register (R15). Static analysis tools see a single flat loop instead of the original branching structure.
Injects semantically-inert instruction sequences between real instructions — NOPs, self-canceling XORs, balanced ADD/SUB pairs. Inflates function bodies and breaks signature-based pattern matching without affecting program behavior.
Adds unreachable code blocks guarded by opaque predicates (cmp rsp, 0; je ... — RSP is never zero). These dead paths contain realistic-looking instruction sequences that waste analyst time and confuse decompilers.
Replaces instructions with semantically equivalent alternatives. Breaks byte-level signatures while preserving exact program semantics.
Automatically identifies CRT/runtime functions via inverted call graph analysis — BFS from the entry point marks runtime code, everything else is user code. Aggressive passes (CFF, dead-code) are only applied to confirmed user functions, preventing breakage of statically-linked library code.
Reports detailed metrics after each run: .text coverage, function counts, expansion ratio, and pass breakdown.
All transforms use a seeded PRNG. Same seed, same output — useful for debugging, CI, and deterministic builds.
- Parse the PE binary — reads section headers,
.pdataexception table, relocations - Discover functions via
.pdataRUNTIME_FUNCTION entries - Classify — inverted CRT detection identifies runtime vs user functions via call graph BFS from entry point
- Lift each function into an IR (basic blocks + CFG)
- Transform — runs the pass pipeline with per-function pass selection:
- All user functions:
insn_substitution → junk_insertion - Main-reachable functions: additionally
dead_code → control_flow_flatten
- All user functions:
- Encode transformed functions into machine code
- Emit a new
.cobrasection containing all obfuscated function bodies - Patch original functions with
jmptrampolines redirecting into.cobra
# Basic usage — works on .exe and .dll
cobra-obfuscator -i target.exe -o target_obf.exe
cobra-obfuscator -i library.dll -o library_obf.dll
# With a fixed seed for reproducibility
cobra-obfuscator -i target.exe -o target_obf.exe --seed 42
# Disable specific passes
cobra-obfuscator -i target.exe -o target_obf.exe --disable junk-insertion,dead-code
# Multiple iterations (stack transforms)
cobra-obfuscator -i target.exe -o target_obf.exe --iterations 2
# Adjust junk density (0.0–1.0)
cobra-obfuscator -i target.exe -o target_obf.exe --junk-density 0.5| Option | Description | Default |
|---|---|---|
-i, --input |
Input PE binary (.exe or .dll) |
required |
-o, --output |
Output file path | required |
--seed |
RNG seed for deterministic output | random |
--iterations |
Number of pass iterations | 1 |
--disable |
Comma-separated passes to skip | none |
--junk-density |
Junk insertion probability (0.0–1.0) | 0.3 |
--format |
Force input format: auto, coff, pe |
auto |
control-flow-flattenjunk-insertiondead-codeinsn-substitution
cargo build --releaseThe binary lands in target/release/cobra-obfuscator.exe.
Requirements: Rust toolchain (stable). No external dependencies beyond crates.
The test matrix covers multiple compilers, optimization levels, pass combinations, and seeds:
- Compilers — GCC (MinGW), Clang (MinGW target), MSVC (cl.exe), Rust (debug + release), Go
- Optimization levels —
-O0through-O3,-Os(GCC/Clang),/Od,/O1,/O2(MSVC) - 9 C test programs — minimal, medium, loops, recursion, switch_heavy, selfval, bitops, structs, func_ptrs
- 2 Rust test programs — rust_crypto, rust_structs (debug + release builds)
- 2 Go test programs — go_algorithms, go_crypto
- DLL tests — C DLL and Rust cdylib with loader programs that validate exported functions
- 11 pass combinations — all passes, each pass solo, pairwise combos, triple combos
- 10 seeds per configuration
Test programs exercise: deep nesting, mutual recursion, Ackermann function, binary exponentiation, bubble sort, state machines, large/sparse/nested switch statements, heap allocation, function pointers, bitwise operations, structs, hashing, sorting, primality testing, and cryptographic operations.
# Run the full matrix (auto-detects available compilers)
cd tests && bash run_matrix.sh| Target | .text Coverage | Status |
|---|---|---|
| C (GCC, 9 programs) | 58–63% | All pass |
| Rust (debug + release) | 76–84% | All pass |
| C DLL (GCC) | ~68% | All pass |
| Rust DLL (cdylib) | ~80% | All pass |
| Large binaries (8MB+) | ~74% | Tested |
src/
├── main.rs CLI entry point
├── lib.rs Library API
├── config.rs ObfuscatorConfig
├── pipeline.rs Orchestrates PE/COFF obfuscation + statistics
├── passes/
│ ├── pass_trait.rs ObfuscationPass trait + PassContext
│ ├── control_flow_flatten.rs
│ ├── junk_insertion.rs
│ ├── dead_code.rs
│ └── insn_substitution.rs
├── ir/
│ ├── instruction.rs IrInsn (wraps iced-x86)
│ ├── basic_block.rs BasicBlock + successors
│ ├── function.rs Function IR container
│ ├── cfg.rs CFG construction
│ └── relocation.rs Relocation tracking
├── pe/
│ ├── reader.rs PE parsing, function discovery, CRT detection
│ ├── writer.rs .cobra section creation + trampolines
│ ├── pdata.rs Exception table parsing
│ └── reloc.rs PE relocation handling
├── coff/
│ ├── reader.rs COFF object file parsing
│ ├── writer.rs COFF output
│ └── types.rs COFF data structures
└── encode/
├── assembler.rs IR → machine code (BlockEncoder)
└── reloc_fixup.rs Post-encode relocation validation
- x86-64 only — no 32-bit support
- Windows PE only — no ELF/Mach-O (yet)
- Functions with jump tables (indirect branches) are skipped to preserve correctness
- CRT/runtime functions are intentionally excluded from transformation
- Go binaries: obfuscation runs but runtime metadata (.gopclntab) is not patched, so obfuscated Go binaries may crash
MIT