ββββ ββββ ββββββ βββ βββββββ βββββββββββ
βββββ ββββββββββββββββ βββββββββ βββββββββββ
ββββββββββββββββββββββββββ ββββββ βββββββββ
ββββββββββββββββββββββββββ ββββββββββββββββ
βββ βββ ββββββ ββββββ ββββββ ββββββββββββββ
βββ ββββββ ββββββ ββββββ βββββββββββββ
An advanced binary-level mutation and obfuscation framework for PE (Portable Executable) both 32-bit (x86) and 64-bit (x64) binaries written in C++17. Leveraging the high-performance Zydis disassembler backend, the engine dynamically parses PE files, identifies instruction/basic block boundaries, applies polymorphic and metamorphic transformation passes, and rebuilds the executable with modified section structures and updated PE metadata.
The project follows a clean, modular C++ directory layout separating definitions (headers) from source code and configurations:
makne/
βββ CMakeLists.txt # Cross-platform build configuration
βββ README.md # Project documentation
βββ include/ # Header files
β βββ PEStructs.h # Native PE structures definitions (DOS, COFF, Optional headers)
β βββ CodeReorderer.h # Basic block analysis and shuffling definitions
β βββ ControlFlowObfuscator.h # Control flow flattening & opaque predicate definitions
β βββ DataEncoder.h # Data/String encoding & decoder stub generation
β βββ DecryptorGenerator.h # Polymorphic decryptor stub creation
β βββ ImportObfuscator.h # IAT obfuscation and API hashing definitions
β βββ InstructionSubstitutor.h# Instruction-equivalent database mapping
β βββ JunkCodeInserter.h # Dead code/junk sequence generator
β βββ MetamorphicEngine.h # High-level metamorphic mutation pipeline
β βββ PayloadEncryptor.h # Section-level encryption management
β βββ PolymorphicEngine.h # Core processing, PE parsing, and orchestrator
β βββ RegisterRandomizer.h # ModR/M register mapping and randomization
β βββ SectionRandomizer.h # PE section name, layout, and alignment shuffler
β βββ Utils.h # Randomness and helper definitions
βββ src/ # Implementation files
βββ main.cpp # Command-line driver and argument parser
βββ CodeReorderer.cpp # Basic block identification, jump fixing, and shuffling
βββ ControlFlowObfuscator.cpp # Flow flatters, dispatchers, and opaque predicates
βββ DataEncoder.cpp # XOR, Base64, and split-string algorithms
βββ DecryptorGenerator.cpp # Dynamic x86 assembly generator for decryption
βββ ImportObfuscator.cpp # IAT parsing, dynamic DLL resolution, and API hashing
βββ InstructionSubstitutor.cpp # x86 equivalent instruction mapping execution
βββ JunkCodeInserter.cpp # NOP-equivalent & flag-safe instruction generation
βββ MetamorphicEngine.cpp # Loop unrolling, inlining, and expansion levels
βββ PayloadEncryptor.cpp # XOR encryption and decryption insertion logic
βββ PolymorphicEngine.cpp # Core engine implementation (PE parsing, rebuilding)
βββ RegisterRandomizer.cpp # Register swapping and translation tables
βββ SectionRandomizer.cpp # Section shuffling, renaming, and alignment fixing
βββ Utils.cpp # Cryptographic RNG (CryptoRandom)
This document details the step-by-step binary-level mutation, encryption, and obfuscation pipeline of the makne framework. It maps the conceptual execution flow directly to the project's C++ classes and source files, and explains how to configure or extend the pipeline to achieve nested multi-layered encryption. The diagram below illustrates the target obfuscation design. Red indicates the RC4-encrypted layer, and Blue denotes the Random Block Cipher-encrypted layer. Dashed lines inside a box indicate component boundaries within the encrypted payload.
flowchart LR
%% Global styling
classDef default fill:#FFFFFF,stroke:#333333,stroke-width:1.5px,color:#000000;
classDef decryptor fill:#F4F4F9,stroke:#333333,stroke-dasharray: 0;
%% STATE 1: Raw Payload
subgraph State1 ["1. Raw Payload"]
direction TB
s1_payload["Payload"]
end
%% STATE 2: Optional Loader Add
subgraph State2 ["2. Payload + Loader"]
direction TB
s2_payload["Payload"]
s2_loader["Loader"]
s2_payload --- s2_loader
end
%% STATE 3: Garbage Stub Add
subgraph State3 ["3. Obfuscated Stack"]
direction TB
s3_garbage["Garbage Stub"]
s3_payload["Payload"]
s3_loader["Loader"]
s3_garbage --- s3_payload
s3_payload --- s3_loader
end
%% STATE 4: RC4 Encryption
subgraph State4 ["4. RC4 Encrypted"]
direction TB
s4_decryptor["RC4 Decryptor"]
subgraph State4_RC4 ["RC4 Encrypted Block"]
direction TB
s4_garbage["Garbage Stub"]
s4_payload["Payload"]
s4_loader["Loader"]
s4_garbage -.- s4_payload
s4_payload -.- s4_loader
end
s4_decryptor === State4_RC4
end
%% STATE 5: Block Cipher Encryption
subgraph State5 ["5. Block Cipher Encrypted"]
direction TB
subgraph State5_Block ["Random Block Cipher Encrypted"]
direction TB
s5_decryptor["RC4 Decryptor"]
subgraph State5_RC4 ["RC4 Encrypted Block"]
direction TB
s5_garbage["Garbage Stub"]
s5_payload["Payload"]
s5_loader["Loader"]
s5_garbage -.- s5_payload
s5_payload -.- s5_loader
end
s5_decryptor === State5_RC4
end
s5_bc_decryptor["Block Cipher Decryptor"]
State5_Block === s5_bc_decryptor
end
%% STATE 6: Final Obfuscated Executable
subgraph State6 ["6. Final Payload"]
direction TB
s6_garbage_outer["Garbage Stub"]
subgraph State6_Block ["Random Block Cipher Encrypted"]
direction TB
s6_decryptor["RC4 Decryptor"]
subgraph State6_RC4 ["RC4 Encrypted Block"]
direction TB
s6_garbage["Garbage Stub"]
s6_payload["Payload"]
s6_loader["Loader"]
s6_garbage -.- s6_payload
s6_payload -.- s6_loader
end
s6_decryptor === State6_RC4
end
s6_bc_decryptor["Block Cipher Decryptor"]
s6_garbage_outer === State6_Block
State6_Block === s6_bc_decryptor
end
%% State Transitions (with arrows)
State1 ==> |"Optional Loader"| State2
State2 ==> |"Garbage Stub"| State3
State3 ==> |"RC4 Cipher"| State4
State4 ==> |"Random Block Cipher"| State5
State5 ==> |"Garbage Stub"| State6
%% Color styling matching the original diagram
style State4_RC4 stroke:#FF3333,stroke-width:2.5px,fill:#FFF8F8
style State5_RC4 stroke:#FF3333,stroke-width:2.5px,fill:#FFF8F8
style State6_RC4 stroke:#FF3333,stroke-width:2.5px,fill:#FFF8F8
style State5_Block stroke:#3333FF,stroke-width:2.5px,fill:#F8F8FF
style State6_Block stroke:#3333FF,stroke-width:2.5px,fill:#F8F8FF
style s4_decryptor fill:#F4F4F9,stroke:#333333
style s5_decryptor fill:#F4F4F9,stroke:#333333
style s6_decryptor fill:#F4F4F9,stroke:#333333
style s5_bc_decryptor fill:#F4F4F9,stroke:#333333
style s6_bc_decryptor fill:#F4F4F9,stroke:#333333
The engine features two distinct modes of transformation which can be combined (Mixed Mode):
- Zydis Disassembler Backend: Replaced custom prefix/opcode length parsers with a full-featured Zydis decoder to safely identify x86/x64 instruction boundaries, decode operand layouts, and perform atomic byte stream modifications.
-
Instruction Substitution: Replaces instruction patterns with equivalent CPU sequences. For example:
-
MOV reg, Imm$\rightarrow$ PUSH Imm; POP reg -
XOR reg, reg$\rightarrow$ SUB reg, reg -
NOP$\rightarrow$ PUSH RBX; POP RBXorXCHG RAX, RAX -
x64 Safety Filter: Automatically bypasses single-byte legacy
INC(0x40) /DEC(0x48) substitutions on x64 targets to prevent collisions with the REX prefix byte range (0x40-0x4F). -
Width Guards: Substitutions for
ADD reg, 1 β INC reg,SUB reg, 1 β DEC reg, andCMP reg, 0 β TEST reg, regare restricted to 32-bit and 64-bit operand sizes only, preventing flag corruption on 8-bit/16-bit registers. -
REX Prefix Scan: The
LEA reg, [reg] β MOV reg, regsubstitution correctly skips legacy prefixes before checking for a valid REX prefix byte (0x40β0x4F) in 64-bit mode, preserving both legacy and REX prefixes to avoid encoding corruption.
-
-
Register Randomizer: Dynamically re-maps general-purpose register usage while adhering to strict architecture constraints:
-
Calling Convention Safe: Preserves caller/callee boundary registers
RAX/EAX(return values),RCX/ECX, RDX/EDX, R8, R9(arguments),RSP/ESP, RBP/EBP(stack frames), andR12, R13(special SIB addresses). -
Partitioned Shuffle: Safely shuffles registers only within legacy (
RBX, RSI, RDI) and extension (R10, R11, R14, R15) groups, guaranteeing that instruction lengths and REX prefix status remain completely invariant. - Dynamic Implicit-Register Scan: Decodes instruction operands to automatically detect and exclude implicit registers (e.g., EAX/EDX in division, or ESI/EDI/RSI/RDI in string operations) to prevent semantic corruption.
- RIP-Relative Safe-guard: Automatically bypasses register randomization on instructions containing RIP-relative or EIP-relative displacement addressing to maintain correct relative memory references.
-
Calling Convention Safe: Preserves caller/callee boundary registers
-
Import Obfuscation: Erases the original Import Address Table (IAT) names and replaces them with dynamically generated import resolution stubs:
-
x86 targets: Walks the 32-bit PEB
InMemoryOrderModuleListviaFS:[0x30], uppercase case-folds UnicodeBaseDllNamecharacters, and resolves API addresses at runtime using aROR13-ADDhash. The precomputed hash0x6E2BCA17identifiesKERNEL32.DLLrobustly regardless of module load order. -
x64 targets: Walks the 64-bit PEB
InMemoryOrderModuleListviaGS:[0x60], implements full Microsoft x64 calling conventions with 32-byte stack shadow space allocation, and utilizes RIP-relative addressing to locate string table offsets.
-
x86 targets: Walks the 32-bit PEB
-
Exception Directory Relocation: Automatically parses x64
.pdataruntime function tables andUNWIND_INFOstructures to relocate 32-bit exception handler RVAs when shuffling or renaming PE sections. AMapEndRVArange helper correctly recalculatesEndAddressfor functions that grew in size during metamorphic transformation. -
Code Reordering (x86/x64): Groups functions by exact byte size and performs size-matched in-place swaps rather than appending to separate lists. This guarantees that every function's RVA β including those not being shuffled β remains identical to its original value, keeping
.rdataswitch-case jump tables correct while still randomizing thousands of same-sized functions. Zydis is used to parse branch offsets and relative memory displacements to patch targets. -
Junk Code Inserter (x86/x64): Inserts context-aware, benign junk instructions (e.g., flag-safe operations) to modify byte signatures without changing execution behavior. Stack pointer (
ESP/RSP) and frame pointer (EBP/RBP) registers are explicitly excluded from the junk clobber mask using named Zydis register constants, preventing stack/frame corruption. Filters out x86-only instructions on x64. -
Control Flow Obfuscation (x86/x64): Distorts control flow by replacing jumps with equivalent joint condition pairs (e.g.,
JO+JNO) and Jcc conditions with inverted Jcc skips. All short jumps are expanded to near Jcc instructions with 4-byte displacements to eliminate offset overflow. -
Payload Encryption: Encrypts target payload sections (XOR, etc.) and injects dynamically generated decryptor stubs as the entry point. Decryptor stub displacement offsets are calculated dynamically relative to the actual
POPinstruction address rather than using hardcoded values, ensuring correctness regardless of the size of any preceding anti-debug or anti-emulation stubs. On x64 targets, stubs use RIP-relative LEA instructions; on x86 targets, a call-pop GetPC technique is used. - Data Encoding: Encodes static data strings using XOR, Base64, or string-splitting to avoid detection of plaintext strings.
The MetamorphicEngine runs first in the PassManager pipeline, before any other passes (such as CodeReorderer) shuffle instructions. This ordering ensures that control-flow disassembly and jump displacement decoding are always performed on instructions in their original layout.
- Zydis Intermediate Representation: Disassembles and decodes target functions to an IR, rewriting displacements and
%rip-relative displacements to patch jump offsets and relocations on mutations. - Instruction Permutation (x86/x64): Alters instruction positions using Bernstein's data dependency conditions (RAW, WAR, WAW) while preserving stack frame layout registers (
RSP,ESP,RBP,EBP). - Code Expansion: Expands instructions to multi-byte equivalents to vary executable sizing. A dynamic
maxRawSizeheadroom limit (8 KB) is reserved per.textsection to prevent size growth from overlapping adjacent sections. - Localized Short Branch Expansion: Short branch expansion is applied only inside
MetamorphicEngine::DisassembleToIR, scoped to functions actually undergoing metamorphic transformation. This prevents excessive binary size growth from pre-emptive expansion across the entire code section. - Loop Unrolling & Function Inlining: Modifies the stack frame structure and execution sequence by eliminating calls and branches.
- Anti-Debugging / Anti-Emulation: Integrates stubs to detect hypervisors, sandboxes, and debuggers (e.g., PEB checks, timing checks).
- FileAlignment Section Resizing: Safely pads, resizes, and aligns raw PE section size growth to
FileAlignmentboundaries, automatically relocating the COFF symbol table to prevent symbol warnings or image loaders crash. - Relocation Table Rebuilding: Uses
MapRVA(rather thanMapRVAStrict) for mid-instruction base relocs pointing to absolute addresses, constrained to only shift RVAs within the.textsection. This prevents corruption of relocations in.data,.rdata, or import sections.
This project can be compiled as a standalone C++ command-line tool, or installed as a Python package with programmatic C++ wrapper bindings.
You can build and install the project directly as a Python package. The PEP 517 build backend (scikit-build-core) will automatically configure and build the C++ codebase via CMake when installing.
Ensure you have a C++17 compiler (MSVC on Windows, GCC on Linux, Clang on macOS) and CMake installed.
- Windows Source Build Note: If installing from source in a standard PowerShell/CMD terminal, you must specify the generator if MSVC tools are not in your path:
Alternatively, run the command inside a Developer PowerShell for Visual Studio.
$env:CMAKE_GENERATOR="MinGW Makefiles"
pip install makneClone the repository and run:
# Editable install (recommended for developers)
pip install -e .
# Or standard local install
pip install .- CLI usage: Installing the package registers a global command-line entry point:
makne --help
- Python API usage: You can run the obfuscator directly from Python scripts:
import makne # Obfuscate a PE binary return_code = makne.obfuscate("input.exe", "output.exe", ["--polymorphic", "--substitution"]) if return_code == 0: print("Obfuscation successful!")
If you prefer building a standalone native executable without Python, the build system utilizes CMake for configuration and building. The build system automatically fetches dependencies like Zydis disassembler and Zycore via CMake's FetchContent module during configuration, so no manual downloading of submodules is necessary.
- Visual Studio 2019 or 2022 (Community, Professional, or Enterprise).
- During installation, ensure the "Desktop development with C++" workload is checked. This installs the MSVC compiler, CMake, and the required Windows SDKs.
- Alternatively, you can use standalone CMake (3.15+) and Build Tools for Visual Studio.
Open Developer PowerShell for VS or Developer Command Prompt for VS and run:
# Generate the build configuration
cmake -B build -S .
# Build the release binary
cmake --build build --config ReleaseThe compiled executable makne.exe will be located in build/Release/.
- Open Visual Studio.
- Select Open a local folder and choose the root directory containing
CMakeLists.txt. - Visual Studio will automatically detect and configure the CMake project.
- Go to the menu: Build > Build All (or select the
makne.exestartup item and press F5/Ctrl+F5 to build and run).
Install CMake and a C++17 compatible compiler (GCC 8+ or Clang 7+):
- Ubuntu / Debian:
sudo apt update sudo apt install -y build-essential cmake
- Fedora / CentOS / RHEL:
sudo dnf groupinstall -y "Development Tools" sudo dnf install -y cmake - Arch Linux:
sudo pacman -Syu base-devel cmake
Open a terminal in the project root folder:
# Generate build configuration for a Release build
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
# Build the project
cmake --build buildThe compiled executable makne will be located in build/.
- Xcode Command Line Tools: Install them by running the following command in terminal:
xcode-select --install
- CMake: Install CMake using a package manager:
- Homebrew (Recommended):
brew install cmake
- MacPorts:
sudo port install cmake
- Homebrew (Recommended):
Open a terminal in the project root folder:
# Generate build configuration for a Release build
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
# Build the project
cmake --build buildThe compiled executable makne will be located in build/.
graph TD
A[Input PE Binary] --> B[PE Parser]
B --> C[Disassembler & Block Finder]
C --> D{Transformation Mode}
D -->|Polymorphic| E[Polymorphic Pipeline]
D -->|Metamorphic| F[Metamorphic Pipeline]
D -->|Mixed| G[Polymorphic & Metamorphic Pipeline]
E --> H[Payload Encryption & Stub Generation]
F --> I[Block Permutation & Expansion]
G --> J[Combined Transformations]
H --> K[PE Rebuilder & Checksum Generator]
I --> K
J --> K
K --> L[Output Obfuscated PE Binary]
- Parsing (PE Parser):
Loads the raw byte stream of the target
.exefile. Parses the DOS MZ signature, COFF Header, Optional Header, and Sections to build an in-memory structural mapping of code (.text) and data (.data,.rdata) segments. - Code Analysis & Disassembly: Parses machine code instructions, determines byte length boundary offsets, identifies branches (jumps, calls), and isolates independent execution blocks (Basic Blocks).
- Applying Mutations:
Runs the pipeline of selected obfuscation passes.
MetamorphicEngineis always invoked first so that disassembly and jump displacement decoding operate on the original instruction layout before any reordering or substitution passes shift RVAs. The engine tracks offset modifications since instruction substitution, junk insertion, and block shuffling alter virtual addresses (RVAs). - Header Reconstruction & Rebuilding: Adjusts relocations, recalculates Entry Point (OEP), shifts Section Headers offsets, fixes the Import Address Table (IAT) pointers, generates dynamic import-resolving stubs, computes a new PE checksum, and saves the new output binary.
- Windows (PowerShell/CMD):
.\makne.exe <input.exe> <output.exe> [options]
- Linux / macOS:
./makne <input.exe> <output.exe> [options]
| Option | Category | Description |
|---|---|---|
--polymorphic |
Transformation | Apply polymorphic transformations (Default) |
--metamorphic |
Transformation | Apply metamorphic transformations |
--mixed |
Transformation | Combine both polymorphic & metamorphic pipelines |
--substitution |
Polymorphic | Enable instruction substitutions |
--registers |
Polymorphic | Enable register randomization |
--reorder |
Polymorphic | Enable basic block code reordering |
--junk |
Polymorphic | Enable junk/dead code insertion |
--cflow |
Polymorphic | Enable control flow obfuscation (flattening/predicates) |
--encrypt |
Polymorphic | Enable payload section encryption |
--data |
Polymorphic | Enable static data/string encoding |
--sections |
Polymorphic | Randomize section names and layout |
--imports |
Polymorphic | Obfuscate IAT and import names |
--permute <1-5> |
Metamorphic | Set instruction permutation complexity level |
--expand <1-5> |
Metamorphic | Set code expansion multiplier |
--garbage <1-5> |
Metamorphic | Set junk insertion density |
--unroll |
Metamorphic | Enable loop unrolling |
--inline |
Metamorphic | Enable function inlining |
--antidebug |
Advanced | Add anti-debugger stub detections |
--antiemu |
Advanced | Add anti-emulation timing checks |
--level <1-5> |
Advanced | Set global obfuscation intensity (default: 3) |
--iterations <n> |
Advanced | Number of mutation passes to run |
--help |
General | Display help documentation |
Below are examples of how to run the engine. Make sure to run them from the directory containing the compiled executable (build/ or build/Release/), or provide the full path to it.
Verify the installation and see the full list of supported parameters.
- Windows (PowerShell):
.\makne.exe --help
- Linux / macOS:
./makne --help
Applies instruction substitutions, register randomization, code reordering, and section name/layout randomization.
- Windows (PowerShell):
.\makne.exe input.exe output.exe --polymorphic --substitution --registers --reorder --sections
- Linux / macOS:
./makne input.exe output.exe --polymorphic --substitution --registers --reorder --sections
- Explanation of flags:
--polymorphic: Activates the polymorphic transformation pipeline.--substitution: Replaces common instruction patterns with equivalent sequences.--registers: Randomizes general-purpose register usage safely.--reorder: Partitions code into size-matched function groups and shuffles them in-place, preserving all RVAs while maximizing randomization.--sections: Randomizes PE section names and structural layout.
Applies aggressive code expansion, high complexity instruction permutations, loop unrolling, and function inlining.
- Windows (PowerShell):
.\makne.exe input.exe output.exe --metamorphic --permute 5 --expand 4 --unroll --inline
- Linux / macOS:
./makne input.exe output.exe --metamorphic --permute 5 --expand 4 --unroll --inline
- Explanation of flags:
--metamorphic: Activates the metamorphic transformation pipeline.--permute 5: Sets the highest complexity (level 5) for instruction permutation.--expand 4: Sets the code expansion multiplier to 4.--unroll: Enables optimization loop unrolling.--inline: Inlines function calls where safe.
Combines all polymorphic passes simultaneously for maximum coverage.
- Windows (PowerShell):
.\makne.exe input.exe output.exe --polymorphic --substitution --registers --reorder --junk --cflow --encrypt --imports
- Linux / macOS:
./makne input.exe output.exe --polymorphic --substitution --registers --reorder --junk --cflow --encrypt --imports
Combines all metamorphic and polymorphic features, flattens control flow, obfuscates import tables, encodes static strings, adds anti-analysis/debugger/emulation checks, and runs multiple passes.
- Windows (PowerShell):
.\makne.exe input.exe output.exe --mixed --cflow --encrypt --imports --data --antidebug --antiemu --level 5 --iterations 2
- Linux / macOS:
./makne input.exe output.exe --mixed --cflow --encrypt --imports --data --antidebug --antiemu --level 5 --iterations 2
- Explanation of flags:
--mixed: Runs both the polymorphic and metamorphic pipelines sequentially.--cflow: Distorts control flow via dispatchers and opaque predicates.--encrypt: Encrypts target sections and inserts a decryption stub at the entry point.--imports: Obfuscates the Import Address Table (IAT) and dynamically resolves DLLs via PEB walking.--data: Encodes static strings (XOR/Base64/splitting).--antidebug&--antiemu: Injects checks to detect debuggers, hypervisors, and sandboxes.--level 5: Sets global intensity to maximum (5).--iterations 2: Runs the entire mutation pipeline twice to generate nested layers of obfuscation.
This software is developed strictly for educational, security research, and defensive binary analysis purposes. Using this software to obfuscate malware to bypass anti-virus scanners for unauthorized deployment is strictly prohibited and a violation of local and international laws. The developers assume no liability for misuse of this tool.