A Java bytecode obfuscator that transforms JAR files to make decompilation harder. Class names (including homoglyphs and invisible chars), numeric constants, booleans, strings, and array dimensions are obfuscated while preserving runtime behavior.
- Java 17 or later
- Gradle (wrapper included)
# Build the obfuscator (JAR + scripts)
./gradlew dist # → build/dist/
# Open the GUI (works on Linux, macOS, Windows)
java -jar build/dist/st3ix-obfuscator.jar
# Obfuscate a JAR via CLI (output goes to build/dist/Obfuscate/)
java -jar build/dist/st3ix-obfuscator.jar -i myapp.jar -o myapp-obfuscated.jar
# Run the result
java -jar build/dist/Obfuscate/myapp-obfuscated.jarWindows: Use gradlew.bat for building. You can also run run.bat from build/dist/ or double-click the JAR for the GUI. Linux/macOS: The java -jar command is the recommended way to start the GUI, since run.bat is Windows-only.
Bei jedem Release gibt es ein ZIP-Archiv mit allem Nötigen: JAR, Batch-Datei zum Starten, Config-Beispiel, Images.
- Class renaming – Short or random names; configurable length
- Method renaming – Obfuscate method names; handles override chains
- Field renaming – Obfuscate field names; excludes serialVersionUID and enum constants
- Homoglyph & invisible chars – Unicode lookalikes (a→а) and zero-width chars; copy-paste fails
- Number obfuscation – Hides
intvia math expressions (123→(50*3)-27);long/float/doublevia XOR - Array obfuscation – Hides array dimensions
- Boolean obfuscation – Hides
true/falseliterals - String obfuscation – XOR encryption; inline decrypt at each use; key per class and per string; static final String fields initialized in <clinit> (no readable API keys/secrets)
- Flow obfuscation – Linear methods flattened into switch-dispatcher; execution order obscured
- Debug info stripping – Removes source names, line numbers, local variable names
- Local variable renaming (planned) – Obfuscate local variable names when debug kept
- Random options – Optional random keys and class/method/field names per build
- Exclude patterns – Skip JDK, Bukkit, Minecraft, and custom packages
- GUI – Graphical interface; start with
java -jar st3ix-obfuscator.jar(orrun.baton Windows) - YAML config –
config.ymlnext to the JAR
See Features.md for the full list of current and planned features.
| Option | Description |
|---|---|
-i, --input <path> |
Input JAR file |
-o, --output <path> |
Output filename (saved to Obfuscate/ next to the obfuscator JAR) |
--max-ram <size> |
Max heap hint (e.g. 512m, 2g) – use the launcher script |
-h, --help |
Show usage |
Output files are written to the Obfuscate/ folder in the directory containing the obfuscator JAR. If a file with the same name exists, it is overwritten.
Copy config.yml.example to config.yml and place it next to st3ix-obfuscator.jar.
classRenamingEnabled: true
methodRenamingEnabled: true
fieldRenamingEnabled: true
numberObfuscationEnabled: true
arrayObfuscationEnabled: true
booleanObfuscationEnabled: true
stringObfuscationEnabled: true
flowObfuscationEnabled: true
debugInfoStrippingEnabled: true
classNamesRandom: false
classNameLength: 6
classNamesHomoglyph: false # Cyrillic lookalikes (a→а)
classNamesInvisibleChars: false # Zero-width chars in names
numberKeyRandom: false
arrayKeyRandom: false
booleanKeyRandom: false
stringKeyRandom: false
flowKeyRandom: false
excludeClasses:
- com.myapp.sensitiveSee config.yml.example for all options.
src/main/java/st3ix/obfuscator/
├── api/ – Public API (if exposed)
├── cli/ – Command-line interface
├── config/ – Configuration loading
├── core/ – Obfuscation pipeline
├── io/ – JAR reading and writing
├── log/ – Logging
└── transform/ – Bytecode transformers
The Example/Java Project folder contains a demo with an obfuscate Gradle task.
cd "Example/Java Project"
./gradlew obfuscate
java -jar ../../build/dist/Obfuscate/example-java-project-obfuscated.jarOr run test-obfuscate.bat from the project root for a full build and test.
Before obfuscation (decompiled):
package example;
public final class Main {
public static void main(String[] args) {
System.out.println("License validation active.");
LicenseValidator validator = new LicenseValidator();
validator.validate();
DataProcessor proc = new DataProcessor();
proc.process(10, 20);
}
}
// example/LicenseValidator.java
public final class LicenseValidator {
private static final String API_KEY = "sk-live-a7f3b9c2e1d4";
private int validationCount;
public void validate() {
validationCount++;
int port = 443; // HTTPS
int maxRetries = 3;
boolean strictMode = true;
System.out.println("port=" + port + ", retries=" + maxRetries);
}
}
// example/DataProcessor.java – linear method + array (flow & array obfuscation)
public final class DataProcessor {
public int process(int a, int b) {
int[] buf = new int[8];
int step1 = a * 2;
int step2 = step1 + b;
int step3 = step2 / 3;
int step4 = step3 - 7;
return step4;
}
}After obfuscation (class, method, field, number, array, boolean, string, flow, debug stripping, homoglyph):
// String constant obfuscation: built from char codes, no readable text
public final class b {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append((char)(50+59)); sb.append((char)(120+1)); sb.append((char)45); // ...
System.out.println(sb.toString()); // "License..." – unreadable in source
ь var0 = new ь();
var0.a();
с var1 = new с();
var1.b(10, 20);
}
}
public final class ь {
private static final String a = /* built from (char)(expr) per character */;
private int b;
public void a() {
this.b++;
int var0 = 431 + 12; // 443 via expression
int var1 = 2 * 2 - 1; // 3 via expression
boolean var2 = 0x... ^ 0x...; // boolean XOR
System.out.println("port=" + var0 + ", retries=" + var1);
}
}
public final class с {
public int b(int a, int b) {
int[] var3 = new int[(8 ^ 0x3B9A7C2E) ^ 0x3B9A7C2E]; // array dimension obfuscated
int var4 = 0x3B9A7C2E; // flow: initial dispatch state
int var5 = 0, var6 = 0, var7 = 0, var8 = 0;
while (true) {
switch (var4) {
case 0x3B9A7C2E:
var5 = a * 2;
var4 = 0x3B9A7C33;
break;
case 0x3B9A7C33:
var6 = var5 + b;
var4 = 0x3B9A7C38;
break;
case 0x3B9A7C38:
var7 = var6 / 3;
var4 = 0x3B9A7C3D;
break;
case 0x3B9A7C3D:
var8 = var7 - 7;
return var8;
}
}
}
}| Transform | Effect |
|---|---|
| Class renaming | Main → b, LicenseValidator → ь, DataProcessor → с (short names; homoglyph) |
| Method renaming | validate() → a(), process() → b() (excludes main, constructors, native) |
| Field renaming | API_KEY → a, validationCount → b |
| Homoglyph | Latin a becomes Cyrillic а (U+0430) – copy-paste fails |
| Invisible chars | Zero-width chars in names – appear normal but differ |
| Number obfuscation | 443 → 431+12, 3 → 2*2-1 (math expressions) |
| Array obfuscation | new int[8] → new int[(8 ^ key) ^ key] |
| Boolean obfuscation | true → (value ^ key) ^ key |
| String obfuscation | Strings built from char codes via math expressions; no readable text |
| Flow obfuscation | Linear methods → switch-dispatcher; execution order obscured |
| Debug stripping | Local vars become var0, var1; line numbers removed |
Obfuscation raises the bar for casual and automated reverse engineering. Numbers are hidden as math expressions at compile time; decompilers show the expression, not the literal. Strings use constant obfuscation: each character is built from math expressions (e.g. (char)(50+59) for 'm'), so API keys, secrets, and literals never appear as readable text. No string in the constant pool; nothing for strings-tools to extract. Issues and PRs are open—if you want AES/XOR encryption as an optional mode, contributions are welcome.
Realistic caveats: determined reversers can still trace decryption logic; obfuscation is a deterrent, not unbreakable protection.
- Support Server – Discord
- Features.md – Current and planned features
- docs/HOMOGLYPH_INFO.md – Homoglyph & invisible char obfuscation
- CONTRIBUTING.md – Contribution guidelines
All Rights Reserved. This project is proprietary software. Unauthorized copying, modification, distribution, or use is not permitted without explicit permission from the author.
