forked from openrs2/openrs2
The obfuscator (or compiler, potentially?) converts INVOKEVIRTUAL instructions to INVOKESPECIAL in the following circumstances: * The owner of the method is the same as the class containing the INVOKE instruction. * The owner's ACC_FINAL flag is set. When those two conditions are met, and when ACC_SUPER is set on the owner (which is always true in the RuneScape client, and the flag is ignored in modern JVMs), then INVOKESPECIAL and INVOKEVIRTUAL are equivalent. This has not caused problems until now. However, the future static scrambling transformer will break the first condition in some cases, as it moves methods between classes. This transformer reverses the obfuscation, such that INVOKEVIRTUAL is used again. INVOKEVIRTUAL instructions may be moved between classes without complication.bzip2
parent
a82d2e3cef
commit
ccb37f120b
@ -0,0 +1,48 @@ |
|||||||
|
package dev.openrs2.deob.transform |
||||||
|
|
||||||
|
import com.github.michaelbull.logging.InlineLogger |
||||||
|
import dev.openrs2.asm.classpath.ClassPath |
||||||
|
import dev.openrs2.asm.classpath.Library |
||||||
|
import dev.openrs2.asm.transform.Transformer |
||||||
|
import org.objectweb.asm.Opcodes |
||||||
|
import org.objectweb.asm.tree.ClassNode |
||||||
|
import org.objectweb.asm.tree.MethodInsnNode |
||||||
|
import org.objectweb.asm.tree.MethodNode |
||||||
|
|
||||||
|
class InvokeSpecialTransformer : Transformer() { |
||||||
|
private var invokeSpecialsReplaced = 0 |
||||||
|
|
||||||
|
override fun preTransform(classPath: ClassPath) { |
||||||
|
invokeSpecialsReplaced = 0 |
||||||
|
} |
||||||
|
|
||||||
|
override fun transformCode(classPath: ClassPath, library: Library, clazz: ClassNode, method: MethodNode): Boolean { |
||||||
|
for (insn in method.instructions) { |
||||||
|
if (insn !is MethodInsnNode || insn.opcode != Opcodes.INVOKESPECIAL) { |
||||||
|
continue |
||||||
|
} else if (insn.name == "<init>") { |
||||||
|
continue |
||||||
|
} else if (insn.owner != clazz.name) { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
val owner = classPath.getNode(insn.owner)!! |
||||||
|
if ((owner.access and Opcodes.ACC_FINAL) == 0) { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
insn.opcode = Opcodes.INVOKEVIRTUAL |
||||||
|
invokeSpecialsReplaced++ |
||||||
|
} |
||||||
|
|
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
override fun postTransform(classPath: ClassPath) { |
||||||
|
logger.info { "Replaced $invokeSpecialsReplaced INVOKESPECIALs with INVOKEVIRTUAL" } |
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
private val logger = InlineLogger() |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue