diff --git a/deob/src/main/java/dev/openrs2/deob/remap/ClassMappingGenerator.kt b/deob/src/main/java/dev/openrs2/deob/remap/ClassMappingGenerator.kt new file mode 100644 index 0000000000..03a2d8c95a --- /dev/null +++ b/deob/src/main/java/dev/openrs2/deob/remap/ClassMappingGenerator.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() + + fun generate(): Map { + 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 + } +} diff --git a/deob/src/main/java/dev/openrs2/deob/remap/FieldMappingGenerator.kt b/deob/src/main/java/dev/openrs2/deob/remap/FieldMappingGenerator.kt new file mode 100644 index 0000000000..094b60c745 --- /dev/null +++ b/deob/src/main/java/dev/openrs2/deob/remap/FieldMappingGenerator.kt @@ -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 +) { + private val inheritedFieldSets = classPath.createInheritedFieldSets() + private val nameGenerator = NameGenerator() + private val mapping = mutableMapOf() + + fun generate(): Map { + 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): 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()) + } +} diff --git a/deob/src/main/java/dev/openrs2/deob/remap/MethodMappingGenerator.kt b/deob/src/main/java/dev/openrs2/deob/remap/MethodMappingGenerator.kt new file mode 100644 index 0000000000..88637f7e06 --- /dev/null +++ b/deob/src/main/java/dev/openrs2/deob/remap/MethodMappingGenerator.kt @@ -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 { + val mapping = mutableMapOf() + + 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 + ): 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 + } + } +} diff --git a/deob/src/main/java/dev/openrs2/deob/remap/NameGenerator.kt b/deob/src/main/java/dev/openrs2/deob/remap/NameGenerator.kt new file mode 100644 index 0000000000..dfb04f5756 --- /dev/null +++ b/deob/src/main/java/dev/openrs2/deob/remap/NameGenerator.kt @@ -0,0 +1,19 @@ +package dev.openrs2.deob.remap + +class NameGenerator { + private val prefixes = mutableMapOf() + + 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 + } +} diff --git a/deob/src/main/java/dev/openrs2/deob/remap/TypedRemapper.kt b/deob/src/main/java/dev/openrs2/deob/remap/TypedRemapper.kt index 059f25fea9..9070232715 100644 --- a/deob/src/main/java/dev/openrs2/deob/remap/TypedRemapper.kt +++ b/deob/src/main/java/dev/openrs2/deob/remap/TypedRemapper.kt @@ -1,18 +1,10 @@ package dev.openrs2.deob.remap import com.github.michaelbull.logging.InlineLogger -import dev.openrs2.asm.MemberDesc import dev.openrs2.asm.MemberRef -import dev.openrs2.asm.classpath.ClassMetadata import dev.openrs2.asm.classpath.ClassPath 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.util.collect.DisjointSet -import dev.openrs2.util.indefiniteArticle -import org.objectweb.asm.Opcodes -import org.objectweb.asm.Type class TypedRemapper private constructor( private val classes: Map, @@ -37,12 +29,9 @@ class TypedRemapper private constructor( private val LIBRARY_PREFIX_REGEX = Regex("^(?:loader|unpackclass)_") fun create(classPath: ClassPath, profile: Profile): TypedRemapper { - val inheritedFieldSets = classPath.createInheritedFieldSets() - val inheritedMethodSets = classPath.createInheritedMethodSets() - - val classes = createClassMapping(classPath, profile.excludedClasses) - val fields = createFieldMapping(classPath, profile.excludedFields, inheritedFieldSets, classes) - val methods = createMethodMapping(classPath, profile.excludedMethods, inheritedMethodSets) + val classes = ClassMappingGenerator(classPath, profile.excludedClasses).generate() + val fields = FieldMappingGenerator(classPath, profile.excludedFields, classes).generate() + val methods = MethodMappingGenerator(classPath, profile.excludedMethods).generate() verifyMapping(classes, profile.maxObfuscatedNameLen) verifyMemberMapping(fields, profile.maxObfuscatedNameLen) @@ -69,188 +58,5 @@ class TypedRemapper private constructor( logger.warn { "Remapping probably unobfuscated name $originalName to $mappedName" } } } - - private fun generateName(prefixes: MutableMap, 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 { - val mapping = mutableMapOf() - val prefixes = mutableMapOf() - for (clazz in classPath.libraryClasses) { - populateClassMapping(excludedClasses, mapping, prefixes, clazz) - } - return mapping - } - - private fun populateClassMapping( - excludedClasses: ClassFilter, - mapping: MutableMap, - prefixes: MutableMap, - 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, - prefixes: MutableMap, - 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, - classMapping: Map - ): Map { - val mapping = mutableMapOf() - val prefixes = mutableMapOf() - - 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 - ): 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, - classMapping: Map, - 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 - ): Map { - val mapping = mutableMapOf() - 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 - ): 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 - } } } diff --git a/deob/src/main/java/dev/openrs2/deob/transform/UnusedArgTransformer.kt b/deob/src/main/java/dev/openrs2/deob/transform/UnusedArgTransformer.kt index 0960d58a0e..1679ce11d8 100644 --- a/deob/src/main/java/dev/openrs2/deob/transform/UnusedArgTransformer.kt +++ b/deob/src/main/java/dev/openrs2/deob/transform/UnusedArgTransformer.kt @@ -11,7 +11,7 @@ import dev.openrs2.deob.ArgRef import dev.openrs2.deob.Profile import dev.openrs2.deob.analysis.ConstSourceInterpreter 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 org.objectweb.asm.Opcodes import org.objectweb.asm.Type @@ -75,7 +75,9 @@ class UnusedArgTransformer @Inject constructor(private val profile: Profile) : T val invokePartition = inheritedMethodSets[MemberRef(insn)] if (invokePartition == null) { continue@frame - } else if (!TypedRemapper.isMethodRenamable(classPath, profile.excludedMethods, invokePartition)) { + } else if ( + !MethodMappingGenerator.isRenamable(classPath, profile.excludedMethods, invokePartition) + ) { continue@frame } @@ -119,7 +121,9 @@ class UnusedArgTransformer @Inject constructor(private val profile: Profile) : T } 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 } @@ -152,7 +156,7 @@ class UnusedArgTransformer @Inject constructor(private val profile: Profile) : T ): Boolean { // delete unused int args from the method itself val partition = inheritedMethodSets[MemberRef(clazz, method)]!! - if (!TypedRemapper.isMethodRenamable(classPath, profile.excludedMethods, partition)) { + if (!MethodMappingGenerator.isRenamable(classPath, profile.excludedMethods, partition)) { return false }