Skip to content

JVM bytecode obfuscator utilizing invokedynamic instructions

Notifications You must be signed in to change notification settings

andreblanke/indy-obfuscator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

InDy Obfuscator

InDy Obfuscator, short for InvokeDynamic Obfuscator, is an open-source obfuscator for JVM bytecode utilizing a novel obfuscation technique which attempts to hide a program's call graph.

It does so by replacing invoke(virtual|special|static|interface) instructions with invokedynamic ones, delegating to a bootstrap method at first invocation time. The bootstrap method is then responsible for determining the actual call site.

By implementing the bootstrap method in native code rather than in Java itself, the level of obfuscation is increased without sacrificing much performance. It also gives access to a broad variety of additional obfuscation methods for native code.

Getting started

With Docker

A containerized version of the obfuscator can be built and run by executing the below command in this repository's root directory.

docker build -t indy-obfuscator . && docker run -it indy-obfuscator

The runnable, packaged artifact will be located at ./obfuscator.jar. A CMakeLists.txt file to compile a bootstrap.c file generated by the obfuscator to a native library libbootstrap.so is included within the container.

After obfuscating a JAR, e.g., the obfuscator itself via

java -jar obfuscator.jar -- obfuscator.jar -o obfuscator-obf.jar -I 'dev.blanke.indyobfuscator.*' > bootstrap.c

The generated bootstrap.c file may be compiled as follows.

mkdir cmake && cd cmake
cmake .. && make

mv libbootstrap.so .. && cd ..

Afterward, the obfuscated application, in our case obfuscator-obf.jar, may be run with libbootstrap.so in the current working directory using

java -jar obfuscator-obf.jar

Without Docker

Obtaining the obfuscator

This project uses Apache Maven as its build system. To compile the obfuscator from source, first clone the repository and navigate to its root directory.

An executable JAR file can be created by executing

mvn package

The runnable, packaged artifact will be located at./target/obfuscator-1.0-SNAPSHOT.jar.

Prerequisites

Due to the premise of the obfuscation technique, some non-Java related tools are required in addition to the obfuscator itself. These tools are used to build a shared library that can be accessed using JNI. The following programs will be needed:

  • A C compiler (e.g. GCC, Clang, or MSVC), for the compilation of the bootstrap method source code generated from the bootstrap method template processing

  • (optional, recommended) CMake, to compile the bootstrap method source code without manually locating jni.h

Obfuscation process

Once all prerequisites have been met you can get started with the actual obfuscation process. Two input files are used by the obfuscator:

  1. a JAR file to be obfuscated

  2. (optional) a bootstrap method template

    If no custom bootstrap method template is provided, the default one located at obfuscator/src/main/resources/bootstrap.c.ftl is used.

See the diagram below for a high-level overview of the obfuscation process.

Overview of the obfuscation process

Explanation of the obfuscation process

The blue path represents the input file which gets obfuscated, whereas the orange path represents the processing of the bootstrap method template. The provided template file is populated using information gained in the obfuscation phase (most notably the symbol table and information about the bootstrap method) to produce valid source code making up the native implementation of the bootstrap method.

The generated source code will be compiled into a native library which is loaded by the obfuscated program at runtime. As the compilation of the generated source code is out of scope for the obfuscator, this step will need to be executed manually or scripted.

In the end, two artifacts will together make up the obfuscated program: an obfuscated JAR or class file and a native library.

A simple example usage of the obfuscator is shown in the below command. input.jar is obfuscated while the example bootstrap method template is populated.

output.jar will contain the obfuscated bytecode. The bootstrap method source code produced by the population of the template will be written to System.out, so it is redirected to a file, in this case to native/bootstrap.c.

java -jar obfuscator-1.0-SNAPSHOT.jar input.jar \
  -o output.jar \
  --bsm-template native/bootstrap.c.ftl > native/bootstrap.c
Further command-line arguments
  • --bsm-owner can be used to manually specify the class which should contain the bootstrap method stub in case the owner cannot be determined automatically.

    By default, the main class of a jar file is used. This option has no effect when the input is a class file.

  • --bsm-name can be used to manually specify the name of the bootstrap method in case a method with the same name and signature already exists within the class that should contain the bootstrap method.

  • -I or --include can be used to specify one or more regular expressions matching fully qualified class names of classes to be included in the obfuscation.

    Non-confidential dependencies that require no obfuscation can and should be excluded from the obfuscation process by limiting the obfuscation to application-specific classes.

  • --help can be used to show usage information and to list available command-line parameters.

The generated C source code making up the bootstrap method implementation must now be compiled to a shared library. A CMake setup is included in the obfuscator/native folder of the repository for convenience, but the compilation can also be performed manually. An example usage of CMake to compile the bootstrap.c file output above is shown below.

cd native/cmake
cmake ..
make

Running the above commands should produce a shared library. The concrete name is platform-dependent: on UNIX systems for example, the library will be named libbootstrap.so while it will be called bootstrap.dll on Windows.

Move the compiled library into the same folder as output.jar. The obfuscated program can now be launched using

java -jar output.jar

assuming that input.jar was an executable jar. Immediately after launch, the shared library will be loaded from the current working directory.

See obfuscator/obfuscate-self.sh for a script which builds the obfuscator, runs the obfuscator on its own jar file, builds the shared library, and invokes the obfuscated obfuscator to show the usage information.

Project structure

The below project layout gives an overview over the most important files and folders within this repository.

├─ java-agent/               Dynamic analysis Java agent
│   └─ src/main/
│       └─ java/dev/blanke/indyobfuscator/
│           ├─ Arguments                 CLI arguments using Picocli
│           ├─ BootstrapDecorator        Implements decorated BSM
│           ├─ ClassFileTransformer      Changes indy instr. using ASM
│           └─ DynamicAnalysisAgent      premain entrypoint
├─ obfuscator/               Main obfuscator source code
│   ├─ native/
│   │   ├─ cmake/            CMake build for processed BSM template
│   │   └─ debug.h           Utility functions for debugging JNI code
│   └─ src/main/
│       ├─ java/dev/blanke/indyobfuscator/
│       │   ├─ mapping/                  Symbol mapping implementation
│       │   ├─ template/                 BSM template processing
│       │   ├─ obfuscation/              Bytecode obfuscation using ASM
│       │   │   ├─ bootstrap/            3rd obfuscation step
│       │   │   ├─ field/                1st obfuscation step
│       │   │   └─ obfuscation/          2nd obfuscation step
│       │   ├─ Arguments.java            CLI arguments using Picocli
│       │   ├─ InDyObfuscator.java       Main class
│       │   └─ InputType.java            Input JAR/class file handling
│       └─ resources/bootstrap.c.ftl     Default BSM template
└─ obfuscator-api/           Optional public API for applications
    └─ src/main/
        └─ java/dev/blanke/indyobfuscator/
            └─ Obfuscate.java            Annotation to limit obfuscation

Related projects

  • superblaubeere27/obfuscator, an open-source Java bytecode obfuscator supporting a variety of obfuscation techniques, including regular invokedynamic obfuscation.
  • Zelix KlassMaster, a commercial obfuscator for Java bytecode.

Links

About

JVM bytecode obfuscator utilizing invokedynamic instructions

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published