Split TypedRemapper::create up

Signed-off-by: Graham <gpe@openrs2.dev>
Graham 5 years ago
parent 113820a9a2
commit 9b1f0c6886
  1. 64
      deob/src/main/java/dev/openrs2/deob/remap/ClassMappingGenerator.kt
  2. 71
      deob/src/main/java/dev/openrs2/deob/remap/FieldMappingGenerator.kt
  3. 58
      deob/src/main/java/dev/openrs2/deob/remap/MethodMappingGenerator.kt
  4. 19
      deob/src/main/java/dev/openrs2/deob/remap/NameGenerator.kt
  5. 200
      deob/src/main/java/dev/openrs2/deob/remap/TypedRemapper.kt
  6. 12
      deob/src/main/java/dev/openrs2/deob/transform/UnusedArgTransformer.kt

@ -0,0 +1,64 @@
package dev.openrs2.deob.remap
import dev.openrs2.asm.classpath.ClassMetadata
import dev.openrs2.asm.classpath.ClassPath
import dev.openrs2.asm.filter.ClassFilter
import org.objectweb.asm.Opcodes
class ClassMappingGenerator(
private val classPath: ClassPath,
private val excludedClasses: ClassFilter
) {
private val nameGenerator = NameGenerator()
private val mapping = mutableMapOf<String, String>()
fun generate(): Map<String, String> {
for (clazz in classPath.libraryClasses) {
populateMapping(clazz)
}
return mapping
}
private fun populateMapping(clazz: ClassMetadata): String {
val name = clazz.name
if (mapping.containsKey(name) || !isRenamable(clazz)) {
return mapping.getOrDefault(name, name)
}
val mappedName = generateName(clazz)
mapping[name] = mappedName
return mappedName
}
private fun isRenamable(clazz: ClassMetadata): Boolean {
if (excludedClasses.matches(clazz.name) || clazz.dependency) {
return false
}
for (method in clazz.methods) {
if (clazz.getMethodAccess(method)!! and Opcodes.ACC_NATIVE != 0) {
return false
}
}
return true
}
private fun generateName(clazz: ClassMetadata): String {
val name = clazz.name
var mappedName = name.substring(0, name.lastIndexOf('/') + 1)
val superClass = clazz.superClass
if (superClass != null && superClass.name != "java/lang/Object") {
var superName = populateMapping(superClass)
superName = superName.substring(superName.lastIndexOf('/') + 1)
mappedName += nameGenerator.generate(superName + "_Sub")
} else if (clazz.`interface`) {
mappedName += nameGenerator.generate("Interface")
} else {
mappedName += nameGenerator.generate("Class")
}
return mappedName
}
}

@ -0,0 +1,71 @@
package dev.openrs2.deob.remap
import dev.openrs2.asm.MemberRef
import dev.openrs2.asm.classpath.ClassPath
import dev.openrs2.asm.filter.MemberFilter
import dev.openrs2.util.collect.DisjointSet
import dev.openrs2.util.indefiniteArticle
import org.objectweb.asm.Type
class FieldMappingGenerator(
private val classPath: ClassPath,
private val excludedFields: MemberFilter,
private val classMapping: Map<String, String>
) {
private val inheritedFieldSets = classPath.createInheritedFieldSets()
private val nameGenerator = NameGenerator()
private val mapping = mutableMapOf<MemberRef, String>()
fun generate(): Map<MemberRef, String> {
for (partition in inheritedFieldSets) {
if (!isRenamable(partition)) {
continue
}
val type = Type.getType(partition.first().desc)
val mappedName = generateName(type)
for (field in partition) {
mapping[field] = mappedName
}
}
return mapping
}
private fun isRenamable(partition: DisjointSet.Partition<MemberRef>): Boolean {
for (field in partition) {
val clazz = classPath[field.owner]!!
if (excludedFields.matches(field) || clazz.dependency) {
return false
}
}
return true
}
private fun generateName(type: Type): String {
val dimensions: String
val elementType: Type
if (type.sort == Type.ARRAY) {
dimensions = "Array".repeat(type.dimensions)
elementType = type.elementType
} else {
dimensions = ""
elementType = type
}
val prefix = when (elementType.sort) {
Type.BOOLEAN, Type.BYTE, Type.CHAR, Type.SHORT, Type.INT, Type.LONG, Type.FLOAT, Type.DOUBLE -> {
elementType.className + dimensions
}
Type.OBJECT -> {
val className = classMapping.getOrDefault(elementType.internalName, elementType.internalName)
className.substring(className.lastIndexOf('/') + 1) + dimensions
}
else -> throw IllegalArgumentException("Unknown field type $elementType")
}
return nameGenerator.generate(prefix.indefiniteArticle() + prefix.capitalize())
}
}

@ -0,0 +1,58 @@
package dev.openrs2.deob.remap
import dev.openrs2.asm.MemberDesc
import dev.openrs2.asm.MemberRef
import dev.openrs2.asm.classpath.ClassPath
import dev.openrs2.asm.filter.MemberFilter
import dev.openrs2.util.collect.DisjointSet
import org.objectweb.asm.Opcodes
class MethodMappingGenerator(
private val classPath: ClassPath,
private val excludedMethods: MemberFilter
) {
private val inheritedMethodSets = classPath.createInheritedMethodSets()
private var index = 0
fun generate(): Map<MemberRef, String> {
val mapping = mutableMapOf<MemberRef, String>()
for (partition in inheritedMethodSets) {
@Suppress("DEPRECATION")
if (!isRenamable(classPath, excludedMethods, partition)) {
continue
}
val mappedName = "method" + ++index
for (method in partition) {
mapping[method] = mappedName
}
}
return mapping
}
companion object {
@Deprecated("No replacement yet")
fun isRenamable(
classPath: ClassPath,
excludedMethods: MemberFilter,
partition: DisjointSet.Partition<MemberRef>
): Boolean {
for (method in partition) {
val clazz = classPath[method.owner]!!
if (excludedMethods.matches(method) || clazz.dependency) {
return false
}
val access = clazz.getMethodAccess(MemberDesc(method))
if (access != null && access and Opcodes.ACC_NATIVE != 0) {
return false
}
}
return true
}
}
}

@ -0,0 +1,19 @@
package dev.openrs2.deob.remap
class NameGenerator {
private val prefixes = mutableMapOf<String, Int>()
fun generate(prefix: String): String {
require(prefix.isNotEmpty())
val separator = if (prefix.last().isDigit()) {
"_"
} else {
""
}
val index = prefixes.merge(prefix, 1, Integer::sum)
return prefix + separator + index
}
}

@ -1,18 +1,10 @@
package dev.openrs2.deob.remap package dev.openrs2.deob.remap
import com.github.michaelbull.logging.InlineLogger import com.github.michaelbull.logging.InlineLogger
import dev.openrs2.asm.MemberDesc
import dev.openrs2.asm.MemberRef import dev.openrs2.asm.MemberRef
import dev.openrs2.asm.classpath.ClassMetadata
import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.ClassPath
import dev.openrs2.asm.classpath.ExtendedRemapper import dev.openrs2.asm.classpath.ExtendedRemapper
import dev.openrs2.asm.filter.ClassFilter
import dev.openrs2.asm.filter.MemberFilter
import dev.openrs2.deob.Profile import dev.openrs2.deob.Profile
import dev.openrs2.util.collect.DisjointSet
import dev.openrs2.util.indefiniteArticle
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
class TypedRemapper private constructor( class TypedRemapper private constructor(
private val classes: Map<String, String>, private val classes: Map<String, String>,
@ -37,12 +29,9 @@ class TypedRemapper private constructor(
private val LIBRARY_PREFIX_REGEX = Regex("^(?:loader|unpackclass)_") private val LIBRARY_PREFIX_REGEX = Regex("^(?:loader|unpackclass)_")
fun create(classPath: ClassPath, profile: Profile): TypedRemapper { fun create(classPath: ClassPath, profile: Profile): TypedRemapper {
val inheritedFieldSets = classPath.createInheritedFieldSets() val classes = ClassMappingGenerator(classPath, profile.excludedClasses).generate()
val inheritedMethodSets = classPath.createInheritedMethodSets() val fields = FieldMappingGenerator(classPath, profile.excludedFields, classes).generate()
val methods = MethodMappingGenerator(classPath, profile.excludedMethods).generate()
val classes = createClassMapping(classPath, profile.excludedClasses)
val fields = createFieldMapping(classPath, profile.excludedFields, inheritedFieldSets, classes)
val methods = createMethodMapping(classPath, profile.excludedMethods, inheritedMethodSets)
verifyMapping(classes, profile.maxObfuscatedNameLen) verifyMapping(classes, profile.maxObfuscatedNameLen)
verifyMemberMapping(fields, profile.maxObfuscatedNameLen) verifyMemberMapping(fields, profile.maxObfuscatedNameLen)
@ -69,188 +58,5 @@ class TypedRemapper private constructor(
logger.warn { "Remapping probably unobfuscated name $originalName to $mappedName" } logger.warn { "Remapping probably unobfuscated name $originalName to $mappedName" }
} }
} }
private fun generateName(prefixes: MutableMap<String, Int>, prefix: String): String {
val separator = if (prefix.last().isDigit()) {
"_"
} else {
""
}
return prefix + separator + prefixes.merge(prefix, 1, Integer::sum)
}
private fun createClassMapping(classPath: ClassPath, excludedClasses: ClassFilter): Map<String, String> {
val mapping = mutableMapOf<String, String>()
val prefixes = mutableMapOf<String, Int>()
for (clazz in classPath.libraryClasses) {
populateClassMapping(excludedClasses, mapping, prefixes, clazz)
}
return mapping
}
private fun populateClassMapping(
excludedClasses: ClassFilter,
mapping: MutableMap<String, String>,
prefixes: MutableMap<String, Int>,
clazz: ClassMetadata
): String {
val name = clazz.name
if (mapping.containsKey(name) || !isClassRenamable(clazz, excludedClasses)) {
return mapping.getOrDefault(name, name)
}
val mappedName = generateClassName(excludedClasses, mapping, prefixes, clazz)
mapping[name] = mappedName
return mappedName
}
private fun isClassRenamable(clazz: ClassMetadata, excludedClasses: ClassFilter): Boolean {
if (excludedClasses.matches(clazz.name) || clazz.dependency) {
return false
}
for (method in clazz.methods) {
if (clazz.getMethodAccess(method)!! and Opcodes.ACC_NATIVE != 0) {
return false
}
}
return true
}
private fun generateClassName(
excludedClasses: ClassFilter,
mapping: MutableMap<String, String>,
prefixes: MutableMap<String, Int>,
clazz: ClassMetadata
): String {
val name = clazz.name
var mappedName = name.substring(0, name.lastIndexOf('/') + 1)
val superClass = clazz.superClass
if (superClass != null && superClass.name != "java/lang/Object") {
var superName = populateClassMapping(excludedClasses, mapping, prefixes, superClass)
superName = superName.substring(superName.lastIndexOf('/') + 1)
mappedName += generateName(prefixes, superName + "_Sub")
} else if (clazz.`interface`) {
mappedName += generateName(prefixes, "Interface")
} else {
mappedName += generateName(prefixes, "Class")
}
return mappedName
}
private fun createFieldMapping(
classPath: ClassPath,
excludedFields: MemberFilter,
disjointSet: DisjointSet<MemberRef>,
classMapping: Map<String, String>
): Map<MemberRef, String> {
val mapping = mutableMapOf<MemberRef, String>()
val prefixes = mutableMapOf<String, Int>()
for (partition in disjointSet) {
if (!isFieldRenamable(classPath, excludedFields, partition)) {
continue
}
val type = Type.getType(partition.first().desc)
val mappedName = generateFieldName(prefixes, classMapping, type)
for (field in partition) {
mapping[field] = mappedName
}
}
return mapping
}
private fun isFieldRenamable(
classPath: ClassPath,
excludedFields: MemberFilter,
partition: DisjointSet.Partition<MemberRef>
): Boolean {
for (field in partition) {
val clazz = classPath[field.owner]!!
if (excludedFields.matches(field) || clazz.dependency) {
return false
}
}
return true
}
private fun generateFieldName(
prefixes: MutableMap<String, Int>,
classMapping: Map<String, String>,
type: Type
): String {
val dimensions: String
val elementType: Type
if (type.sort == Type.ARRAY) {
dimensions = "Array".repeat(type.dimensions)
elementType = type.elementType
} else {
dimensions = ""
elementType = type
}
val prefix = when (elementType.sort) {
Type.BOOLEAN, Type.BYTE, Type.CHAR, Type.SHORT, Type.INT, Type.LONG, Type.FLOAT, Type.DOUBLE -> {
elementType.className + dimensions
}
Type.OBJECT -> {
val className = classMapping.getOrDefault(elementType.internalName, elementType.internalName)
className.substring(className.lastIndexOf('/') + 1) + dimensions
}
else -> throw IllegalArgumentException("Unknown field type $elementType")
}
return generateName(prefixes, prefix.indefiniteArticle() + prefix.capitalize())
}
private fun createMethodMapping(
classPath: ClassPath,
excludedMethods: MemberFilter,
disjointSet: DisjointSet<MemberRef>
): Map<MemberRef, String> {
val mapping = mutableMapOf<MemberRef, String>()
var id = 0
for (partition in disjointSet) {
if (!isMethodRenamable(classPath, excludedMethods, partition)) {
continue
}
val mappedName = "method" + ++id
for (method in partition) {
mapping[method] = mappedName
}
}
return mapping
}
fun isMethodRenamable(
classPath: ClassPath,
excludedMethods: MemberFilter,
partition: DisjointSet.Partition<MemberRef>
): Boolean {
for (method in partition) {
val clazz = classPath[method.owner]!!
if (excludedMethods.matches(method) || clazz.dependency) {
return false
}
val access = clazz.getMethodAccess(MemberDesc(method))
if (access != null && access and Opcodes.ACC_NATIVE != 0) {
return false
}
}
return true
}
} }
} }

@ -11,7 +11,7 @@ import dev.openrs2.deob.ArgRef
import dev.openrs2.deob.Profile import dev.openrs2.deob.Profile
import dev.openrs2.deob.analysis.ConstSourceInterpreter import dev.openrs2.deob.analysis.ConstSourceInterpreter
import dev.openrs2.deob.analysis.ConstSourceValue import dev.openrs2.deob.analysis.ConstSourceValue
import dev.openrs2.deob.remap.TypedRemapper import dev.openrs2.deob.remap.MethodMappingGenerator
import dev.openrs2.util.collect.DisjointSet import dev.openrs2.util.collect.DisjointSet
import org.objectweb.asm.Opcodes import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type import org.objectweb.asm.Type
@ -75,7 +75,9 @@ class UnusedArgTransformer @Inject constructor(private val profile: Profile) : T
val invokePartition = inheritedMethodSets[MemberRef(insn)] val invokePartition = inheritedMethodSets[MemberRef(insn)]
if (invokePartition == null) { if (invokePartition == null) {
continue@frame continue@frame
} else if (!TypedRemapper.isMethodRenamable(classPath, profile.excludedMethods, invokePartition)) { } else if (
!MethodMappingGenerator.isRenamable(classPath, profile.excludedMethods, invokePartition)
) {
continue@frame continue@frame
} }
@ -119,7 +121,9 @@ class UnusedArgTransformer @Inject constructor(private val profile: Profile) : T
} }
val partition = inheritedMethodSets[MemberRef(insn)] val partition = inheritedMethodSets[MemberRef(insn)]
if (partition == null || !TypedRemapper.isMethodRenamable(classPath, profile.excludedMethods, partition)) { if (partition == null) {
continue
} else if (!MethodMappingGenerator.isRenamable(classPath, profile.excludedMethods, partition)) {
continue continue
} }
@ -152,7 +156,7 @@ class UnusedArgTransformer @Inject constructor(private val profile: Profile) : T
): Boolean { ): Boolean {
// delete unused int args from the method itself // delete unused int args from the method itself
val partition = inheritedMethodSets[MemberRef(clazz, method)]!! val partition = inheritedMethodSets[MemberRef(clazz, method)]!!
if (!TypedRemapper.isMethodRenamable(classPath, profile.excludedMethods, partition)) { if (!MethodMappingGenerator.isRenamable(classPath, profile.excludedMethods, partition)) {
return false return false
} }

Loading…
Cancel
Save