Add initial AST deobfuscator

pull/48/head
Graham 5 years ago
parent fef902c176
commit bf55b0d901
  1. 30
      deob-ast/pom.xml
  2. 80
      deob-ast/src/main/java/dev/openrs2/deob/ast/AstDeobfuscator.java
  3. 36
      deob-ast/src/main/java/dev/openrs2/deob/ast/transform/AddSubTransformer.java
  4. 66
      deob-ast/src/main/java/dev/openrs2/deob/ast/transform/ComplementTransformer.java
  5. 7
      deob-ast/src/main/java/dev/openrs2/deob/ast/transform/Transformer.java
  6. 18
      deob-ast/src/main/java/dev/openrs2/deob/ast/util/ExprUtils.java
  7. 6
      pom.xml

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.openrs2</groupId>
<artifactId>openrs2</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>openrs2-deob-ast</artifactId>
<packaging>jar</packaging>
<name>OpenRS2 AST Deobfuscator</name>
<properties>
<openrs2.root>${project.parent.basedir}</openrs2.root>
</properties>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-symbol-solver-core</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,80 @@
package dev.openrs2.deob.ast;
import java.nio.file.Path;
import java.nio.file.Paths;
import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.printer.PrettyPrinter;
import com.github.javaparser.printer.PrettyPrinterConfiguration;
import com.github.javaparser.symbolsolver.JavaSymbolSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
import com.github.javaparser.utils.SourceRoot;
import com.google.common.collect.ImmutableList;
import dev.openrs2.deob.ast.transform.AddSubTransformer;
import dev.openrs2.deob.ast.transform.ComplementTransformer;
import dev.openrs2.deob.ast.transform.Transformer;
public final class AstDeobfuscator {
private static final ImmutableList<Transformer> TRANSFORMERS = ImmutableList.of(
new AddSubTransformer(),
new ComplementTransformer()
);
public static void main(String[] args) {
var deobfuscator = new AstDeobfuscator(ImmutableList.of(
Paths.get("nonfree/client/src/main/java"),
Paths.get("nonfree/gl/src/main/java"),
Paths.get("nonfree/gl-dri/src/main/java"),
Paths.get("nonfree/loader/src/main/java"),
Paths.get("nonfree/signlink/src/main/java"),
Paths.get("nonfree/unpack/src/main/java"),
Paths.get("nonfree/unpacker/src/main/java")
));
deobfuscator.run();
}
private final ImmutableList<Path> modules;
public AstDeobfuscator(ImmutableList<Path> modules) {
this.modules = modules;
}
public void run() {
var solver = new CombinedTypeSolver(new ReflectionTypeSolver(true));
for (var module : modules) {
solver.add(new JavaParserTypeSolver(module));
}
var config = new ParserConfiguration()
.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_8)
.setSymbolResolver(new JavaSymbolSolver(solver));
var printerConfig = new PrettyPrinterConfiguration()
.setIndentType(PrettyPrinterConfiguration.IndentType.TABS_WITH_SPACE_ALIGN)
.setIndentSize(1);
var printer = new PrettyPrinter(printerConfig);
for (var module : modules) {
var root = new SourceRoot(module, config);
var results = root.tryToParseParallelized();
for (var result : results) {
if (!result.isSuccessful()) {
throw new IllegalArgumentException(result.toString());
}
}
root.getCompilationUnits().forEach(unit -> {
TRANSFORMERS.forEach(transformer -> {
transformer.transform(unit);
});
});
root.setPrinter(printer::print);
root.saveAll();
}
}
}

@ -0,0 +1,36 @@
package dev.openrs2.deob.ast.transform;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.IntegerLiteralExpr;
import com.github.javaparser.ast.expr.UnaryExpr;
import dev.openrs2.deob.ast.util.ExprUtils;
public final class AddSubTransformer extends Transformer {
private static Expression negate(Expression expr) {
if (expr.isIntegerLiteralExpr()) {
return new IntegerLiteralExpr(-expr.asIntegerLiteralExpr().asInt());
} else if (expr.isLongLiteralExpr()) {
return ExprUtils.createLong(-expr.asLongLiteralExpr().asLong());
} else {
throw new IllegalArgumentException();
}
}
@Override
public void transform(CompilationUnit unit) {
unit.findAll(UnaryExpr.class).forEach(expr -> {
var operand = expr.getExpression();
if (!ExprUtils.isIntegerOrLongLiteral(operand)) {
return;
}
var op = expr.getOperator();
if (op == UnaryExpr.Operator.PLUS) {
expr.replace(operand);
} else if (op == UnaryExpr.Operator.MINUS) {
expr.replace(negate(operand));
}
});
}
}

@ -0,0 +1,66 @@
package dev.openrs2.deob.ast.transform;
import java.util.Optional;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.expr.BinaryExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.IntegerLiteralExpr;
import com.github.javaparser.ast.expr.UnaryExpr;
import dev.openrs2.deob.ast.util.ExprUtils;
public final class ComplementTransformer extends Transformer {
private static boolean isComplement(Expression expr) {
return expr.isUnaryExpr() && expr.asUnaryExpr().getOperator() == UnaryExpr.Operator.BITWISE_COMPLEMENT;
}
private static boolean isComplementOrLiteral(Expression expr) {
return isComplement(expr) || ExprUtils.isIntegerOrLongLiteral(expr);
}
private static Optional<BinaryExpr.Operator> complement(BinaryExpr.Operator op) {
switch (op) {
case EQUALS:
case NOT_EQUALS:
return Optional.of(op);
case GREATER:
return Optional.of(BinaryExpr.Operator.LESS);
case GREATER_EQUALS:
return Optional.of(BinaryExpr.Operator.LESS_EQUALS);
case LESS:
return Optional.of(BinaryExpr.Operator.GREATER);
case LESS_EQUALS:
return Optional.of(BinaryExpr.Operator.GREATER_EQUALS);
default:
return Optional.empty();
}
}
private static Expression complement(Expression expr) {
if (expr.isUnaryExpr()) {
return expr.asUnaryExpr().getExpression();
} else if (expr.isIntegerLiteralExpr()) {
return new IntegerLiteralExpr(~expr.asIntegerLiteralExpr().asInt());
} else if (expr.isLongLiteralExpr()) {
return ExprUtils.createLong(~expr.asLongLiteralExpr().asLong());
} else {
throw new IllegalArgumentException();
}
}
@Override
public void transform(CompilationUnit unit) {
unit.findAll(BinaryExpr.class).forEach(expr -> {
complement(expr.getOperator()).ifPresent(op -> {
var left = expr.getLeft();
var right = expr.getRight();
if (isComplementOrLiteral(left) && isComplementOrLiteral(right) && !(ExprUtils.isIntegerOrLongLiteral(left) && ExprUtils.isIntegerOrLongLiteral(right))) {
expr.setOperator(op);
expr.setLeft(complement(left));
expr.setRight(complement(right));
}
});
});
}
}

@ -0,0 +1,7 @@
package dev.openrs2.deob.ast.transform;
import com.github.javaparser.ast.CompilationUnit;
public abstract class Transformer {
public abstract void transform(CompilationUnit unit);
}

@ -0,0 +1,18 @@
package dev.openrs2.deob.ast.util;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.LongLiteralExpr;
public final class ExprUtils {
public static boolean isIntegerOrLongLiteral(Expression expr) {
return expr.isIntegerLiteralExpr() || expr.isLongLiteralExpr();
}
public static LongLiteralExpr createLong(long value) {
return new LongLiteralExpr(Long.toString(value).concat("L"));
}
private ExprUtils() {
/* empty */
}
}

@ -21,6 +21,7 @@
<module>decompiler</module>
<module>deob</module>
<module>deob-annotations</module>
<module>deob-ast</module>
<module>game</module>
<module>util</module>
</modules>
@ -52,6 +53,11 @@
<artifactId>guava</artifactId>
<version>28.0-jre</version>
</dependency>
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-symbol-solver-core</artifactId>
<version>3.14.9</version>
</dependency>
<dependency>
<groupId>dev.openrs2</groupId>
<artifactId>fernflower</artifactId>

Loading…
Cancel
Save