Architecture¶
kagura/
├── include/kagura/ Public headers (Passes.h, Options.h, Utils.h, game_protect.h)
├── lib/Transforms/
│ ├── CFG/ Control-flow obfuscation passes
│ ├── Data/ String / constant / global / wide-string / memory-value encryption
│ ├── AntiAnalysis/ Anti-debug, integrity, call indirection, honey values
│ ├── Platform/ iOS (ObjC), Android (JNI), VM virtualization
│ ├── Infrastructure/ DWARF control, config DSL, symbol map
│ ├── Options.cpp Centralized CLI flag definitions
│ ├── Plugin.cpp Pass registration & pipeline wiring
│ └── Utils.cpp Shared IR helpers & PRNG
├── runtime/
│ ├── core/ AES, VM interpreter, crash symbolication, device key
│ ├── anti_debug/ Anti-debug / anti-Frida (cross-platform POSIX)
│ ├── android/ Android + Linux: root detection, attestation, /proc, syscall
│ ├── ios/ iOS / macOS: jailbreak detection, Mach-O integrity
│ ├── windows/ Windows: IsDebuggerPresent, NtQueryInformationProcess, PE integrity
│ └── game/ Anti-cheat, IL2CPP protection, telemetry
├── integration/ Xcode, Gradle, Unity, Unreal, CMake, Bazel, CocoaPods, SPM
├── scripts/ CLI tools, verification, differential testing, review risk assessment
└── tests/ CTest + FileCheck lit-based regression tests
Plugin entry point¶
lib/Transforms/Plugin.cpp registers all passes with the LLVM New Pass
Manager via PassPluginLibraryInfo. It does two things:
- Exposes every pass by name so it can be requested from
opt(-passes="kagura-str,...") or from clang via-mllvm -kagura-<name>. - Auto-wires the recommended order onto the
OptimizerLastextension point so users only need-fpass-plugin=KaguraObfuscator.dylibto get a sensible default pipeline.
Configuration & options¶
Options.cpp is the single source of truth for every CLI flag — adding a new
tunable means adding a cl::opt<...> there, then reading it from the pass.
The kagura-config loader runs first in the pipeline and
populates these option values from the JSON policy file.