LLVMmovfuscator is an LLVM-based ARM mov-style / data-transfer-style obfuscation prototype. The current mainline target is AArch64MovLite on Apple Silicon: user-level i32 arithmetic and comparisons are expanded in LLVM IR, control flow is lowered to block-id dispatch, and an isolated experimental LLVM target emits AArch64 assembly that is linked into a native executable.
In the ARM context, "mov" does not mean the literal x86 mov instruction. It means the restricted ARM-Lite model: user semantics are pushed toward MOV/LDR/STR-style data transfer and runtime helpers. libc calls, function ABI, stack frames, call/return, symbol materialization, and runtime dispatch stubs are allowed to use native AArch64 instructions in the current v1 scaffold.
Chinese version: README.zh-cn.md
| Path | Description |
|---|---|
| src/ | LLVM-based ARM mov-style implementation: target-prep pass (pass/) plus runtime stubs (runtime/). See src/README.md. |
| patches/ | Small LLVM-side patches kept in Git instead of committing a full LLVM source tree. |
| llvm-project-21.1.8/ | Local LLVM 21.1.8 source tree. It is not committed to Git and is used to build the pass, Clang, opt, and llc. |
| docs/DESIGN.md | LLVM implementation design and phase plan. Recommended first read. |
| docs/AARCH64_MOVLITE_V1_IMPLEMENTATION.md | AArch64MovLite v1 implementation summary, tradeoffs, verification commands, and current boundaries. |
| movfuscator/ | Local clone of the original M/o/Vfuscator. It is not committed to Git and is used as reference material and validation case source. |
| tests/ | Unicorn example tests, the movfuscator validation runner, and AArch64MovLite basic C dual-execution comparison. |
- v1 feature scope: Cover a basic ANSI C subset on
-O0LLVM IR, including 32-bit signed/unsigned integer arithmetic, comparisons, if/for/while, break/continue, switch, normal functions, recursion, local/global variables, arrays, pointer dereference, malloc/free, and libc boundaries such as printf/puts/putchar/getchar. - v1 implementation path: The
aarch64-movlite-preparepass expands user arithmetic/comparison semantics directly and lowers branches to ARM-Lite dispatch.llc -march=aarch64movliteemits.s, and the system clang/assembler links an arm64 Mach-O executable. The AArch64MovLite runner checks that the final binary does not contain__mov_*helper symbols. - Multi-architecture direction: The current hard acceptance target is Apple Silicon macOS arm64. ARM32 remains design-compatible. The x86 M/o/Vfuscator subtree remains a reference implementation and validation case source.
This repository does not commit the large llvm-project-21.1.8/ or movfuscator/ directories. Prepare them locally:
# After placing the LLVM 21.1.8 source tree at llvm-project-21.1.8/,
# apply the AArch64MovLite target registration patch.
git apply --unidiff-zero patches/llvm-21.1.8-aarch64movlite-target.patch
# To run movfuscator validation cases, clone the original repository locally.
git clone https://github.com/xoreaxeaxeax/movfuscator movfuscator-
Use the original compiler (LCC + mov backend)
cd movfuscator && ./build.sh && sudo ./install.sh movcc example.c -o example
-
Build LLVM-mov with the local LLVM tree
# 1. Build LLVM once. This registers the aarch64movlite target. cmake -S llvm-project-21.1.8/llvm -B build-llvm -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=clang ninja -C build-llvm clang opt llc # 2. Build the pass and runtime. cmake -S src -B build -G Ninja -DLLVM_DIR=$PWD/build-llvm/lib/cmake/llvm ninja -C build
Verify target registration:
build-llvm/bin/llc --version | grep aarch64movlite -
AArch64MovLite compilation pipeline
build-llvm/bin/clang -O0 -S -emit-llvm -target arm64-apple-macosx case.c -o case.ll build-llvm/bin/opt -load-pass-plugin build/pass/MovOnlyPass.so \ -passes=aarch64-movlite-prepare case.ll -S -o case_movlite.ll build-llvm/bin/llc -march=aarch64movlite -mtriple=aarch64movlite-apple-macosx \ case_movlite.ll -o case_movlite.s clang -target arm64-apple-macosx case_movlite.s build/runtime/libmov_runtime_stubs.a -o case_movlite
-
Execution comparison
LLVM_BIN=$PWD/build-llvm/bin python3 tests/run_basic_c_tests.py -o artifacts/basic_c MOVFUSCATOR=$PWD/movfuscator TARGET=arm64-apple-macosx LLVM_BIN=$PWD/build-llvm/bin \ python3 tests/run_movfuscator_tests.py
The runner builds both the reference and MovLite paths, runs them with the same stdin/argv, and strictly compares stdout plus process exit code.
ARM64 validates
hello,prime,arithmetic,crc32, andhanoiby default.crc32is currently recorded as an expected failure because v1 does not support ordered pointer comparisons. -
Design and implementation notes Read docs/DESIGN.md for the design and phase plan. Read docs/AARCH64_MOVLITE_V1_IMPLEMENTATION.md for the v1 implementation summary. Source code lives under
src/.
- mov is Turing-complete - Stephen Dolan
- M/o/Vfuscator - Chris Domas (@xoreaxeaxeax)