Browse documentation
Documentation / Protection passes / Native library bundling

Native library bundling

ImplementedThe compiled native library is obfuscated and stored at a randomised per-build path instead of a fixed, guessable one.

What it does

The compiled native library's bytes are obfuscated with a random per-build 16-byte XOR key and written into the JAR at a random path with a .dat extension, instead of a predictable location like native.so. A small manifest recording the chosen path and key is bundled at one fixed location shared by every protected jar, since the loader needs a known starting point to find its own configuration. At runtime, the loader reads the manifest, follows it to the blob, and reverses the obfuscation to recover the library bytes before extracting and loading it.

Why this shape

Built after inspecting two sample jars produced by JNIC, a comparable native-compilation obfuscator. Everything JNIC bundles lives under one fixed namespace, and the native library itself is stored at a random-UUID .dat path. A raw byte inspection showed no recognisable native-binary header. RJNI's scheme matches that shape under its own namespace.

Threat model

Defeats a casual scan of the jar's entries for a native library, and a naive file-signature check for a bundled .so/.dll/.dylib. It does not resist an attacker who reads this loader's logic and reimplements the reversal. Other native-compilation obfuscators with a similar approach share this limitation.

Verified. A raw byte dump of the bundled obfuscated blob in a protected jar showed no ELF magic header. A round-trip test packages the bundled entries into a jar, loads them through an isolated class loader, and confirms the loader recovers the exact original native-library bytes.