Windows x64 polymorphic machine-code rewriter. N faces, one body. One static morphkatz.exe that rewrites
PE binaries into semantically identical but byte-different variants.
---
MorphKatz rewrites x86-64 machine code inside PE executables and raw shellcode
into **semantically identical but byte-different** equivalents. Same arithmetic,
same observable EFLAGS effects, same control-flow — different bytes. That
breaks byte-pattern detection (YARA rules, Defender signatures, Elastic rules,
Sigma detection content) without changing what the code actually does.
## Live Demo
> Scan → **detected** (`HackTool:Win32/AmDisable!MTB`) → morph with `--data-morph on` → scan again → **clean** → run → bypass still works at runtime.
## Who it's for
MorphKatz is built for **two complementary audiences**, and we treat both as
first-class:
### 🛡️ Detection engineers / Blue team
If your job is to write YARA rules, Defender custom indicators, Elastic
detection content, or Sigma rules, MorphKatz tells you **how durable each rule
actually is**. Pipe one of your malware samples through MorphKatz with
`--variants 50` and `--target your-yara/*.yar` and you get back, per rule, the
percentage of variants on which it still triggers. Rules that fall off a
cliff under polymorphic mutation are the ones an evolving threat actor will
silence first; you want to harden those before the actor does.
Specific Blue-team workflows:
- **Detection-engineering coverage testing** — quantify "what % of my rules
are one equivalent-swap away from silence?".
- **Signature triage** — see exactly which bytes in a PE drove a Defender
detection (`morphkatz scan --bisect`), and use that to harden or generalise
the rule.
- **Polymorphic-robust classifier training** — generate diverse but
semantically identical training data for ML malware classifiers.
- **Binary-similarity research** — generate evaluation corpora with known
ground truth (every variant shares the same source semantics).
### 🗡️ Red team / Authorised offensive research
If you're testing detection coverage from the offensive side under a clear
rules-of-engagement paper trail, MorphKatz turns "manually rewrite five
gadgets and recompile" into a rules-of-engagement-friendly automation:
- **Rules-of-engagement-friendly evasion** — every mutation is rule-cited from
the Intel SDM, every run is reproducible from `--seed`, every change lands
in a JSON / HTML diff report you can drop into the engagement deliverable.
- **Reproducibility for your write-up** — same seed, same input, byte-for-byte
identical output, on any machine.
- **Author-audited rules only** — MorphKatz refuses to ship pop-malware-of-
the-month rule packs. Every rule has a cited semantic-equivalence proof in
its YAML.
What MorphKatz is **not**:
- ❌ A live-malware obfuscator. We deliberately do not target the
pop-malware-of-the-month list — see [`RESPONSIBLE_USE.md`](RESPONSIBLE_USE.md).
- ❌ A behavioural / ML-evasion tool. MorphKatz mutates *bytes* with
preserved semantics; ML detections (anything ending in `!ml`) evaluate
global behaviour and won't budge — that class of evasion is out of
scope.
- ❌ A black box. Every rule's equivalence proof, every diff report's
metric, every byte changed is yours to audit.
## Features
- **CFG-aware disassembly** — Zydis-powered recursive descent with
jump-table recovery; data-in-code regions are never accidentally
decoded.
- **In-process encoding** — Zydis encoder generates patched
instructions in the same address space, zero IPC overhead.
- **YAML rule packs** — every rewrite rule lives under `rules/x64/`,
reviewable and hot-swappable. Add your own without recompiling.
- **Typed intermediate representation** — `ir::Instruction` carries
full Zydis operand metadata through the entire rewrite pipeline.
- **EFLAGS liveness** — full effect model (AF/CF/OF/PF/SF/ZF) with
per-basic-block dataflow so rewrites never corrupt flag state.
- **Seeded polymorphism** — `xoshiro256**` RNG; `--seed N` gives
byte-for-byte reproducible output on any machine.
- **Intel SDM NOP padding** — 1..9-byte multi-byte NOP rotation drawn
from the Intel Optimization Reference Manual.
- **Semantic verification** — re-disassembly check by default;
optional Unicorn basic-block emulation (`--verify unicorn`).
- **YARA-aware targeting** — `--target rules.yar` prioritises rewrites
that break specified signature atoms.
- **Defender feedback loop** — `--target-defender` runs MpCmdRun,
bisects anchors, and feeds them into the priority queue automatically.
- **Data-section morphing** — `--data-morph on` XOR-encodes
signature-bearing byte sequences in `.rdata` / `.data` and decodes
them at runtime via a polymorphic stub with an anti-emulation gate.
- **JSON + HTML reports** — per-offset before/after diffs, rule IDs,
and detection-coverage metrics.
- **PE hygiene** — `CheckSumMappedFile`, Authenticode strip,
reproducible timestamp, Rich-header `preserve|strip|randomize`.
- **Single static binary** — one `morphkatz.exe`, no runtime
dependencies.
## Quick start
### Prerequisites
- **Windows 10+** / Windows Server 2019+, x64.
- **Visual Studio 2022 17.8+** with "Desktop development with C++" and the
MSVC v143 toolset.
- **CMake 3.27+** (bundled with recent VS installers).
- **[vcpkg](https://github.com/microsoft/vcpkg)**:
```powershell
git clone https://github.com/microsoft/vcpkg
.\vcpkg\bootstrap-vcpkg.bat
[Environment]::SetEnvironmentVariable('VCPKG_ROOT', (Resolve-Path .\vcpkg), 'User')
```
### Build — classic Visual Studio `.sln` (one-click)
MorphKatz does **not** commit `.sln` / `.vcxproj` files — they are generated
from `CMakeLists.txt` on demand so target wiring, include dirs, and vcpkg
linkage stay authoritative in one place. For the classic "double-click the
.sln" experience:
```powershell
.\Open-in-VS.cmd # default: preset vs2022-x64
.\Open-in-VS.cmd -Preset vs2022-x64-asan # ASan build
.\Open-in-VS.cmd -Fresh # nuke CMake cache first
.\Open-in-VS.cmd -NoOpen # configure only; for CI / scripting
```
`Open-in-VS.cmd` (a thin wrapper over `scripts\open-in-vs.ps1`) checks
`VCPKG_ROOT`, runs the CMake VS generator, and launches the generated
`build\\MorphKatz.sln` in the matching Visual Studio install
(located via `vswhere`). Once open, set `morphkatz` as the startup project
and hit F5.
Equivalent manual flow:
```powershell
cmake --preset vs2022-x64
start build\vs2022-x64\MorphKatz.sln
```
### Build — VS 2022 "Open Folder" / CMake mode
```powershell
# In Visual Studio: File > Open > Folder... -> (this repo)
# Select the vs2022-x64 configuration, hit F5.
# `.vs\launch.vs.json` is pre-wired with --version / --help / dry-run targets.
```
### Build — CLI only (Ninja)
```powershell
cmake --preset ninja-x64-release
cmake --build --preset ninja-x64-release
ctest --preset ninja-x64-release --output-on-failure
.\build\ninja-x64-release\morphkatz.exe --version
```
### Presets
| Preset | Purpose |
|---------------------|--------------------------------------------------------|
| `vs2022-x64` | Emits `MorphKatz.sln` + `.vcxproj`. Default developer workflow. |
| `vs2022-x64-asan` | Same, with MSVC `/fsanitize=address`. |
| `ninja-x64-release` | CLI Release build. CI-fast. |
| `ninja-x64-debug` | CLI Debug build. |
| `clang-cl-asan` | `clang-cl` with ASan + UBSan. CI fuzzing. |
## Usage
### First-run / bare-invocation
Double-clicking `morphkatz.exe` or running it with no arguments prints
a compact banner and the top five examples — no silent crash, no empty
help dump:
```text
/\_/\ /\_/\ /\_/\
( o.o ) ( -.- ) ( ^.^ )
> ^ < > ^ < > ^ <
\_________|_________/
|
[ PE ]
M o r p h K a t z
N faces, one body - polymorphic PE rewriter (Windows x64)
Coded by Mohammed Abuhassan
Usage: morphkatz [options]
morphkatz compare [more...] [--report out.json]
morphkatz scan [--bisect] [--report out.html]
Quick start:
morphkatz payload.exe --seed 42 --report report.html
morphkatz payload.exe --seed 1 --variants 8 --report batch.json
morphkatz target.exe --target yara/*.yar -vv
morphkatz target.exe --target-defender target.exe --report run.html
morphkatz compare v0.exe v1.exe --report cmp.html
morphkatz scan suspect.exe --bisect --report scan.json
Run 'morphkatz --help' for all options.
Run 'morphkatz compare --help' for the comparison subcommand.
Run 'morphkatz scan --help' for Defender scanning options.
Run 'morphkatz --version' for build info.
```
### Full option surface
```text
morphkatz [options]
Input/output:
-o, --output Default: .patched. (foo.exe -> foo.patched.exe)
--backup Write .bak (default on)
--in-place Overwrite input (requires --no-backup)
Modes:
--profile {safe,normal,aggressive} Default: normal
--target Prioritise rewrites that break these YARA rules
--rules Load custom YAML rule packs
Polymorphism:
--seed Reproducible run
--mutation-budget Max rewrites per basic block
--variants Emit N deterministic morphs (1..1000);
outputs go to