Skip to content

Commit

Permalink
Fixed Method Rename and Class Dumper
Browse files Browse the repository at this point in the history
  • Loading branch information
SpartanB312 committed Jun 27, 2024
1 parent 8fcc9e9 commit c028b39
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ object Transformers : Collection<Transformer> by mutableListOf(
TrashClassTransformer,
StringEncryptTransformer,
NumberEncryptTransformer,
InitializerRedirectTransformer,
//InitializerRedirectTransformer, DISABLED
StringEqualsRedirectTransformer,
FieldRedirectTransformer,
NativeCandidateTransformer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ class ClassDumper(
useComputeMax: Boolean = false
) : ClassWriter(if (useComputeMax) COMPUTE_MAXS else COMPUTE_FRAMES) {

override fun getCommonSuperClass(type1: String, type2: String): String? {
val clazz1 = resourceCache.getClassNode(type1) ?: return null
val clazz2 = resourceCache.getClassNode(type2) ?: return null
override fun getCommonSuperClass(type1: String, type2: String): String {
val clazz1 = resourceCache.getClassNode(type1) ?: return "java/lang/Object"
val clazz2 = resourceCache.getClassNode(type2) ?: return "java/lang/Object"
return when {
type1 == "java/lang/Object" -> type1
type2 == "java/lang/Object" -> type2
clazz1.isInterface && clazz2.isInterface -> "java/lang/Object"
hierarchy.isSubType(type1, type2) -> type2
hierarchy.isSubType(type2, type1) -> type1
else -> return null
else -> return "java/lang/Object"
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,14 @@ class ResourceCache(private val input: String, private val libs: List<String>) {
}.toByteArray()
} catch (ignore: Exception) {
Logger.error("Failed to dump class ${classNode.name}. Force use COMPUTE_MAXS")
ClassDumper(this@ResourceCache, hierarchy, false).apply {
classNode.accept(this)
}.toByteArray()
try {
ClassDumper(this@ResourceCache, hierarchy, false).apply {
classNode.accept(this)
}.toByteArray()
} catch (exception: Exception) {
exception.printStackTrace()
ByteArray(0)
}
}
putNextEntry(ZipEntry(classNode.name + ".class"))
write(byteArray)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import net.spartanb312.grunt.process.Transformer
import net.spartanb312.grunt.process.hierarchy.FastHierarchy
import net.spartanb312.grunt.process.resource.NameGenerator
import net.spartanb312.grunt.process.resource.ResourceCache
import net.spartanb312.grunt.process.transformers.rename.FieldRenameTransformer.isPrimeField
import net.spartanb312.grunt.utils.extensions.isAnnotation
import net.spartanb312.grunt.utils.isExcludedIn
import net.spartanb312.grunt.utils.isNotExcludedIn
import net.spartanb312.grunt.utils.logging.Logger
import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.tree.FieldNode
import kotlin.system.measureTimeMillis

/**
Expand Down Expand Up @@ -65,6 +66,16 @@ object MixinFieldRenameTransformer : Transformer("MixinFieldRename", Category.Mi
Logger.info(" Renamed ${mappings.size} mixin fields")
}

fun FastHierarchy.isPrimeField(owner: ClassNode, field: FieldNode): Boolean {
val ownerInfo = getHierarchyInfo(owner)
if (ownerInfo.missingDependencies) return false
return ownerInfo.parents.none { p ->
if (p is FastHierarchy.HierarchyInfo) {
p.classNode.fields.any { it.name == field.name && it.desc == field.desc }
} else true//Missing dependencies
}
}

private val annotations = mutableListOf(
"Lorg/spongepowered/asm/mixin/gen/Accessor",
"Lorg/spongepowered/asm/mixin/gen/Invoker",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,53 +36,44 @@ object FieldRenameTransformer : Transformer("FiledRename", Category.Renaming) {
override fun ResourceCache.transform() {
Logger.info(" - Renaming fields...")

Logger.info(" Building hierarchy graph...")
val hierarchy = FastHierarchy(this)
val buildTime = measureTimeMillis {
hierarchy.build()
}
Logger.info(" Took ${buildTime}ms to build ${hierarchy.size} hierarchies")

val mappings = HashMap<String, String>()
nonExcluded.asSequence()
.filter { !it.isAnnotation && it.name.isNotExcludedIn(exclusion) }
.forEach { classNode ->
val dictionary = NameGenerator.getByName(dictionary)
val info = hierarchy.getHierarchyInfo(classNode)
if (!info.missingDependencies) {
for (fieldNode in classNode.fields) {
if (fieldNode.name.isExcludedIn(excludedName)) continue
if (hierarchy.isPrimeField(classNode, fieldNode)) {
val key = classNode.name + "." + fieldNode.name
val newName = malPrefix + dictionary.nextName()
mappings[key] = newName
// Apply for children
info.children.forEach { c ->
if (c is FastHierarchy.HierarchyInfo) {
val childKey = c.classNode.name + "." + fieldNode.name
mappings[childKey] = newName
}
}
} else continue
val fields: MutableList<FieldNode> = ArrayList()
nonExcluded.forEach { fields.addAll(it.fields) }
fields.shuffle()

val dictionaries = ConcurrentHashMap<ClassNode?, NameGenerator>()
val count = count {
for (fieldNode in fields) {
if (fieldNode.name.isExcludedIn(excludedName)) continue
val c = getOwner(fieldNode, classes)
val dic = dictionaries.getOrPut(c) { NameGenerator.getByName(dictionary) }
val name = malPrefix + dic.nextName()
val stack: Stack<ClassNode> = Stack()
stack.add(c)
while (stack.size > 0) {
val classNode = stack.pop()
val key = classNode.name + "." + fieldNode.name
if (key.isNotExcludedIn(exclusion)) {
mappings[key] = name
}
classes.values.forEach {
if (it.superName == classNode.name || it.interfaces.contains(classNode.name))
stack.add(it)
}
}
add()
}

}.get()

Logger.info(" Applying remapping for fields...")
applyRemap("fields", mappings)

Logger.info(" Renamed ${mappings.size} fields")
Logger.info(" Renamed $count fields")
}

fun FastHierarchy.isPrimeField(owner: ClassNode, field: FieldNode): Boolean {
val ownerInfo = getHierarchyInfo(owner)
if (ownerInfo.missingDependencies) return false
return ownerInfo.parents.none { p ->
if (p is FastHierarchy.HierarchyInfo) {
p.classNode.fields.any { it.name == field.name && it.desc == field.desc }
} else true//Missing dependencies
}
private fun getOwner(f: FieldNode, classNodes: MutableMap<String, ClassNode>): ClassNode? {
for (c in classNodes.values) if (c.fields.contains(f)) return c
return null
}

}
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
package net.spartanb312.grunt.process.transformers.rename

import net.spartanb312.grunt.config.Configs
import net.spartanb312.grunt.config.value
import net.spartanb312.grunt.process.resource.NameGenerator
import net.spartanb312.grunt.process.Transformer
import net.spartanb312.grunt.process.hierarchy.FastHierarchy
import net.spartanb312.grunt.process.resource.NameGenerator
import net.spartanb312.grunt.process.resource.ResourceCache
import net.spartanb312.grunt.utils.*
import net.spartanb312.grunt.utils.count
import net.spartanb312.grunt.utils.extensions.isAnnotation
import net.spartanb312.grunt.utils.extensions.isEnum
import net.spartanb312.grunt.utils.extensions.isNative
import net.spartanb312.grunt.utils.isExcludedIn
import net.spartanb312.grunt.utils.isNotExcludedIn
import net.spartanb312.grunt.utils.logging.Logger
import net.spartanb312.grunt.utils.nextBadKeyword
import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.tree.MethodNode
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CountDownLatch
import kotlin.system.measureTimeMillis

/**
Expand All @@ -37,7 +39,7 @@ object MethodRenameTransformer : Transformer("MethodRename", Category.Renaming)
Logger.info(" - Renaming methods...")

Logger.info(" Building hierarchy graph...")
val hierarchy = FastHierarchy(this)
val hierarchy = FastHierarchy(this, true)
val buildTime = measureTimeMillis {
hierarchy.build()
}
Expand All @@ -47,46 +49,55 @@ object MethodRenameTransformer : Transformer("MethodRename", Category.Renaming)
val mappings = ConcurrentHashMap<String, String>()
val count = count {
// Generate names and apply to children
val tasks = mutableListOf<Runnable>()
nonExcluded.asSequence()
.filter { !it.isAnnotation && it.name.isNotExcludedIn(exclusion) }
.filter { !it.isEnum && !it.isAnnotation && it.name.isNotExcludedIn(exclusion) }
.forEach { classNode ->
val task = Runnable {
val info = hierarchy.getHierarchyInfo(classNode)
if (!info.missingDependencies) {
for (methodNode in classNode.methods) {
if (methodNode.name.startsWith("<")) continue
if (methodNode.name == "main") continue
if (methodNode.name.isExcludedIn(excludedName)) continue
if (methodNode.isNative) continue
if (hierarchy.isPrimeMethod(classNode, methodNode)) {
val newName = (if (randomKeywordPrefix) "$nextBadKeyword " else "") +
prefix + dic.nextName(heavyOverloads, methodNode.desc)
mappings[combine(classNode.name, methodNode.name, methodNode.desc)] = newName
// Apply to children
info.children.forEach { c ->
if (c is FastHierarchy.HierarchyInfo) {
val childKey = combine(c.classNode.name, methodNode.name, methodNode.desc)
mappings[childKey] = newName
val info = hierarchy.getHierarchyInfo(classNode)
if (!info.missingDependencies) {
for (methodNode in classNode.methods) {
if (methodNode.name.startsWith("<")) continue
if (methodNode.name == "main") continue
if (methodNode.name.isExcludedIn(excludedName)) continue
if (methodNode.isNative) continue
if (hierarchy.isPrimeMethod(classNode, methodNode)) {
val readyToApply = mutableMapOf<String, String>()
var shouldApply = true
val newName = (if (randomKeywordPrefix) "$nextBadKeyword " else "") +
prefix + dic.nextName(heavyOverloads, methodNode.desc)
readyToApply[combine(classNode.name, methodNode.name, methodNode.desc)] = newName
// Check children
info.children.forEach { c ->
if (c is FastHierarchy.HierarchyInfo) {
// Check its origin
for (parent in c.parents) {
if (parent.missingDependencies) shouldApply = false
if (parent is FastHierarchy.HierarchyInfo) {
val flag1 = !hierarchy.isSubType(parent.classNode.name, classNode.name)
val flag2 = !hierarchy.isSubType(classNode.name, parent.classNode.name)
if (parent.classNode.name != classNode.name && (flag1 && flag2)) {
parent.classNode.methods.forEach { check ->
if (check.name == methodNode.name && check.desc == methodNode.desc) {
// Skip multi origin methods
shouldApply = false
//Logger.debug("Multi Origin ${methodNode.name}${methodNode.desc} in ${classNode.name} and ${parent.classNode.name}")
}
}
}
}
}

val childKey = combine(c.classNode.name, methodNode.name, methodNode.desc)
readyToApply[childKey] = newName
}
add()
} else continue
}
}
// Apply mappings
if (shouldApply) readyToApply.forEach { (key, value) -> mappings[key] = value }
add()
} else continue
}
}
if (Configs.Settings.parallel) tasks.add(task) else task.run()
}
if (Configs.Settings.parallel) {
val cdl = CountDownLatch(tasks.size)
tasks.forEach {
Thread {
it.run()
cdl.countDown()
}.start()

}
cdl.await()
}
}.get()

Logger.info(" Applying remapping for methods...")
Expand Down

0 comments on commit c028b39

Please sign in to comment.