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 9f1e1ed7..1b7ff6bc 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 @@ -15,19 +15,23 @@ import com.google.common.collect.ImmutableList; import dev.openrs2.deob.ast.transform.AddSubTransformer; import dev.openrs2.deob.ast.transform.BinaryExprOrderTransformer; import dev.openrs2.deob.ast.transform.ComplementTransformer; +import dev.openrs2.deob.ast.transform.EncloseTransformer; import dev.openrs2.deob.ast.transform.IfElseTransformer; import dev.openrs2.deob.ast.transform.NegativeLiteralTransformer; import dev.openrs2.deob.ast.transform.TernaryTransformer; import dev.openrs2.deob.ast.transform.Transformer; +import dev.openrs2.deob.ast.transform.UnencloseTransformer; public final class AstDeobfuscator { private static final ImmutableList TRANSFORMERS = ImmutableList.of( + new UnencloseTransformer(), new NegativeLiteralTransformer(), new ComplementTransformer(), new IfElseTransformer(), new TernaryTransformer(), new BinaryExprOrderTransformer(), - new AddSubTransformer() + new AddSubTransformer(), + new EncloseTransformer() ); public static void main(String[] args) { diff --git a/deob-ast/src/main/java/dev/openrs2/deob/ast/transform/EncloseTransformer.java b/deob-ast/src/main/java/dev/openrs2/deob/ast/transform/EncloseTransformer.java new file mode 100644 index 00000000..b6cd474d --- /dev/null +++ b/deob-ast/src/main/java/dev/openrs2/deob/ast/transform/EncloseTransformer.java @@ -0,0 +1,183 @@ +package dev.openrs2.deob.ast.transform; + +import java.util.Optional; + +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.expr.EnclosedExpr; +import com.github.javaparser.ast.expr.Expression; + +public final class EncloseTransformer extends Transformer { + private enum Associativity { + LEFT, + RIGHT, + NONE + } + + private enum Op { + ACCESS_PARENS(Associativity.LEFT), + POSTFIX(Associativity.NONE), + UNARY(Associativity.RIGHT), + CAST_NEW(Associativity.RIGHT), + MULTIPLICATIVE(Associativity.LEFT), + ADDITIVE(Associativity.LEFT), + SHIFT(Associativity.LEFT), + RELATIONAL(Associativity.LEFT), + EQUALITY(Associativity.NONE), + BITWISE_AND(Associativity.LEFT), + BITWISE_XOR(Associativity.LEFT), + BITWISE_OR(Associativity.LEFT), + LOGICAL_AND(Associativity.LEFT), + LOGICAL_OR(Associativity.LEFT), + TERNARY(Associativity.RIGHT), + ASSIGNMENT(Associativity.RIGHT); + + public static Optional from(Expression expr) { + if (expr.isArrayAccessExpr() || expr.isFieldAccessExpr() || expr.isMethodCallExpr() || expr.isEnclosedExpr()) { + return Optional.of(ACCESS_PARENS); + } else if (expr.isUnaryExpr()) { + return Optional.of(expr.asUnaryExpr().getOperator().isPostfix() ? POSTFIX : UNARY); + } else if (expr.isCastExpr() || expr.isObjectCreationExpr() || expr.isArrayCreationExpr()) { + return Optional.of(CAST_NEW); + } else if (expr.isBinaryExpr()) { + switch (expr.asBinaryExpr().getOperator()) { + case MULTIPLY: + case DIVIDE: + case REMAINDER: + return Optional.of(MULTIPLICATIVE); + case PLUS: + case MINUS: + return Optional.of(ADDITIVE); + case LEFT_SHIFT: + case SIGNED_RIGHT_SHIFT: + case UNSIGNED_RIGHT_SHIFT: + return Optional.of(SHIFT); + case LESS: + case LESS_EQUALS: + case GREATER: + case GREATER_EQUALS: + return Optional.of(RELATIONAL); + case EQUALS: + case NOT_EQUALS: + return Optional.of(EQUALITY); + case BINARY_AND: + return Optional.of(BITWISE_AND); + case XOR: + return Optional.of(BITWISE_XOR); + case BINARY_OR: + return Optional.of(BITWISE_OR); + case AND: + return Optional.of(LOGICAL_AND); + case OR: + return Optional.of(LOGICAL_OR); + } + } else if (expr.isInstanceOfExpr()) { + return Optional.of(RELATIONAL); + } else if (expr.isConditionalExpr()) { + return Optional.of(TERNARY); + } else if (expr.isAssignExpr()) { + return Optional.of(ASSIGNMENT); + } + return Optional.empty(); + } + + private final Associativity associativity; + + Op(Associativity associativity) { + this.associativity = associativity; + } + + public Associativity getAssociativity() { + return associativity; + } + + public boolean isPrecedenceLess(Op other) { + return ordinal() > other.ordinal(); + } + + public boolean isPrecedenceLessEqual(Op other) { + return ordinal() >= other.ordinal(); + } + } + + private static void encloseLeft(Expression parent, Expression child) { + var parentOp = Op.from(parent).orElseThrow(IllegalArgumentException::new); + Op.from(child).ifPresent(childOp -> { + switch (parentOp.getAssociativity()) { + case LEFT: + if (childOp.isPrecedenceLess(parentOp)) { + parent.replace(child, new EnclosedExpr(child.clone())); + } + break; + case NONE: + case RIGHT: + if (childOp.isPrecedenceLessEqual(parentOp)) { + parent.replace(child, new EnclosedExpr(child.clone())); + } + break; + default: + throw new IllegalArgumentException(); + } + }); + } + + private static void encloseRight(Expression parent, Expression child) { + var parentOp = Op.from(parent).orElseThrow(IllegalArgumentException::new); + Op.from(child).ifPresent(childOp -> { + switch (parentOp.getAssociativity()) { + case NONE: + case LEFT: + if (childOp.isPrecedenceLessEqual(parentOp)) { + parent.replace(child, new EnclosedExpr(child.clone())); + } + break; + case RIGHT: + if (childOp.isPrecedenceLess(parentOp)) { + parent.replace(child, new EnclosedExpr(child.clone())); + } + break; + default: + throw new IllegalArgumentException(); + } + }); + } + + @Override + public void transform(CompilationUnit unit) { + unit.findAll(Expression.class).forEach(expr -> { + if (expr.isArrayAccessExpr()) { + var accessExpr = expr.asArrayAccessExpr(); + encloseLeft(expr, accessExpr.getName()); + } else if (expr.isFieldAccessExpr()) { + encloseLeft(expr, expr.asFieldAccessExpr().getScope()); + } else if (expr.isMethodCallExpr()) { + expr.asMethodCallExpr().getScope().ifPresent(scope -> { + encloseLeft(expr, scope); + }); + } else if (expr.isUnaryExpr()) { + var unaryExpr = expr.asUnaryExpr(); + encloseRight(expr, unaryExpr.getExpression()); + } else if (expr.isCastExpr()) { + encloseRight(expr, expr.asCastExpr().getExpression()); + } else if (expr.isObjectCreationExpr()) { + expr.asObjectCreationExpr().getScope().ifPresent(scope -> { + encloseLeft(expr, scope); + }); + } else if (expr.isBinaryExpr()) { + var binaryExpr = expr.asBinaryExpr(); + encloseLeft(expr, binaryExpr.getLeft()); + encloseRight(expr, binaryExpr.getRight()); + } else if (expr.isInstanceOfExpr()) { + encloseLeft(expr, expr.asInstanceOfExpr().getExpression()); + } else if (expr.isConditionalExpr()) { + var conditionalExpr = expr.asConditionalExpr(); + encloseLeft(expr, conditionalExpr.getCondition()); + encloseLeft(expr, conditionalExpr.getThenExpr()); + encloseRight(expr, conditionalExpr.getElseExpr()); + } else if (expr.isAssignExpr()) { + var assignExpr = expr.asAssignExpr(); + encloseLeft(expr, assignExpr.getTarget()); + encloseRight(expr, assignExpr.getValue()); + } + }); + } +} diff --git a/deob-ast/src/main/java/dev/openrs2/deob/ast/transform/UnencloseTransformer.java b/deob-ast/src/main/java/dev/openrs2/deob/ast/transform/UnencloseTransformer.java new file mode 100644 index 00000000..01fd39a1 --- /dev/null +++ b/deob-ast/src/main/java/dev/openrs2/deob/ast/transform/UnencloseTransformer.java @@ -0,0 +1,13 @@ +package dev.openrs2.deob.ast.transform; + +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.expr.EnclosedExpr; + +public final class UnencloseTransformer extends Transformer { + @Override + public void transform(CompilationUnit unit) { + unit.findAll(EnclosedExpr.class).forEach(expr -> { + expr.replace(expr.getInner().clone()); + }); + } +}