Java .class to .cpp converter for use with JNI
Currently, fully supports only Java 8. Java 9+ and Android support is entirely experimental
Warning: blacklist/whitelist usage is recommended because this tool slows down code significantly (like do not obfuscate full Minecraft .jar)
Also, this tool does not particularly obfuscate your code; it just transpiles it to native. Remember to use protectors like VMProtect, Themida, or obfuscator-llvm (in case of clang usage)
-
JDK 8
-
For Windows:
I recommend downloading Oracle JDK 8, though you need to have some login credentials on Oracle.
-
For Linux/MacOS:
Google "your distro install jdk 8", and install the required packages
-
-
CMake
-
For Windows:
Download the latest release from CMake
-
For Linux/MacOS:
Google "your distro install cmake" and install the required package (default -
apt/yum/brew install cmake)
-
-
C++/C compiler toolchain
-
For Windows:
Download the freeware version of MSVS from Microsoft and select Visual C++ compiler in opt-ins
Or install mingw if you have any experience with this.
-
For Linux/MacOS:
Google "your distro install g++"
-
Usage: native-obfuscator [-ahV] [--debug] [-b=<blackListFile>]
[--custom-lib-dir=<customLibraryDirectory>]
[-l=<librariesDirectory>] [-p=<platform>]
[--plain-lib-name=<libraryName>] [-w=<whiteListFile>]
<jarFile> <outputDirectory>
Transpiles .jar file into .cpp files and generates output .jar file
<jarFile> Jar file to transpile
<outputDirectory> Output directory
-a, --annotations Use annotations to ignore/include native obfuscation
-b, --black-list=<blackListFile>
File with a list of blacklist classes/methods for
transpilation
--custom-lib-dir=<customLibraryDirectory>
Custom library directory for LoaderUnpack
--debug Enable generation of debug .jar file (non-executable)
-h, --help Show this help message and exit.
-l, --libraries=<librariesDirectory>
Directory for dependent libraries
-p, --platform=<platform>
Target platform: hotspot - standard standalone
HotSpot JRE, std_java - java standard, android -
for Android builds (w/o DefineClass)
--plain-lib-name=<libraryName>
Plain library name for LoaderPlain
-V, --version Print version information and exit.
-w, --white-list=<whiteListFile>
File with a list of whitelist classes/methods for
transpilation
<jarFile> - input .jar file to obfuscate
<outputDirectory> - output directory where C++/new .jar file where be created
-l <librariesDirectory> - directory where dependant libraries should be, optional, but preferable
-p <platform> - JVM platform to run library on
Three options are available:
hotspot: will use HotSpot JVM internals and should work with most obfuscators (even with stack trace checking as well)std_java: will use only minor JVM internals that must be available on all JVMsandroid: use this method when building library for Android. Will use no JVM internals, as well as no DefineClass for hidden methods (obfuscators that rely on stack for string/name obfuscator will not work due to the fact that some methods will not be hidden)
-a - enable annotation processing
To use annotations for black/whitelisting methods/classes as native you can add the following library to your project:
com.github.radioegor146.native-obfuscator:annotations:master-SNAPSHOT
Also, you need to add JitPack to your repositories.
You can add @Native annotation to include classes/methods to the native obfuscation process and add @NotNative annotation to ignore methods in classes marked as @Native
Whitelist/Blacklist has higher priority than annotations.
-w <whiteList> - path to .txt file for whitelist of methods and classes if required
-b <blackList> - path to a .txt file for a blacklist of methods and classes if required
Both of them should come in such form:
<class>
<class>#<method name>#<method descriptor>
mypackage/myotherpackage/Class1
mypackage/myotherpackage/Class1#doSomething!()V
mypackage/myotherpackage/Class1$SubClass#doOther!(I)V
It uses internal names of classes and method descriptors for filtering (you can read more about it by googling "java internal class names" or "java method descriptors")
Also, you can use a wildcard matcher like these:
mypackage/myotherpackage/*
mypackage/myotherpackagewithnested/**
mypackage/myotherpackage/*/Class1
mypackage/myotherpackagewithnested/**/Class1
mypackage/myotherpackage/Class*
* matches a single entry (divided by /) in the class/package name
** matches all entries in class/package name
--plain-lib-name - if you ship your .jar separately from the result native libraries, or you use it for Android, you can specify the name of the native library that it will try to search while using.
--custom-lib-dir - if you want to set custom directory for storing libraries inside the jar
If you want to ship your .jar with native libraries in it, you should omit that argument, and after building native files, add them in the form of
x64-windows.dll
x64-linux.so
x86-windows.dll
x64-macos.dylib
arm64-linux.so
arm64-windows.dll
to the directory of the .jar file that this tool will print in stdout (by default native0/ or custom if --custom-lib-dir is present)
- Transpile your code using
java -jar native-obfuscator.jar <input jar> <output directory> - Run
cmake .in the resultcppdirectory - Add changes to .cpp code if necessary
- Run
cmake --build . --config Releasein resultcppdirectory to build .so/.dll file - Copy result .dll/.so from
build/libs/to the path specified in the previous paragraph. - Run created .jar
java -jar <output jar>and enjoy!
Steps 2–5 can be replaced with a single --use-zig flag that compiles the
generated cpp/ tree directly with the Zig toolchain (no CMake / no host
compiler required, cross-compilation built in).
java -jar native-obfuscator.jar install-zig [--version <x.y.z>] [--install-dir <path>] [--force]
Downloads the official Zig release (SHA-256 verified), extracts it under
~/.native-obfuscator/zig/ by default, and writes an installed.json marker
so subsequent builds can locate it.
Options:
--version– pin a specific stable version. Defaults to the latest stable inhttps://ziglang.org/download/index.json.--install-dir– custom install root.--force– re-download even if already installed.--index-url– use a mirror of the release index.
java -jar native-obfuscator.jar --use-zig \
[--zig-targets x64-windows,x64-linux,arm64-linux] \
[--jdk-home <path-to-jdk>] \
<input.jar> <output-dir>
--use-zig– after transpilation, invokezig c++for each requested target and pack the resulting shared library back into the produced jar (or into<output-dir>/native-libs/when--plain-lib-nameis used).--zig-targets– comma-separated list. Defaults tohost. Known targets:x64-linux,x64-windows,x64-macos,arm64-linux,arm64-windows,arm64-macos,x86-linux,x86-windows,arm32-linux, plushost.--zig-path– use a specificzigexecutable instead of the installed/PATH one.--jdk-home– JDK whoseinclude/jni.hshould be used (defaults toJAVA_HOME, thenjava.home).jni_md.his supplied as a portable shim per target, so the JDK's host-specific subfolder is not required.--zig-install-dir– tell the build where Zig was installed (only needed if you used a non-default--install-dir).
The compiled libraries are named according to LoaderUnpack's convention
(x64-windows.dll, x64-linux.so, arm64-macos.dylib, …) and dropped into
the output jar under the loader directory printed at the end of step 1.
- Run
gradlew assembleto force gradle not to run tests after the build
You need to have Krakatau installed to your PATH, because test suite is using krak2 for some tests
- Run
gradlew buildto assemble and run full test suite
This tool uses tests from huzpsb/JavaObfuscatorTest
In case of any problems, feel free to open an issue or contact me at re146.dev