Account for inheritance in StaticScramblingTransformer

GETSTATIC, PUTSTATIC and INVOKESTATIC (strangely) use the same field and
method resolution algorithms as their non-static equivalents.

While this doesn't cause problems for 550, as the *STATIC instructions
seem to always refer to the class containing the static definition,
Major reports that OSRS clients sometimes change the owner to a
subclass. This broke the old transformer.

This commit fixes it by applying the old to new owner mapping to an
entire disjoint set at a time.

Signed-off-by: Graham <gpe@openrs2.dev>
master
Graham 5 years ago
parent a9312f3cd2
commit 78db7d3179
  1. 30
      deob/src/main/java/dev/openrs2/deob/transform/StaticScramblingTransformer.kt

@ -6,6 +6,7 @@ import dev.openrs2.asm.MemberRef
import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.ClassPath
import dev.openrs2.asm.classpath.Library import dev.openrs2.asm.classpath.Library
import dev.openrs2.asm.transform.Transformer import dev.openrs2.asm.transform.Transformer
import dev.openrs2.common.collect.DisjointSet
import dev.openrs2.deob.remap.TypedRemapper import dev.openrs2.deob.remap.TypedRemapper
import org.objectweb.asm.Opcodes import org.objectweb.asm.Opcodes
import org.objectweb.asm.tree.ClassNode import org.objectweb.asm.tree.ClassNode
@ -27,9 +28,11 @@ class StaticScramblingTransformer : Transformer() {
?.mapTo(mutableSetOf(), ::MemberRef) ?: emptySet<MemberRef>() ?.mapTo(mutableSetOf(), ::MemberRef) ?: emptySet<MemberRef>()
} }
private lateinit var inheritedFieldSets: DisjointSet<MemberRef>
private lateinit var inheritedMethodSets: DisjointSet<MemberRef>
private val fieldSets = mutableMapOf<MemberRef, FieldSet>() private val fieldSets = mutableMapOf<MemberRef, FieldSet>()
private val fieldClasses = mutableMapOf<MemberRef, String>() private val fieldClasses = mutableMapOf<DisjointSet.Partition<MemberRef>, String>()
private val methodClasses = mutableMapOf<MemberRef, String>() private val methodClasses = mutableMapOf<DisjointSet.Partition<MemberRef>, String>()
private var nextStaticClass: ClassNode? = null private var nextStaticClass: ClassNode? = null
private var nextClinit: MethodNode? = null private var nextClinit: MethodNode? = null
private val staticClasses = mutableListOf<ClassNode>() private val staticClasses = mutableListOf<ClassNode>()
@ -115,12 +118,14 @@ class StaticScramblingTransformer : Transformer() {
} }
for (field in fieldSet.fields) { for (field in fieldSet.fields) {
val ref = MemberRef(fieldSet.owner, field) val partition = inheritedFieldSets[MemberRef(fieldSet.owner, field)]!!
fieldClasses[ref] = staticClass.name fieldClasses[partition] = staticClass.name
} }
} }
override fun preTransform(classPath: ClassPath) { override fun preTransform(classPath: ClassPath) {
inheritedFieldSets = classPath.createInheritedFieldSets()
inheritedMethodSets = classPath.createInheritedMethodSets()
fieldSets.clear() fieldSets.clear()
fieldClasses.clear() fieldClasses.clear()
methodClasses.clear() methodClasses.clear()
@ -166,7 +171,8 @@ class StaticScramblingTransformer : Transformer() {
staticClass.methods.add(method) staticClass.methods.add(method)
staticClass.version = ClassVersionUtils.maxVersion(staticClass.version, clazz.version) staticClass.version = ClassVersionUtils.maxVersion(staticClass.version, clazz.version)
methodClasses[MemberRef(clazz, method)] = staticClass.name val partition = inheritedMethodSets[MemberRef(clazz, method)]!!
methodClasses[partition] = staticClass.name
return@removeIf true return@removeIf true
} }
} }
@ -182,8 +188,18 @@ class StaticScramblingTransformer : Transformer() {
override fun transformCode(classPath: ClassPath, library: Library, clazz: ClassNode, method: MethodNode): Boolean { override fun transformCode(classPath: ClassPath, library: Library, clazz: ClassNode, method: MethodNode): Boolean {
for (insn in method.instructions) { for (insn in method.instructions) {
when (insn) { when (insn) {
is FieldInsnNode -> insn.owner = fieldClasses.getOrDefault(MemberRef(insn), insn.owner) is FieldInsnNode -> {
is MethodInsnNode -> insn.owner = methodClasses.getOrDefault(MemberRef(insn), insn.owner) val partition = inheritedFieldSets[MemberRef(insn)]
if (partition != null) {
insn.owner = fieldClasses.getOrDefault(partition, insn.owner)
}
}
is MethodInsnNode -> {
val partition = inheritedMethodSets[MemberRef(insn)]
if (partition != null) {
insn.owner = methodClasses.getOrDefault(partition, insn.owner)
}
}
} }
} }

Loading…
Cancel
Save