Branchlock

Introduction

Branchlock offers obfuscation for binary files of Java desktop applications, Android applications, and Java Virtual Machine languages like Kotlin and Groovy. The demo version of Branchlock provides a small overview of the service, but it doesn't offer the full range of features. Obfuscation can be performed on different projects:

Supported Project Types

We provide support for a wide range of projects, including:

  • Java Standalone Applications
  • Java Libraries
  • Java Applets
  • J2ME and Jakarta EE Applications
  • Android SDK Applications (Java & Kotlin only, no cross-platform app tools)
  • Spring Boot Applications
  • Java Virtual Machine Languages (Kotlin, Groovy, Scala, etc.)
  • JavaFX and Swing Applications (GUI)
  • Java Web Applications (Servlets, JSP, JSF, etc.)
  • and more.

Branchlock supports all Java versions from Java 5 to the latest version. For Android, we support all projects with AGP 7 and above. If a new version of Java or Android is released, we will add support for it as soon as possible.

Obfuscating JARs, Desktop Applications, Server Applications, etc.

To obfuscate Java archives (JAR files), open the web app and create a new project. Upload the Java binary you wish to obfuscate. Our service will perform obfuscation on your application and return an obfuscated output JAR file. Branchlock supports most JVM languages like Kotlin and Groovy.

Obfuscating Android Applications

Branchlock uses an Android Gradle plugin integration for obfuscating Android applications. Set up a new Android project and follow the instructions.

Project Configuration

Branchlock offers a wide range of configuration options. The configuration is specified in the project settings.

Tasks

Tasks are different obfuscation techniques with different goals. They can be used in combination with each other to achieve the best results. Each task affects the runtime and security of the obfuscated application.

Let's take a look at the "String Encryption" task. This task encrypts all strings in the application, which makes it harder to read the application's code:

public class MyClass {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
    ...
}

After using String encryption, the output could look like this:

public class MyClass {
    public static void main(String[] args) {
        System.out.println(荡[(char)1 << 2306]);
    }
    ...
}

Some tasks should be used sparingly, while others should be used on the whole application. By hovering over a task, you can see a description of what it does and how it affects the performance of the application. Some tasks have internal settings that can also be specified. Note that Android projects have a different set of tasks than Java archives.

Ranges

With "Obfuscation Ranges", you can specify what should be obfuscated in your application, and what shouldn't be. Excluding a class means that it will remain untouched by a certain task. Including a class means that if it has been excluded before, the exclusion will be removed. Be aware that excluding a class does not mean that it remains unchanged. Renamed reference names or signatures, for example, have to be updated in all classes. For more details, refer to the Ranges documentation.

Obfuscating JVM Languages

Branchlock supports most JVM languages like Kotlin and Groovy. Make sure to include the runtime classes of your language as a library. For Kotlin, this would be the Kotlin Standard Library.

Using Branchlock Annotations

Branchlock offers a set of annotations that can be used to control the obfuscation process. These annotations can be used to exclude classes, methods, and fields from obfuscation more easily.

Here is a small example of how the annotations can be used:

import net.branchlock.annotations.*;

@RetainSignature
public class MyClass {
    @RetainSignature /* ensures that the method name is not changed */
    @EntryPoint /* mark this method as a possible entry point for the Trimmer task */
    public void dynamicMethod() {
        ...
    }
    
    @CallerSensitive /* ensures that the references to this method are not encrypted */
    public void specialMethod() {
        var calledBy = new Throwable().getStackTrace()[0].getMethodName();
        ...
    }
    ...
}
Handling Missing Reference Errors

After obfuscation, a list of missing references is provided. These classes were neither found in the input nor in the libraries, but were needed by Branchlock to obfuscate the application. Not providing these classes can lead to unwanted errors. If the application works as expected, you can ignore these warnings. If you are using dynamic libraries make sure to provide extra Java archives that provide those classes.

Good To Know
  • Spring applications may have to use the "No compression" setting.
  • For total anonymity, licensed users can disable the watermark.
  • If you are obfuscating a Java ME or Jakarta EE application, make sure to add the runtime classes of your application server as a library.

Correctly Obfuscating Applications

Achieving a good obfuscation is not easy and has a lot to do with trial-and-error. You will need some time to find the best configuration for your project.

Determine Ranges

First, consider which parts of your application need good security protection, and which don't. Tasks that are expensive on runtime should only be used on classes that need extra protection. If you are obfuscating a fat-jar (Java application that includes both your runtime classes and all library classes), make sure to exclude all library classes. This is achieved by excluding all classes first, and then including your runtime classes.

Testing After Obfuscation

It is essential to test the obfuscated application after obfuscation. Features may break easily through a bad configuration. To make sure everything has been obfuscated correctly, we recommend using a decompiler to view the obfuscated output.

Debugging Broken Applications After Obfuscation

If the output does not work as expected, then try to approach it in a slow and methodical way. Start by only using one task, and then slowly increase the obfuscation range and the amount of tasks used. Just because the output does not work on the first try, it doesn't mean that the obfuscator does not work correctly. In most cases, the config is faulty. Also read the obfuscator log to find out what could have gone wrong. This also applies to the Gradle plugin for Android.

Target Java Versions

Make sure to provide the correct target Java version to ensure compatibility. The obfuscator will use different techniques based on the target Java version.

Java Reflection Usage

Obfuscation and Reflection don't harmonize with each other. Make sure to be careful with tasks that can be broken by Reflection usage. For example: Renaming a class that uses the getResource() method to retrieve a resource file in the package. It is best to exclude classes that use Reflection from obfuscation. To make things easier for you, Branchlock detects some cases of Reflection automatically:

public class MyClass {
    public void myMethod() {
        // if Foo is renamed, this reference will be broken. Branchlock handles this case automatically by keeping the original class name.
        String otherClassName = Foo.class.getName();

        // Branchlock does not handle this case automatically, as the parameter passed to Class.forName() in getPackage() is not fully known.
        // Bar could get renamed and break the application.
        String otherClassPackage = getPackage("SomeBar".substring(4));
        ...
    }
        
    public String getPackage(String className) {
        return Class.forName(className).getPackageName();
    }
}
Layering Obfuscation

While it's technically possible to use multiple obfuscators, we do not recommend it. Using additional obfuscators could lead to unnecessary performance costs without adding any additional security benefits.

Salting Task For Security

If you are looking for the best security, always use the "Salting" task in combination with other tasks. It will protect your application from static analysis and decryption methods.

To understand how the salting task works, let's take a look at the following real-world example, which was obfuscated using Salting and Reference Encryption:

public static void registerCustomDefaults(Object var0, int var1 /* inserted by salting */) {
    Object[] var3 = Np;
    File var4 = (File)var0;
    if ((List)(1.qz(Laf.class, var3, var1 ^ 54)) == null) {  // encrypted reference
        1.rA(new ArrayList(), Laf.class, var3, var1 ^ 73); // encrypted reference
    }
    (Boolean)1.cA((List)(1.qz(Laf.class, var3, var1 ^ 12)), var4, var3, var1 ^ 121);  // encrypted references
}

If you were to decrypt the encrypted references (which is already difficult), the parameter var1 would be needed, which was inserted by the Salting task. This parameter is passed onwards through multiple functions and modified in the process. To trace the value of var1, you would need to know the original references (or else you wouldn't know where calls come from or lead to), which is not possible without decrypting all encrypted references. Those two tasks converge extremely well, and now force a potential attacker to simulate a custom virtual machine.

Branchlock Gradle Plugin / IDE Integration

The Branchlock Gradle plugin is an integration plugin for Gradle. It can be used for obfuscating desktop applications and Android applications, directly from the Gradle build system. The setup is specified in each project. Branchlock does not offer a plugin for other build systems like Maven.

For Android Projects

To use the Branchlock Gradle plugin for Android, your Android project will have to use at least AGP 7. Our plugin is also compatible with AGP 8. The Android plugin directly hooks onto the build process of the Android Gradle plugin. By building a release container, the plugin will obfuscate the application using our API.

For Desktop Gradle Projects

The Desktop gradle plugin hooks onto every "jar" task. This means you can e.g. also use the "shadow" plugin to create a fat-jar, which is then automatically obfuscated. It will create an obfuscated jar file in the build directory.

Troubleshooting

If you are experiencing problems with the Gradle plugin, make sure to check the log output. The log output can be found in the Gradle console or in the Gradle log file. Clearing the Gradle cache or rebuilding / cleaning the project can also help.

Stacktrace Decryption

To decrypt a stacktrace which has been encrypted using the "Stacktrace Encryption" task, head to the "Stacktrace" page in the web application. Paste the stacktrace into the input field and enter the decryption key.

Reporting Abuse

If you found out malware or similar has used our service for obfuscation, you can report it to us. We will try our best to take action. We do not apply any identification methods to our output files.