O-MVLL, an LLVM obfuscator you configure from Python
:electron: O-MVLL is a code obfuscation tool based on LLVM for native code (Android and iOS).
At a glance
- What is it?
- O-MVLL is a code obfuscation tool for native code on Android and iOS, built on LLVM and driven from Python through the pass manager, so you write a small Python class that decides which functions get which transformation. The configuration layer is the interesting part of the design.
- Who is it for?
- Adopt O-MVLL if you ship native Android or iOS code and want control flow obfuscation applied selectively, because the Python configuration lets you apply a pass to one function and leave the rest of the binary readable, which is what keeps a crash report usable. Do not adopt it for managed code, for server binaries or for a project without a native toolchain, since the tool is an LLVM pass plugin and needs clang, the NDK or an Xcode toolchain.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 17 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A pass plugin, loaded by the compiler
O-MVLL is a LLVM-based obfuscator driven by Python and the LLVM pass manager, and the name is a reference to O-LLVM, the long standing obfuscating compiler that O-MVLL takes inspiration from.
The way it is used is a single compiler flag.
clang++ -fpass-plugin=libOMVLL.dylib main.cpp -o mainThat is the whole integration. The obfuscator is a pass plugin, a shared library that clang loads at compile time, and the passes inside it run as part of the normal optimisation pipeline. There is no separate packaging step, no post-processing tool and no wrapper around the compiler, so the obfuscated binary is the output of the same build you already have, with one extra argument.
That design has a practical consequence for anyone evaluating it. The build system you already use can call clang with the plugin, and the output is a normal object file and a normal executable. The obfuscation happens where the code is compiled, which means the compiler's own view of the program is still the pre-obfuscation program, and the transformation is applied to the IR rather than to the binary after the fact.
The project is Apache-2.0 licensed, released under the same licence as LLVM, and the primary language is C++. The last push was on 2026-10-06, the repository is not archived, and the recent releases are 1.11.0 from 2026-09-29, 1.9.1 from 2026-07-06 and 1.9.0 from 2026-06-23.
The configuration is a Python class, and that is the whole idea
The second example in the project description shows how the passes are chosen, and it is the reason to look at this tool rather than a general purpose obfuscator.
import omvll
class MyConfig(omvll.ObfuscationConfig):
def __init__(self):
super().__init__()
def flatten_cfg(self, mod: omvll.Module, func: omvll.Function):
if func.name == "check_password":
return True
return FalseA configuration class subclasses ObfuscationConfig, and each method corresponds to a pass. The method receives the module and the function, and returns whether that pass should be applied. Here, control flow flattening is applied to one function, check_password, and to nothing else.
That is a much finer grain of control than a compiler switch. The whole point of an obfuscator is to make the code harder to read, and the way most tools do that is to apply everything everywhere, which produces a binary where nothing is debuggable and every stack trace is noise. Here the decision is a Python expression, so a team can protect the licensing check and the protocol handler and leave the rest of the program alone.
The object model makes that possible. A Module holds a Function, and the pass is asked about a specific function, so the configuration is written against the same structure the compiler is working on. The project also publishes a pipeline diagram, which is the piece a new user should look at first, because the order in which passes run is what determines whether the result is correct and how much it costs.
Android NDK, Xcode, and two architectures
O-MVLL can be used with the Android NDK and an iOS toolchain, and it currently supports AArch64 and ARM architectures.
That is a narrow target, and it is the right target for the project. The obfuscation passes work on IR, and the IR differs between architectures, so supporting a set of related architectures rather than everything is a deliberate choice. AArch64 is what modern phones use, and ARM is the older 32-bit case that some embedded devices still run.
The build is verified on both platforms by two separate GitHub Actions workflows, one for the Android NDK and one for the Xcode toolchain, and the repository carries a badge for each. Two workflows rather than one is the right shape, because the two toolchains do not share a build script and a failure in one says nothing about the other.
The homepage is a documentation site at obfuscator.re/omvll, and the project says to check it out for more details, which is where the pass list, the pipeline and the build instructions live.
For an adopter, the practical order is to read the documentation, build the plugin for the architecture you ship, and try it on a small library before a large binary, because the passes change the shape of the code and the tools you use to debug it will notice.
Official releases, experimental builds, and where the passes come from
There are two download channels, and the distinction is worth understanding before you pin a version.
The official releases are the ones on the project's GitHub releases page, and the experimental builds are on a separate continuous integration index hosted by Build38. The distinction is the usual one: a release is a version someone tested and published, and a continuous integration build is whatever the last successful pipeline produced.
The credits section explains where the individual passes come from, and it is a good list for anyone who wants to know what they are getting. The project credits LLVM itself, obfuscator-llvm from the original O-LLVM line, obfuscator-llvm from eShard, Hikari, and DragonFFI.
That list spans both the old compiler-level obfuscators and the newer pass-based work, which tells you the lineage of the transformations rather than the age of the code. The old projects applied their passes by forking the compiler and changing the pass pipeline at build time, which meant shipping a compiler. The pass plugin approach replaces that with a plugin, and the passes themselves are the accumulated work of those earlier projects.
The author is Romain Thomas, known as rh0main, and the maintainer is Build38, described as a next-gen mobile app security platform. The contact address is given as an email on the obfuscator.re domain, and the project says to reach out with any doubt, issue or bug.
One funding detail is stated as well: the project is partly funded by the EU and the European Cybersecurity Competence Center, and the README carries the funding logos.
Licensing that matches LLVM, and a small repository
O-MVLL is released under the same licence as LLVM, the Apache License, Version 2.0, with the LICENSE file in the repository root. That is worth spelling out, because an obfuscation tool that is compiled into your product is a licence question in the same way as any other dependency, and matching LLVM's licence removes the most awkward interaction: a plugin that runs inside the compiler and whose output is your binary.
The repository itself is small. The top level holds a .github directory, a .gitignore, the LICENSE, the README, and four directories that map onto the shape of the project, a dist directory, a doc directory, a scripts directory and a src directory.
That is small for a project that has reached release 1.11.0, and it is a sign that most of the work is in the passes and in the build rather than in a large amount of application code. The dist directory is the built plugin, which is what the clang flag loads, and the doc directory is the documentation that the site is built from.
The release numbering is worth a note. The recent versions are 1.11.0, 1.9.1 and 1.9.0, so the project is on a 1.x line, and a jump from 1.9 to 1.11 rather than 1.10 suggests a versioning scheme that follows the pass set rather than a strict sequence.
The project is Apache-2.0 licensed, its primary language is C++, and it is built and tested on both mobile toolchains with a badge for each, which is a reasonable standard of hygiene for a tool that sits inside a release build.
Editorial conclusion
Adopt O-MVLL if you ship native Android or iOS code and want control flow obfuscation applied selectively, because the Python configuration lets you apply a pass to one function and leave the rest of the binary readable, which is what keeps a crash report usable. Do not adopt it for managed code, for server binaries or for a project without a native toolchain, since the tool is an LLVM pass plugin and needs clang, the NDK or an Xcode toolchain. Before you commit, build the plugin for your architecture, since it currently supports AArch64 and ARM only, and run it on a small binary first to see how much the transformation changes your stack traces and your profiling output.
Frequently asked questions
How do I run O-MVLL on a project?
It is an LLVM pass plugin loaded by the compiler, so you add the plugin to your clang invocation, for example `clang++ -fpass-plugin=libOMVLL.dylib main.cpp -o main`. There is no separate packaging or post-processing step.
How do I choose which obfuscation passes are applied?
By subclassing omvll.ObfuscationConfig in Python and implementing one method per pass, each receiving the module and the function and returning whether to apply it. That lets you obfuscate a single function such as check_password and leave the rest of the binary alone.
Which platforms and architectures does O-MVLL support?
It can be used with the Android NDK and an iOS toolchain, and it currently supports AArch64 and ARM architectures. Separate CI workflows build and test the Android NDK and the Xcode toolchain paths.
Where can I download O-MVLL?
Official releases are on the project's GitHub releases page, and experimental builds are published on a separate continuous integration index. The maintained releases are the ones to pin.
What licence is O-MVLL released under?
Under the Apache License, Version 2.0, the same licence as LLVM. The project is partly funded by the EU and the European Cybersecurity Competence Center, and the recent releases are 1.11.0 from 2026-09-29, 1.9.1 from 2026-07-06 and 1.9.0 from 2026-06-23.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/open-obfuscator-o-mvll)Was this useful?