RJNI

Native-code protection for Java. Your method bodies leave the class file.

RJNI is a Java native obfuscator. It translates the method bodies of your compiled Java code into Rust, compiles them into a native library and links them back through JNI, so the original bytecode is no longer in the class file.

What RJNI does

  • No bytecode left to decompile

    Eligible method bodies are translated to Rust, compiled into a native library and relinked through JNI. The class file keeps a native declaration with no bytecode behind it, so a decompiler has nothing to reconstruct.

  • Runs after your other tools

    RJNI takes a finished JAR, so it runs as one extra build step and can sit after a tool such as ProGuard. Output from specific obfuscators has not all been verified yet; the compatibility notes say what has.

  • A full protection pipeline

    Translation is one of twelve passes. RJNI also renames classes and members, encrypts strings and resources, flattens control flow, adds anti-tamper checks and can watermark a build. See the protection passes.

What is JNI?

The Java Native Interface is the standard way for Java code to call functions written in native languages such as C, C++ or Rust. A method marked native has no Java body: the JVM looks up a function in a loaded native library and runs that instead.

RJNI uses that mechanism for protection. It moves the logic of your methods into a compiled library and leaves native declarations behind, bound at load time through RegisterNatives. The application still runs on an ordinary JVM with the same entry point and public behaviour.

Code example

A small class, decompiled before and after protection. This shows nativization plus string encryption on one class, not the effect of every pass.

Original, decompiled
package com.example.licensing;

public final class LicenseGate {

    public boolean isValid(String key,
                            long issuedAtMillis) {
        String prefix = "LIC-";
        long age = System.currentTimeMillis()
            - issuedAtMillis;
        return key.startsWith(prefix)
            && age < 31_536_000_000L;
    }
}
Protected, decompiled
package a;

public final class a {

    public native boolean a(java.lang.String,
                             long);
}

What changed: the class and method were renamed. The body of isValid, including the comparison, the one-year threshold and the "LIC-" literal, was translated to Rust and compiled into the bundled native library. The literal is encrypted before translation, so it is not stored as plaintext in the library either.

Sample JARs

Original and protected sample JARs, so you can open both in the decompiler of your choice, are not published yet. To see output for your own code before buying, use trial mode, or ask for samples at [email protected].

Built around a clear threat model

RJNI removes the bytecode that off-the-shelf decompilers depend on, then layers renaming, string and resource encryption, control-flow flattening and anti-tamper checks on top. The effort needed to recover your logic moves from running a decompiler to reverse-engineering native code, a far higher bar. Every protection is documented with its scope.

Explore the security model, the full list of protection passes, or the current stage of the project.

See what a licence covers.