Skip to content

Repository files navigation

NOTICE

The master repo is moved to https://github.com/obsidian-java/obsidian

This repo will be archived soon.

obsidian

Control flow obfuscation for Java code

It is work in progress

Usage

Visual Studio Code Plug-In

We have created a VSCode plug-in that transforms highlighted Java code into the obfuscated form. For more information, including how to run the plug-in, click here.

IntelliJ IDEA Plug-In

Alternatively obsidian can be used as an IntelliJ IDEA plug-in to similarily obfuscate highlighed Java code in the editor. For more information, including how to install and run the plug-in, click here

In-code

Compiled binaries are available in the binrepo repository.

To utilize these binaries as a developer looking to utilize the Obsidian library for code obfuscation, add the following repository to your dependancy file and add the Obsidian library as a dependancy.

You should now be able to import it like any other library and use it in your code.

importobsidian.lang.java.obsidian.Obsidian

Gradle

repositories {
maven {
url 'https://raw.githubusercontent.com/obsidian-java/binrepo/master/'
}
}
// ...
dependencies {
implementation 'obsidian:obsidian:0.0.2'
}

SBT

ThisBuild/ resolvers +="obsidian binary github repo" at "https://raw.githubusercontent.com/obsidian-java/binrepo/master/"// ...
libraryDependencies +="obsidian.lang.java"%%%"obsidian"%"0.0.2"

Maven

<repositories>
<repository>
<id>obsidian-java</id>
<url>https://raw.github.com/obsidian-java/binrepo/master</url>
</repository>
</repositories>
// ...
<dependencies>
<dependency>
<groupId>obsidian.lang.java</groupId>
<artifactId>obsidian</artifactId>
<version>0.0.2</version>
</dependency>

Development (Setup Guide)

As a developer for obsidian, follow the following instructions to set up your environment.

Obsidian environment setup

Obfuscates the following demo Java code in Main.scala

publicclassTest
{
publicstaticintf() {
intx; ints;
x = 0;
s = 0;
while (x < 10) {
s = x + s;
x = x + 1;
}
returns;
}
}
# Clone binrepo repository to this specific locationcd~&& mkdir obsidian-java && git clone git@github.com:obsidian-java/binrepo.git
# Clone obsidian repository to any locationcd~/code && git clone git@github.com:obsidian-java/obsidian.git &&cd obsidian
# Compile and run
sbt compile
sbt run # Runs main class demo in Main.scala# run tests
sbt test

Publishing Steps

builds and publish binaries to binrepo repository for library download

# publish obsidian library to ~/obsidian-java/binrepo folder
sbt publish
# Check if the library is publishedcd~/obsidian-java/binrepo && git status

TODOS:

  1. MinSSA does not handle the following
    1. synchronized method, variable, class, which should be an easy fix.
    2. try-catch block, this one is hard.

Documentation

Example

Some examples in Java

Original Code

publicclassFibExcept {
publicclassInputExceptionextendsException {
publicInputException() {
};
}
privateintf1, f2, lpos;
publicFibExcept() {
f1 = 0;
f2 = 1;
lpos = 1;
}
publicintget(intx) {
// 1 inti = lpos;
try { // 2if (x < i) { // 3thrownewInputException();
} else { // 4while (i < x) { // 5intt = f1 + f2;
f1 = f2;
f2 = t;
i++;
} } lpos = i;
returnf2;
} catch (InputExceptione) { // 6 System.out.println("the input should be greater than " + i + ".");
return -1;
}
// 7
}
publicstaticvoidmain(String[] args) {
FibExceptfs = newFibExcept();
System.out.println(fs.get(10));
System.out.println(fs.get(9));
}
}

Obfuscated code simplified version without phi resolution

importjava.util.function.*;
publicclassFibExceptObf {
publicclassInputExceptionextendsException {
publicInputException() { };
}
privateintf1;
privateintf2;
privateintlpos;
publicFibExceptObf() {
f1 = 0;
f2 = 1;
lpos = 1;
}
publicstaticclassCtxt {
publicintinput;
publicintfib_result;
publicExceptionex;
publicinti;
}
publicintget(intx) {
finalCtxtctxt = newCtxt();
Function<Function<Exception,Void>, Function<Function<Void, Void>, Void>> fib0 = raise -> k -> {
ctxt.fib_result = -1;
ctxt.i = this.lpos;
returnk.apply(null);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> fib5 = raise -> k -> { intt = this.f1 + this.f2;
this.f1 = this.f2;
this.f2 = t;
ctxt.i = ctxt.i + 1;
returnk.apply(null);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> fib7 = raise -> k -> {
this.lpos = ctxt.i;
ctxt.fib_result = this.f2;
returnk.apply(null);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> fib4 = raise -> {
returnk -> {
Function<Void, Boolean> cond = isnull -> {
return (newBoolean(ctxt.i < ctxt.input));
};
returnloop(cond, fib5, fib7).apply(raise).apply(k);
};
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> fib3 = raise -> k -> {
returnraise.apply(newInputException());
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> fib2 = raise -> k -> {
Function<Void, Boolean> cond = isnull -> newBoolean(x < ctxt.i);
returnifelse(cond, fib3, fib4).apply(raise).apply(k);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> fib6 = raise -> k -> {
System.out.println("the input should be greater than " + ctxt.i + ".");
returnk.apply(null);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> fib1 = raise -> k -> {
returntrycatch(fib2,ex -> { ctxt.ex = ex; returnfib6; } ).apply(raise).apply(k);
};
Function<Integer, Function<Function<Exception,Void>, Function<Function<Integer, Void>, Void>>> get_cps = input -> raise -> k -> {
ctxt.input = input;
returnseq(fib0,fib1).apply(raise).apply((Voidn) -> k.apply(newInteger(ctxt.fib_result)) );
};
get_cps.apply(x).apply(idHandler).apply(r -> { ctxt.fib_result = r; returnnull;});
returnctxt.fib_result;
}
publicstaticFunction<Void, Void> id = (isNull) -> {
returnnull;
};
publicstaticFunction<Exception, Void> idHandler = e -> {
System.out.println(e.toString());
returnnull;
};
publicstaticFunction<Function<Exception, Void>, Function<Function<Void, Void>, Void>> loop(Function<Void, Boolean> cond, Function<Function<Exception, Void>, Function<Function<Void,Void>, Void>> visitor,
Function<Function<Exception, Void>, Function<Function<Void,Void>, Void>> exit) { returnraise -> k -> { if (cond.apply(null)) {
returnvisitor.apply(raise).apply( isNull -> loop(cond, visitor, exit).apply(raise).apply(k)
);
} else {
returnexit.apply(raise).apply(k);
}
};
}
publicstaticFunction<Function<Exception,Void>, Function<Function<Void, Void>, Void>> trycatch (Function<Function<Exception, Void>, Function<Function<Void,Void>, Void>> visitor,
Function<Exception, Function<Function<Exception, Void>, Function<Function<Void,Void>, Void>>> handler) {
returnraise -> k -> visitor.apply(ex -> handler.apply(ex).apply(raise).apply(k)).apply(k);
}
publicstaticFunction<Function<Exception,Void>, Function<Function<Void,Void>, Void>> seq (Function<Function<Exception, Void>, Function<Function<Void,Void>, Void>> first,
Function<Function<Exception, Void>, Function<Function<Void,Void>, Void>> second) {
returnraise -> k -> first.apply(raise).apply(isnull -> second.apply(raise).apply(k));
}
publicstaticFunction<Function<Exception,Void>, Function<Function<Void,Void>, Void>>
ifelse (Function<Void, Boolean> cond, Function<Function<Exception,Void>, Function<Function<Void,Void>, Void>> th, Function<Function<Exception,Void>, Function<Function<Void,Void>, Void>> el) {
returnraise -> k -> {
if (cond.apply(null)) {
returnth.apply(raise).apply(k);
} else {
returnel.apply(raise).apply(k);
}
};
}
publicstaticvoidmain(String[] args) {
FibExceptObffs = newFibExceptObf();
System.out.println(fs.get(10));
System.out.println(fs.get(9));
}
}

Obfuscated code full version with phi resolution

importjava.util.function.*;
publicclassFibExceptObfFull {
publicclassInputExceptionextendsException {
publicInputException() { };
}
privateintf1;
privateintf2;
privateintlpos;
publicFibExceptObfFull() {
f1 = 0;
f2 = 1;
lpos = 1;
}
publicstaticclassCtxt {
publicintinput;
publicintget_result;
publicExceptionex;
publicinti_1, i_2, i_5, i_6, t_6, r_1, r_2, r_7;
}
publicintget(intx) {
finalCtxtctxt = newCtxt();
Function<Function<Exception,Void>, Function<Function<Void, Void>, Void>> get1 = raise -> k -> {
ctxt.r_1 = -1;
ctxt.i_1 = this.lpos;
returnk.apply(null);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> get6 = raise -> k -> { ctxt.t_6 = this.f1 + this.f2;
this.f1 = this.f2;
this.f2 = ctxt.t_6;
ctxt.i_6 = ctxt.i_5 + 1;
returnk.apply(null);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> get7 = raise -> k -> {
this.lpos = ctxt.i_5;
ctxt.r_7 = this.f2;
returnk.apply(null);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> getk7 = raise -> k -> {
ctxt.i_2 = ctxt.i_5;
returnk.apply(null);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> getk6 = raise -> k -> {
ctxt.i_5 = ctxt.i_6;
returnk.apply(null);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> get5 = raise -> k -> {
Function<Void, Boolean> cond = isnull -> {
return (newBoolean(ctxt.i_5 < ctxt.input));
};
returnloop(cond, seq(get6,getk6), seq(get7,getk7)).apply(raise).apply(k);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> get4 = raise -> k -> {
ctxt.i_2 = ctxt.i_1;
returnraise.apply(newInputException());
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> getk3b = raise -> k -> {
ctxt.i_5 = ctxt.i_1;
returnk.apply(null);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> get3 = raise -> k -> {
Function<Void, Boolean> cond = isnull -> newBoolean(ctxt.input < ctxt.i_1);
returnifelse(cond, get4, seq(getk3b, get5)).apply(raise).apply(k);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> getk3a = raise -> k -> {
ctxt.r_2 = ctxt.r_7; returnk.apply(null);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> get8 = raise -> k -> {
System.out.println("the input should be greater than " + ctxt.i_2 + ".");
returnk.apply(null);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> getk8 = raise -> k -> {
ctxt.r_2 = ctxt.r_1; returnk.apply(null);
};
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> get9 = raise -> k -> {
ctxt.get_result = ctxt.r_2; returnk.apply(null); };
Function<Function<Exception, Void>, Function<Function<Void, Void>, Void>> get2 = raise -> k -> {
returnseq(trycatch(seq(get3,getk3a),ex -> { ctxt.ex = ex; returnseq(get8,getk8); }),get9).apply(raise).apply(k);
};
Function<Integer, Function<Function<Exception,Void>, Function<Function<Integer, Void>, Void>>> get_cps = y -> raise -> k -> {
ctxt.input = y;
returnseq(get1,get2).apply(raise).apply((Voidn) -> k.apply(newInteger(ctxt.get_result)) );
};
get_cps.apply(x).apply(idHandler).apply(r -> { ctxt.get_result = r; returnnull;});
returnctxt.get_result;
}
publicstaticFunction<Void, Void> id = (isNull) -> {
returnnull;
};
publicstaticFunction<Exception, Void> idHandler = e -> {
System.out.println(e.toString());
returnnull;
};
publicstaticFunction<Function<Exception, Void>, Function<Function<Void, Void>, Void>> loop(Function<Void, Boolean> cond, Function<Function<Exception, Void>, Function<Function<Void,Void>, Void>> visitor,
Function<Function<Exception, Void>, Function<Function<Void,Void>, Void>> exit) { returnraise -> k -> { if (cond.apply(null)) {
returnvisitor.apply(raise).apply( isNull -> loop(cond, visitor, exit).apply(raise).apply(k)
);
} else {
returnexit.apply(raise).apply(k);
}
};
}
publicstaticFunction<Function<Exception,Void>, Function<Function<Void, Void>, Void>> trycatch (Function<Function<Exception, Void>, Function<Function<Void,Void>, Void>> visitor,
Function<Exception, Function<Function<Exception, Void>, Function<Function<Void,Void>, Void>>> handler) {
returnraise -> k -> visitor.apply(ex -> handler.apply(ex).apply(raise).apply(k)).apply(k);
}
publicstaticFunction<Function<Exception,Void>, Function<Function<Void,Void>, Void>> seq (Function<Function<Exception, Void>, Function<Function<Void,Void>, Void>> first,
Function<Function<Exception, Void>, Function<Function<Void,Void>, Void>> second) {
returnraise -> k -> first.apply(raise).apply(isnull -> second.apply(raise).apply(k));
}
publicstaticFunction<Function<Exception,Void>, Function<Function<Void,Void>, Void>>
ifelse (Function<Void, Boolean> cond, Function<Function<Exception,Void>, Function<Function<Void,Void>, Void>> th, Function<Function<Exception,Void>, Function<Function<Void,Void>, Void>> el) {
returnraise -> k -> {
if (cond.apply(null)) {
returnth.apply(raise).apply(k);
} else {
returnel.apply(raise).apply(k);
}
};
}
publicstaticvoidmain(String[] args) {
FibExceptObfFullfs = newFibExceptObfFull();
System.out.println(fs.get(10));
System.out.println(fs.get(9));
}
}

About

Control flow obfuscation for Java code

Resources

Stars

39 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages