diff --git a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/BytecodeDeobfuscatorModule.kt b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/BytecodeDeobfuscatorModule.kt index 2dc39ce744..da0e4be89a 100644 --- a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/BytecodeDeobfuscatorModule.kt +++ b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/BytecodeDeobfuscatorModule.kt @@ -22,6 +22,7 @@ import org.openrs2.deob.bytecode.transform.FinalMethodTransformer import org.openrs2.deob.bytecode.transform.InvokeSpecialTransformer import org.openrs2.deob.bytecode.transform.MethodOrderTransformer import org.openrs2.deob.bytecode.transform.MonitorTransformer +import org.openrs2.deob.bytecode.transform.MultipleAssignmentTransformer import org.openrs2.deob.bytecode.transform.OpaquePredicateTransformer import org.openrs2.deob.bytecode.transform.OriginalNameTransformer import org.openrs2.deob.bytecode.transform.OriginalPcRestoreTransformer @@ -53,6 +54,7 @@ public object BytecodeDeobfuscatorModule : AbstractModule() { binder.addBinding().to(OriginalNameTransformer::class.java) binder.addBinding().to(ClassLiteralTransformer::class.java) binder.addBinding().to(InvokeSpecialTransformer::class.java) + binder.addBinding().to(MultipleAssignmentTransformer::class.java) binder.addBinding().to(RemapTransformer::class.java) binder.addBinding().to(PatcherTransformer::class.java) binder.addBinding().to(ResourceTransformer::class.java) diff --git a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/MultipleAssignmentTransformer.kt b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/MultipleAssignmentTransformer.kt new file mode 100644 index 0000000000..4091e76f7e --- /dev/null +++ b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/MultipleAssignmentTransformer.kt @@ -0,0 +1,57 @@ +package org.openrs2.deob.bytecode.transform + +import com.github.michaelbull.logging.InlineLogger +import jakarta.inject.Singleton +import org.objectweb.asm.Opcodes +import org.objectweb.asm.tree.ClassNode +import org.objectweb.asm.tree.FieldInsnNode +import org.objectweb.asm.tree.MethodNode +import org.openrs2.asm.InsnMatcher +import org.openrs2.asm.classpath.ClassPath +import org.openrs2.asm.classpath.Library +import org.openrs2.asm.transform.Transformer +import org.openrs2.deob.bytecode.remap.StaticFieldUnscrambler + +/** + * A [Transformer] that splits multiple assignments to static fields in a + * single expression in `` methods. For example, `a = b = new X()` is + * translated to `b = new X(); a = b`. This allows [StaticFieldUnscrambler] to + * move the fields independently. + */ +@Singleton +public class MultipleAssignmentTransformer : Transformer() { + private var assignments = 0 + + override fun preTransform(classPath: ClassPath) { + assignments = 0 + } + + override fun transformCode(classPath: ClassPath, library: Library, clazz: ClassNode, method: MethodNode): Boolean { + if (method.name != "") { + return false + } + + for (match in MATCHER.match(method)) { + for (i in 0 until match.size - 1 step 2) { + val dup = match[i] + val putstatic = match[i + 1] as FieldInsnNode + + method.instructions.remove(dup) + method.instructions.insert(putstatic, FieldInsnNode(Opcodes.GETSTATIC, putstatic.owner, putstatic.name, putstatic.desc)) + + assignments++ + } + } + + return false + } + + override fun postTransform(classPath: ClassPath) { + logger.info { "Split $assignments multiple assignment expressions into separate expressions" } + } + + private companion object { + private val logger = InlineLogger() + private val MATCHER = InsnMatcher.compile("(DUP PUTSTATIC)+ PUTSTATIC") + } +}