From 2cde631fcaf486caf88ba5af436483abc6fc557d Mon Sep 17 00:00:00 2001 From: Graham Date: Fri, 2 Aug 2019 17:17:47 +0100 Subject: [PATCH] Add BitShiftTransformer --- .../java/dev/openrs2/asm/InsnNodeUtils.java | 61 +++++++++++++++++++ .../java/dev/openrs2/deob/Deobfuscator.java | 2 + .../deob/transform/BitShiftTransformer.java | 48 +++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 deob/src/main/java/dev/openrs2/deob/transform/BitShiftTransformer.java diff --git a/asm/src/main/java/dev/openrs2/asm/InsnNodeUtils.java b/asm/src/main/java/dev/openrs2/asm/InsnNodeUtils.java index a4ec5268..d5f0db55 100644 --- a/asm/src/main/java/dev/openrs2/asm/InsnNodeUtils.java +++ b/asm/src/main/java/dev/openrs2/asm/InsnNodeUtils.java @@ -1,6 +1,10 @@ package dev.openrs2.asm; +import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; public final class InsnNodeUtils { public static AbstractInsnNode nextReal(AbstractInsnNode insn) { @@ -31,6 +35,63 @@ public final class InsnNodeUtils { return insn; } + public static int getIntConstant(AbstractInsnNode insn) { + switch (insn.getOpcode()) { + case Opcodes.ICONST_M1: + return -1; + case Opcodes.ICONST_0: + return 0; + case Opcodes.ICONST_1: + return 1; + case Opcodes.ICONST_2: + return 2; + case Opcodes.ICONST_3: + return 3; + case Opcodes.ICONST_4: + return 4; + case Opcodes.ICONST_5: + return 5; + case Opcodes.BIPUSH: + case Opcodes.SIPUSH: + var intInsn = (IntInsnNode) insn; + return intInsn.operand; + case Opcodes.LDC: + var ldc = (LdcInsnNode) insn; + if (ldc.cst instanceof Integer) { + return (Integer) ldc.cst; + } + } + + throw new IllegalArgumentException(); + } + + public static AbstractInsnNode createIntConstant(int value) { + switch (value) { + case -1: + return new InsnNode(Opcodes.ICONST_M1); + case 0: + return new InsnNode(Opcodes.ICONST_0); + case 1: + return new InsnNode(Opcodes.ICONST_1); + case 2: + return new InsnNode(Opcodes.ICONST_2); + case 3: + return new InsnNode(Opcodes.ICONST_3); + case 4: + return new InsnNode(Opcodes.ICONST_4); + case 5: + return new InsnNode(Opcodes.ICONST_5); + } + + if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { + return new IntInsnNode(Opcodes.BIPUSH, value); + } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { + return new IntInsnNode(Opcodes.SIPUSH, value); + } else { + return new LdcInsnNode(value); + } + } + private InsnNodeUtils() { /* empty */ } diff --git a/deob/src/main/java/dev/openrs2/deob/Deobfuscator.java b/deob/src/main/java/dev/openrs2/deob/Deobfuscator.java index 492fcd08..0329e3ec 100644 --- a/deob/src/main/java/dev/openrs2/deob/Deobfuscator.java +++ b/deob/src/main/java/dev/openrs2/deob/Deobfuscator.java @@ -11,6 +11,7 @@ import dev.openrs2.asm.Library; import dev.openrs2.asm.Transformer; import dev.openrs2.deob.classpath.ClassPath; import dev.openrs2.deob.classpath.TypedRemapper; +import dev.openrs2.deob.transform.BitShiftTransformer; import dev.openrs2.deob.transform.CanvasTransformer; import dev.openrs2.deob.transform.ClassForNameTransformer; import dev.openrs2.deob.transform.CounterTransformer; @@ -27,6 +28,7 @@ public final class Deobfuscator { private static final List TRANSFORMERS = List.of( new OpaquePredicateTransformer(), new ExceptionTracingTransformer(), + new BitShiftTransformer(), new CounterTransformer(), new CanvasTransformer(), new FieldOrderTransformer() diff --git a/deob/src/main/java/dev/openrs2/deob/transform/BitShiftTransformer.java b/deob/src/main/java/dev/openrs2/deob/transform/BitShiftTransformer.java new file mode 100644 index 00000000..60146f0b --- /dev/null +++ b/deob/src/main/java/dev/openrs2/deob/transform/BitShiftTransformer.java @@ -0,0 +1,48 @@ +package dev.openrs2.deob.transform; + +import java.util.Set; + +import dev.openrs2.asm.InsnMatcher; +import dev.openrs2.asm.InsnNodeUtils; +import dev.openrs2.asm.Library; +import dev.openrs2.asm.Transformer; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class BitShiftTransformer extends Transformer { + private static final Logger logger = LoggerFactory.getLogger(BitShiftTransformer.class); + + private static final InsnMatcher CONST_SHIFT_MATCHER = InsnMatcher.compile("(ICONST | BIPUSH | SIPUSH | LDC) (ISHL | ISHR | IUSHR | LSHL | LSHR | LUSHR)"); + private static final Set LONG_SHIFTS = Set.of(Opcodes.LSHL, Opcodes.LSHR, Opcodes.LUSHR); + + private int simplified; + + @Override + public void preTransform(Library library) { + simplified = 0; + } + + @Override + public void transformCode(ClassNode clazz, MethodNode method) { + CONST_SHIFT_MATCHER.match(method).forEach(match -> { + var push = match.get(0); + var bits = InsnNodeUtils.getIntConstant(push); + + var opcode = match.get(1).getOpcode(); + var simplifiedBits = bits & (LONG_SHIFTS.contains(opcode) ? 63 : 31); + + if (bits != simplifiedBits) { + method.instructions.set(push, InsnNodeUtils.createIntConstant(simplifiedBits)); + simplified++; + } + }); + } + + @Override + public void postTransform(Library library) { + logger.info("Simplified {} bit shifts", simplified); + } +}