O-MVLL Documentation
repository·main·Indexed 21 days ago
https://github.com/open-obfuscator/o-mvllAn LLVM-based obfuscator that leverages Python and the LLVM pass manager for advanced code obfuscation. It supports AArch64 and ARM architectures via Android NDK and iOS toolchains. O-MVLL provides a Python API for fine-grained control over obfuscation passes, including Control Flow Flattening and arithmetic obfuscation, and can be integrated as a Clang plugin using the -fpass-plugin flag.
What's inside O-MVLL
- O-MVLL is an LLVM-based obfuscator driven by Python and the LLVM pass manager. It is designed to provide obfuscation capabilities by integrating with the LLVM toolchain. It currently supports AArch64 and ARM architectures and can be used with the Android NDK and iOS toolchains.
Drive obfuscation passes via source annotations
mainInstead of managing lists of function names in Python, you can opt functions into or out of specific obfuscation passes directly in C/C++ source code using
__attribute__((annotate("..."))).To make this work, you must use
omvll.ObfuscationConfig.default_configwithin your config class and provide a matching string via theannotationkeyword.Precedence (Strongest to Weakest):
module_excludesfunction_excludes- Negated annotation
!<annotation> function_includes- Annotation
<annotation> probability
Note: A negated annotation (e.g.,
!<flattening>) always wins, even over explicit includes or 100% probability.// Opt into arithmetic obfuscation __attribute__((annotate("arithmetic"))) // Opt into control-flow flattening __attribute__((annotate("flattening"))) int verify_license(const char *token) { ... } // Opt out of flattening, even if included in a list __attribute__((annotate("!flattening"))) int hot_path(void) { ... }# In your ObfuscationConfig implementation: def obfuscate_arithmetic(self, mod, func): if omvll.ObfuscationConfig.default_config(self, mod, func, annotation="arithmetic"): return omvll.ArithmeticOpt(rounds=2) return omvll.ArithmeticOpt(False)Understand LLVM IR objects in O-MVLL callbacks
mainWhen writing custom obfuscation logic via
omvll.ObfuscationConfigcallbacks, you can access LLVM IR objects such asModule,Function,Struct, andGlobalVariable.Important: These objects are read-only. O-MVLL does not allow mutating the Intermediate Representation (IR) directly through these Python bindings. They are provided primarily for inspection and metadata retrieval during the obfuscation process.
Configure Pass Phases for obfuscation
mainThe
pass_phasesattribute inomvll.configallows you to control the execution timing of specific obfuscation passes. It accepts a dictionary where:- Keys are members of the
omvll.Passenumeration (representing specific obfuscation transformations). - Values are sets of members from the
omvll.Phaseenumeration (representing the stages of the compilation/obfuscation pipeline, such asomvll.Phase.Early).
This allows you to pin certain passes to specific lifecycle stages of the O-MVLL process.
omvll.config.pass_phases = { omvll.Pass.Arithmetic: {omvll.Phase.Early}, }- Keys are members of the
How O-MVLL API documentation is generated
mainO-MVLL API documentation is generated using Sphinx with the
autodocextension. The documentation is not manually written in.rstfiles; instead, it is pulled directly from the C++ docstrings embedded in thepybind11bindings.To update or add documentation for a class, method, or attribute, you must edit the corresponding C++ docstring in the source code rather than the
.rstfiles indoc/src/.Key source files for API docstrings:
src/core/python/PyConfig.cpp: Containsomvll.OMVLLConfig,omvll.Phase/omvll.Passenums, andomvll.ObfuscationConfigcallbacks.src/core/python/pyobf_opt.cpp: Contains the*Optoption classes.src/core/python/pyllvm.cpp: ContainsModule,Function,Struct, andGlobalVariable.
Manual documentation in
.rstfiles is reserved for items that are not class members, such as theomvll.configinstance attribute, configurationTemplate(doc/src/config.rst,doc/src/obfuscation.rst), and version attributes (doc/src/versioning.rst).Configure global O-MVLL settings via omvll_get_config()
mainTo apply global settings across the O-MVLL pipeline, modify the attributes of the
omvll.configinstance within theomvll_get_config()function. This function should return your specific configuration object (e.g., an instance ofomvll.ObfuscationConfig). Using@lru_cache(maxsize=1)is recommended to ensure the global configuration is initialized once and reused.Available global configuration attributes in
omvll.OMVLLConfiginclude:shuffle_functions: Boolean to enable/disable function shuffling.inline_jni_wrappers: Boolean to enable/disable inlining of JNI wrappers.global_mod_exclude: List of modules to exclude from global obfuscation.global_func_exclude: List of functions to exclude from global obfuscation.probability_seed: Seed for probabilistic obfuscation passes.output_folder: Destination directory for obfuscated outputs.pass_phases: A mapping that defines which obfuscation passes run during specific execution phases.
@lru_cache(maxsize=1) def omvll_get_config() -> omvll.ObfuscationConfig: omvll.config.shuffle_functions = True omvll.config.inline_jni_wrappers = True omvll.config.pass_phases = { omvll.Pass.Arithmetic: {omvll.Phase.Early}, } return MyConfig()Download O-MVLL
mainO-MVLL binaries can be obtained from the following sources:
- Official releases: Available on the GitHub releases page.
- Experimental builds: Available via the Build38 CI index.
Build the O-MVLL documentation on Linux / Docker
mainIn CI environments (Linux/Docker), you must build O-MVLL with the
-DOMVLL_PY_STANDALONE=1flag to produce an importable Python extension module (omvll.so). This allows Sphinxautodocto introspect the module. Use theOMVLL_STANDALONE_DIRenvironment variable to point Sphinx to the location of the compiled.sofile.cmake -GNinja -S src -B /standalone -DOMVLL_PY_STANDALONE=1 -DCMAKE_BUILD_TYPE=Release ... ninja -C /standalone # → /standalone/omvll.so OMVLL_STANDALONE_DIR=/standalone sphinx-build -b html doc doc/_build/htmlInstall the omvll Python package for code completion
mainTo enable code completion while working with O-MVLL, install the
omvllpackage from PyPI usingpip.Note: The
omvllpackage only provides Python typing objects to facilitate IDE autocompletion and does not contain the actual obfuscation logic.$ python -m pip install [--user] omvllBuild the O-MVLL documentation on local macOS
mainBuilding documentation on macOS requires Python 3.10 (due to
pybind11compatibility constraints) and a prebuilt dependency tree (LLVM 21.1.6, pybind11, spdlog).Follow these steps:
- Setup Sphinx environment: Create a virtual environment using Python 3.10 and install
sphinxandfuro. - Build the standalone module: Use
cmakewith-DOMVLL_PY_STANDALONE=1. You must provide paths to the downloaded dependencies (LLVM, pybind11, spdlog) and the Python 3.10 framework. On macOS, this producesbuild/omvll.so. - Generate HTML: Run
sphinx-buildwhile settingOMVLL_STANDALONE_DIRto your build directory.
# 1. Sphinx environment (Python 3.10) python3.10 -m venv /tmp/omvll-doc-venv /tmp/omvll-doc-venv/bin/pip install sphinx furo # 2. Build the standalone module DEPS=~/Workspace/omvll-v1.9.1-macos-deps LLVM=$DEPS/LLVM-21.1.6-arm64-Darwin PY=/opt/homebrew/opt/python@3.10 cmake -GNinja -S src -B build \ -DOMVLL_PY_STANDALONE=1 \ -DCMAKE_BUILD_TYPE=Release \ -DPython3_EXECUTABLE=$PY/bin/python3.10 \ -DPython3_INCLUDE_DIR=$PY/Frameworks/Python.framework/Versions/3.10/include/python3.10 \ -DPython3_LIBRARY=$PY/Frameworks/Python.framework/Versions/3.10/lib/libpython3.10.dylib \ -Dpybind11_DIR=$DEPS/share/cmake/pybind11 \ -Dspdlog_DIR=$DEPS/lib/cmake/spdlog \ -DLLVM_DIR=$LLVM/lib/cmake/llvm \ -DClang_DIR=$LLVM/lib/cmake/clang ninja -C build OMVLL # → build/omvll.so # 3. Generate the HTML OMVLL_STANDALONE_DIR=$(pwd)/build \ /tmp/omvll-doc-venv/bin/python -m sphinx -b html doc doc/_build/html- Setup Sphinx environment: Create a virtual environment using Python 3.10 and install
Understand StringEncoding::EncodingInfo configuration
mainThe
EncodingInfostruct holds the configuration for a specific string encoding operation. It defines the encoding type, the key used for the transformation, and the associated decoding routines.Key fields:
Type: AnEncodingTyvalue (e.g.,Local,Global,Replace).Key: AKeyTyvariant which can be:std::monostate(no key).KeyBufferTy(std::vector<uint8_t>) for buffer-based keys.KeyIntTy(uint64_t) for integer-based keys.
TM: A pointer to thellvm::Module.EncodeFn: A pointer to the encoding routine function (EncRoutineFn *).
Configure String Encoding types in O-MVLL
mainThe
StringEncodingpass supports four distinct encoding modes via theEncodingTyenum. These modes determine how strings are transformed and how their decoding logic is injected into the module:None: No encoding is applied.Local: String decoding logic is injected locally within the function using the string.Global: String decoding logic is handled via global routines.Replace: Replaces strings with encoded versions (specific behavior governed byStringEncOptReplace).
enum EncodingTy { None = 0, Local, Global, Replace, };