From 556923559c84f87990822d19090cc27ac7724f52 Mon Sep 17 00:00:00 2001 From: Graham Date: Sun, 11 Aug 2019 18:57:15 +0100 Subject: [PATCH] Add initial transformer for reducing nesting in long if/else chains --- .../dev/openrs2/deob/ast/AstDeobfuscator.java | 4 +- .../deob/ast/transform/IfElseTransformer.java | 58 +++++++++++++++ .../deob/ast/visitor/NegateExprVisitor.java | 72 +++++++++++++++++++ 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 deob-ast/src/main/java/dev/openrs2/deob/ast/transform/IfElseTransformer.java create mode 100644 deob-ast/src/main/java/dev/openrs2/deob/ast/visitor/NegateExprVisitor.java diff --git a/deob-ast/src/main/java/dev/openrs2/deob/ast/AstDeobfuscator.java b/deob-ast/src/main/java/dev/openrs2/deob/ast/AstDeobfuscator.java index 70a934fc..36bd452e 100644 --- a/deob-ast/src/main/java/dev/openrs2/deob/ast/AstDeobfuscator.java +++ b/deob-ast/src/main/java/dev/openrs2/deob/ast/AstDeobfuscator.java @@ -14,12 +14,14 @@ 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.IfElseTransformer; import dev.openrs2.deob.ast.transform.Transformer; public final class AstDeobfuscator { private static final ImmutableList TRANSFORMERS = ImmutableList.of( new AddSubTransformer(), - new ComplementTransformer() + new ComplementTransformer(), + new IfElseTransformer() ); public static void main(String[] args) { diff --git a/deob-ast/src/main/java/dev/openrs2/deob/ast/transform/IfElseTransformer.java b/deob-ast/src/main/java/dev/openrs2/deob/ast/transform/IfElseTransformer.java new file mode 100644 index 00000000..6e54ba1a --- /dev/null +++ b/deob-ast/src/main/java/dev/openrs2/deob/ast/transform/IfElseTransformer.java @@ -0,0 +1,58 @@ +package dev.openrs2.deob.ast.transform; + +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.stmt.IfStmt; +import com.github.javaparser.ast.stmt.Statement; +import dev.openrs2.deob.ast.visitor.NegateExprVisitor; + +public final class IfElseTransformer extends Transformer { + private static boolean isIf(Statement stmt) { + if (stmt.isIfStmt()) { + return true; + } else if (stmt.isBlockStmt()) { + NodeList stmts = stmt.asBlockStmt().getStatements(); + return stmts.size() == 1 && stmts.get(0).isIfStmt(); + } else { + return false; + } + } + + private static Statement getIf(Statement stmt) { + if (stmt.isIfStmt()) { + return stmt; + } else if (stmt.isBlockStmt()) { + NodeList stmts = stmt.asBlockStmt().getStatements(); + if (stmts.size() == 1) { + Statement head = stmts.get(0); + if (head.isIfStmt()) { + return head; + } + } + } + + throw new IllegalArgumentException(); + } + + @Override + public void transform(CompilationUnit unit) { + unit.findAll(IfStmt.class).forEach(stmt -> { + stmt.getElseStmt().ifPresent(elseStmt -> { + var thenStmt = stmt.getThenStmt(); + if (isIf(thenStmt) && !isIf(elseStmt)) { + stmt.setCondition(stmt.getCondition().accept(new NegateExprVisitor(), null)); + stmt.setThenStmt(elseStmt); + stmt.setElseStmt(thenStmt); + } + }); + }); + + unit.findAll(IfStmt.class).forEach(stmt -> { + stmt.getElseStmt().ifPresent(elseStmt -> { + if (isIf(elseStmt)) { + stmt.setElseStmt(getIf(elseStmt)); + } + }); + }); + } +} diff --git a/deob-ast/src/main/java/dev/openrs2/deob/ast/visitor/NegateExprVisitor.java b/deob-ast/src/main/java/dev/openrs2/deob/ast/visitor/NegateExprVisitor.java new file mode 100644 index 00000000..5a48ec38 --- /dev/null +++ b/deob-ast/src/main/java/dev/openrs2/deob/ast/visitor/NegateExprVisitor.java @@ -0,0 +1,72 @@ +package dev.openrs2.deob.ast.visitor; + +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.expr.BinaryExpr; +import com.github.javaparser.ast.expr.BooleanLiteralExpr; +import com.github.javaparser.ast.expr.EnclosedExpr; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.UnaryExpr; +import com.github.javaparser.ast.visitor.GenericVisitorWithDefaults; + +// TODO(gpe): need to be careful about operator precedence/EnclosedExpr +public final class NegateExprVisitor extends GenericVisitorWithDefaults { + @Override + public Expression defaultAction(Node n, Void arg) { + if (!(n instanceof Expression)) { + throw new IllegalArgumentException(); + } + return new UnaryExpr((Expression) n, UnaryExpr.Operator.LOGICAL_COMPLEMENT); + } + + @Override + public Expression defaultAction(NodeList n, Void arg) { + throw new IllegalArgumentException(); + } + + @Override + public Expression visit(BinaryExpr n, Void arg) { + var left = n.getLeft(); + var right = n.getRight(); + switch (n.getOperator()) { + case EQUALS: + return new BinaryExpr(left, right, BinaryExpr.Operator.NOT_EQUALS); + case NOT_EQUALS: + return new BinaryExpr(left, right, BinaryExpr.Operator.EQUALS); + case GREATER: + return new BinaryExpr(left, right, BinaryExpr.Operator.LESS_EQUALS); + case GREATER_EQUALS: + return new BinaryExpr(left, right, BinaryExpr.Operator.LESS); + case LESS: + return new BinaryExpr(left, right, BinaryExpr.Operator.GREATER_EQUALS); + case LESS_EQUALS: + return new BinaryExpr(left, right, BinaryExpr.Operator.GREATER); + case AND: + return new BinaryExpr(left.accept(this, arg), right.accept(this, arg), BinaryExpr.Operator.OR); + case OR: + return new BinaryExpr(left.accept(this, arg), right.accept(this, arg), BinaryExpr.Operator.AND); + default: + return defaultAction(n, arg); + } + } + + @Override + public Expression visit(BooleanLiteralExpr n, Void arg) { + return new BooleanLiteralExpr(!n.getValue()); + } + + @Override + public Expression visit(EnclosedExpr n, Void arg) { + return n.getInner().accept(this, arg); + } + + @Override + public Expression visit(UnaryExpr n, Void arg) { + switch (n.getOperator()) { + case LOGICAL_COMPLEMENT: + return n.getExpression(); + default: + return defaultAction(n, arg); + } + } +}