Add annotation processor for creating deobufscator name mapping files

I'm ignoring the deobfuscator mapping files for now, but when the
deobfuscator is finished then I'll add them to the repository and keep
them up to date.

Signed-off-by: Graham <gpe@openrs2.dev>
Graham 5 years ago
parent c365019007
commit d006997d2d
  1. 16
      asm/src/main/java/dev/openrs2/asm/MemberRef.kt
  2. 1
      buildSrc/src/main/java/Versions.kt
  3. 1
      data/.gitignore
  4. 25
      deob-map/build.gradle.kts
  5. 3
      deob-map/src/main/java/dev/openrs2/deob/map/Field.kt
  6. 14
      deob-map/src/main/java/dev/openrs2/deob/map/Method.kt
  7. 10
      deob-map/src/main/java/dev/openrs2/deob/map/NameMap.kt
  8. 28
      deob-processor/build.gradle.kts
  9. 19
      deob-processor/src/main/java/dev/openrs2/deob/processor/LocalVariableScanner.kt
  10. 102
      deob-processor/src/main/java/dev/openrs2/deob/processor/NameMapProcessor.kt
  11. 1
      deob-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor
  12. 2
      settings.gradle.kts

@ -6,13 +6,27 @@ import org.objectweb.asm.tree.FieldNode
import org.objectweb.asm.tree.MethodInsnNode import org.objectweb.asm.tree.MethodInsnNode
import org.objectweb.asm.tree.MethodNode import org.objectweb.asm.tree.MethodNode
data class MemberRef(val owner: String, val name: String, val desc: String) { data class MemberRef(val owner: String, val name: String, val desc: String) : Comparable<MemberRef> {
constructor(clazz: ClassNode, field: FieldNode) : this(clazz.name, field.name, field.desc) constructor(clazz: ClassNode, field: FieldNode) : this(clazz.name, field.name, field.desc)
constructor(clazz: ClassNode, method: MethodNode) : this(clazz.name, method.name, method.desc) constructor(clazz: ClassNode, method: MethodNode) : this(clazz.name, method.name, method.desc)
constructor(fieldInsn: FieldInsnNode) : this(fieldInsn.owner, fieldInsn.name, fieldInsn.desc) constructor(fieldInsn: FieldInsnNode) : this(fieldInsn.owner, fieldInsn.name, fieldInsn.desc)
constructor(methodInsn: MethodInsnNode) : this(methodInsn.owner, methodInsn.name, methodInsn.desc) constructor(methodInsn: MethodInsnNode) : this(methodInsn.owner, methodInsn.name, methodInsn.desc)
constructor(owner: String, desc: MemberDesc) : this(owner, desc.name, desc.desc) constructor(owner: String, desc: MemberDesc) : this(owner, desc.name, desc.desc)
override fun compareTo(other: MemberRef): Int {
var result = owner.compareTo(other.owner)
if (result != 0) {
return result
}
result = name.compareTo(other.name)
if (result != 0) {
return result
}
return desc.compareTo(other.desc)
}
override fun toString(): String { override fun toString(): String {
return "$owner.$name $desc" return "$owner.$name $desc"
} }

@ -9,6 +9,7 @@ object Versions {
const val guava = "28.2-jre" const val guava = "28.2-jre"
const val guice = "4.2.3" const val guice = "4.2.3"
const val inlineLogger = "1.0.2" const val inlineLogger = "1.0.2"
const val jackson = "2.10.3"
const val javaParser = "3.15.18" const val javaParser = "3.15.18"
const val jdom = "2.0.6" const val jdom = "2.0.6"
const val jgrapht = "1.4.0" const val jgrapht = "1.4.0"

1
data/.gitignore vendored

@ -0,0 +1 @@
/deob-map

@ -0,0 +1,25 @@
plugins {
`maven-publish`
kotlin("jvm")
}
dependencies {
api(project(":asm"))
}
publishing {
publications.create<MavenPublication>("maven") {
from(components["java"])
pom {
packaging = "jar"
name.set("OpenRS2 Deobfuscator Map")
description.set(
"""
Data structures for representing a map of obfuscated to
refactored names.
""".trimIndent()
)
}
}
}

@ -0,0 +1,3 @@
package dev.openrs2.deob.map
data class Field(val owner: String, val name: String)

@ -0,0 +1,14 @@
package dev.openrs2.deob.map
import java.util.SortedMap
data class Method(
val owner: String,
val name: String,
/*
* Uses concrete type as there is no interface for a map sorted by
* insertion order.
*/
val arguments: LinkedHashMap<Int, String>,
val locals: SortedMap<Int, String>
)

@ -0,0 +1,10 @@
package dev.openrs2.deob.map
import dev.openrs2.asm.MemberRef
import java.util.SortedMap
data class NameMap(
val classes: SortedMap<String, String>,
val fields: SortedMap<MemberRef, Field>,
val methods: SortedMap<MemberRef, Method>
)

@ -0,0 +1,28 @@
plugins {
`maven-publish`
kotlin("jvm")
}
dependencies {
implementation(project(":deob-annotations"))
implementation(project(":deob-map"))
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${Versions.jackson}")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:${Versions.jackson}")
}
publishing {
publications.create<MavenPublication>("maven") {
from(components["java"])
pom {
packaging = "jar"
name.set("OpenRS2 Deobfuscator Annotation Processor")
description.set(
"""
Processes deobfuscator annotations to create a mapping file of
obfuscated to refactored names.
""".trimIndent()
)
}
}
}

@ -0,0 +1,19 @@
package dev.openrs2.deob.processor
import com.sun.source.tree.VariableTree
import com.sun.source.util.TreePathScanner
import com.sun.source.util.Trees
import dev.openrs2.deob.annotation.Pc
class LocalVariableScanner(private val trees: Trees) : TreePathScanner<Void, MutableMap<Int, String>>() {
override fun visitVariable(node: VariableTree, p: MutableMap<Int, String>): Void? {
val element = trees.getElement(currentPath)
val pc = element.getAnnotation(Pc::class.java)
if (pc != null) {
p[pc.value] = element.simpleName.toString()
}
return super.visitVariable(node, p)
}
}

@ -0,0 +1,102 @@
package dev.openrs2.deob.processor
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
import com.sun.source.util.Trees
import dev.openrs2.asm.MemberRef
import dev.openrs2.asm.toInternalClassName
import dev.openrs2.deob.annotation.OriginalArg
import dev.openrs2.deob.annotation.OriginalClass
import dev.openrs2.deob.annotation.OriginalMember
import dev.openrs2.deob.map.Field
import dev.openrs2.deob.map.Method
import dev.openrs2.deob.map.NameMap
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.util.TreeMap
import javax.annotation.processing.AbstractProcessor
import javax.annotation.processing.ProcessingEnvironment
import javax.annotation.processing.RoundEnvironment
import javax.annotation.processing.SupportedAnnotationTypes
import javax.annotation.processing.SupportedOptions
import javax.annotation.processing.SupportedSourceVersion
import javax.lang.model.SourceVersion
import javax.lang.model.element.ExecutableElement
import javax.lang.model.element.TypeElement
import javax.lang.model.element.VariableElement
@SupportedAnnotationTypes(
"dev.openrs2.deob.annotation.OriginalArg",
"dev.openrs2.deob.annotation.OriginalClass",
"dev.openrs2.deob.annotation.OriginalMember",
"dev.openrs2.deob.annotation.Pc"
)
@SupportedSourceVersion(SourceVersion.RELEASE_11)
@SupportedOptions(
"map"
)
class NameMapProcessor : AbstractProcessor() {
private val classes = TreeMap<String, String>()
private val fields = TreeMap<MemberRef, Field>()
private val methods = TreeMap<MemberRef, Method>()
private lateinit var trees: Trees
private lateinit var localScanner: LocalVariableScanner
override fun init(env: ProcessingEnvironment) {
super.init(env)
trees = Trees.instance(env)
localScanner = LocalVariableScanner(trees)
}
private fun getPath(): Path? {
val map = processingEnv.options["map"] ?: return null
return Paths.get(map)
}
override fun process(annotations: Set<TypeElement>, env: RoundEnvironment): Boolean {
val mapPath = getPath() ?: return true
for (element in env.getElementsAnnotatedWith(OriginalClass::class.java)) {
check(element is TypeElement)
val originalClass = element.getAnnotation(OriginalClass::class.java)!!
classes[originalClass.value] = element.qualifiedName.toString().toInternalClassName()
}
for (element in env.getElementsAnnotatedWith(OriginalMember::class.java)) {
val path = trees.getPath(element)
val owner = trees.getScope(path).enclosingClass.qualifiedName.toString().toInternalClassName()
val name = element.simpleName.toString()
val originalMember = element.getAnnotation(OriginalMember::class.java)!!
val ref = MemberRef(originalMember.owner, originalMember.name, originalMember.descriptor)
when (element) {
is VariableElement -> fields[ref] = Field(owner, name)
is ExecutableElement -> {
val arguments = element.parameters.map { parameter ->
val originalArg = parameter.getAnnotation(OriginalArg::class.java)!!
Pair(originalArg.value, parameter.simpleName.toString())
}.toMap(LinkedHashMap())
val locals = TreeMap<Int, String>()
localScanner.scan(path, locals)
methods[ref] = Method(owner, name, arguments, locals)
}
else -> error("Unexpected element type")
}
}
if (env.processingOver()) {
Files.newBufferedWriter(mapPath).use { writer ->
val mapper = ObjectMapper(YAMLFactory()).registerKotlinModule()
mapper.writeValue(writer, NameMap(classes, fields, methods))
}
}
return true
}
}

@ -15,6 +15,8 @@ include(
"deob", "deob",
"deob-annotations", "deob-annotations",
"deob-ast", "deob-ast",
"deob-map",
"deob-processor",
"game", "game",
"util" "util"
) )

Loading…
Cancel
Save