Remap ClassNodes directly

This is necessary for a future commit that will track the original
indexes of AbstractInsnNodes throughout the deobfuscator, with the aim
of using this information to track local variables in the decompiled
code.

I suspect this will also improve performance, as we don't need to
re-allocate all of the tree objects.
master
Graham 5 years ago
parent d32de8537d
commit 6464f8dc77
  1. 86
      asm/src/main/java/dev/openrs2/asm/ClassNodeRemapper.kt
  2. 26
      asm/src/main/java/dev/openrs2/asm/classpath/Library.kt

@ -0,0 +1,86 @@
package dev.openrs2.asm
import org.objectweb.asm.commons.Remapper
import org.objectweb.asm.tree.AbstractInsnNode
import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.tree.FieldInsnNode
import org.objectweb.asm.tree.FrameNode
import org.objectweb.asm.tree.InvokeDynamicInsnNode
import org.objectweb.asm.tree.LdcInsnNode
import org.objectweb.asm.tree.MethodInsnNode
import org.objectweb.asm.tree.MultiANewArrayInsnNode
import org.objectweb.asm.tree.TypeInsnNode
fun ClassNode.remap(remapper: Remapper) {
val originalName = name
name = remapper.mapType(originalName)
signature = remapper.mapSignature(signature, false)
superName = remapper.mapType(superName)
if (interfaces != null) {
interfaces = interfaces.map(remapper::mapType)
}
for (field in fields) {
field.name = remapper.mapFieldName(originalName, field.name, field.desc)
field.desc = remapper.mapDesc(field.desc)
field.signature = remapper.mapSignature(field.signature, true)
if (field.value != null) {
field.value = remapper.mapValue(field.value)
}
}
for (method in methods) {
method.name = remapper.mapMethodName(originalName, method.name, method.desc)
method.desc = remapper.mapMethodDesc(method.desc)
method.signature = remapper.mapSignature(method.signature, false)
method.exceptions = method.exceptions.map(remapper::mapType)
if (method.hasCode()) {
ClassForNameUtils.remap(remapper, method)
for (insn in method.instructions) {
insn.remap(remapper)
}
for (tryCatch in method.tryCatchBlocks) {
tryCatch.type = remapper.mapType(tryCatch.type)
}
}
}
}
private fun Remapper.mapFrameType(type: Any): Any {
return if (type is String) {
mapType(type)
} else {
type
}
}
private fun AbstractInsnNode.remap(remapper: Remapper) {
when (this) {
is FrameNode -> {
local = local.map(remapper::mapFrameType)
stack = stack.map(remapper::mapFrameType)
}
is FieldInsnNode -> {
val originalOwner = owner
owner = remapper.mapType(originalOwner)
name = remapper.mapFieldName(originalOwner, name, desc)
desc = remapper.mapDesc(desc)
}
is MethodInsnNode -> {
val originalOwner = owner
owner = remapper.mapType(originalOwner)
name = remapper.mapMethodName(originalOwner, name, desc)
desc = remapper.mapDesc(desc)
}
is InvokeDynamicInsnNode -> throw UnsupportedOperationException()
is TypeInsnNode -> desc = remapper.mapType(desc)
is LdcInsnNode -> cst = remapper.mapValue(cst)
is MultiANewArrayInsnNode -> desc = remapper.mapType(desc)
}
}

@ -1,14 +1,12 @@
package dev.openrs2.asm.classpath
import com.github.michaelbull.logging.InlineLogger
import dev.openrs2.asm.ClassForNameUtils
import dev.openrs2.asm.hasCode
import dev.openrs2.asm.remap
import dev.openrs2.common.crypto.Pkcs12KeyStore
import dev.openrs2.common.io.DeterministicJarOutputStream
import dev.openrs2.common.io.SkipOutputStream
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.commons.ClassRemapper
import org.objectweb.asm.commons.Remapper
import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.util.CheckClassAdapter
@ -17,7 +15,6 @@ import java.io.OutputStream
import java.io.SequenceInputStream
import java.nio.file.Files
import java.nio.file.Path
import java.util.HashSet
import java.util.TreeMap
import java.util.jar.JarEntry
import java.util.jar.JarInputStream
@ -28,7 +25,7 @@ import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream
class Library constructor() : Iterable<ClassNode> {
private val classes = TreeMap<String, ClassNode>()
private var classes = TreeMap<String, ClassNode>()
constructor(library: Library) : this() {
for (clazz in library.classes.values) {
@ -59,26 +56,11 @@ class Library constructor() : Iterable<ClassNode> {
}
fun remap(remapper: Remapper) {
val classNames = HashSet<String>()
for (clazz in classes.values) {
for (method in clazz.methods) {
if (method.hasCode()) {
ClassForNameUtils.remap(remapper, method)
}
}
classNames.add(clazz.name)
clazz.remap(remapper)
}
for (name in classNames) {
val `in` = classes.remove(name)
val out = ClassNode()
`in`!!.accept(ClassRemapper(out, remapper))
classes[out.name] = out
}
classes = classes.mapKeysTo(TreeMap()) { (_, clazz) -> clazz.name }
}
fun writeJar(path: Path, manifest: Manifest? = null) {

Loading…
Cancel
Save