From 2fbcf8e5c4eec0aa4a4fc59c7cc8abac33b1429c Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 19 Jan 2015 22:22:57 -0500 Subject: solved tricky issue with incorrect translation of fields/methods referenced by a subclass instead of the declaring class --- src/cuchaz/enigma/Deobfuscator.java | 8 +- src/cuchaz/enigma/Main.java | 2 +- .../enigma/analysis/ClassInheritanceTreeNode.java | 4 +- src/cuchaz/enigma/analysis/JarIndex.java | 65 +++----- .../enigma/analysis/MethodInheritanceTreeNode.java | 4 +- src/cuchaz/enigma/analysis/TranslationIndex.java | 172 ++++++++++++++++----- src/cuchaz/enigma/bytecode/ClassTranslator.java | 9 ++ src/cuchaz/enigma/mapping/JavassistUtil.java | 55 +++++++ src/cuchaz/enigma/mapping/Mappings.java | 11 +- src/cuchaz/enigma/mapping/MappingsRenamer.java | 6 +- src/cuchaz/enigma/mapping/Translator.java | 57 ++++--- 11 files changed, 271 insertions(+), 122 deletions(-) create mode 100644 src/cuchaz/enigma/mapping/JavassistUtil.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 679518a..2305722 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -144,7 +144,7 @@ public class Deobfuscator { // fields for (FieldMapping fieldMapping : Lists.newArrayList(classMapping.fields())) { FieldEntry fieldEntry = new FieldEntry(obfClassEntry, fieldMapping.getObfName()); - ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(fieldEntry); + ClassEntry resolvedObfClassEntry = m_jarIndex.getTranslationIndex().resolveEntryClass(fieldEntry); if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(fieldEntry.getClassEntry())) { boolean wasMoved = renamer.moveFieldToObfClass(classMapping, fieldMapping, resolvedObfClassEntry); if (wasMoved) { @@ -167,7 +167,7 @@ public class Deobfuscator { methodMapping.getObfName(), methodMapping.getObfSignature() ); - ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(methodEntry); + ClassEntry resolvedObfClassEntry = m_jarIndex.getTranslationIndex().resolveEntryClass(methodEntry); if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(methodEntry.getClassEntry())) { boolean wasMoved = renamer.moveMethodToObfClass(classMapping, methodMapping, resolvedObfClassEntry); if (wasMoved) { @@ -233,7 +233,7 @@ public class Deobfuscator { public Translator getTranslator(TranslationDirection direction) { Translator translator = m_translatorCache.get(direction); if (translator == null) { - translator = m_mappings.getTranslator(direction); + translator = m_mappings.getTranslator(direction, m_jarIndex.getTranslationIndex()); m_translatorCache.put(direction, translator); } return translator; @@ -311,7 +311,7 @@ public class Deobfuscator { Entry obfEntry = obfuscateEntry(deobfReference.entry); // try to resolve the class - ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(obfEntry); + ClassEntry resolvedObfClassEntry = m_jarIndex.getTranslationIndex().resolveEntryClass(obfEntry); if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(obfEntry.getClassEntry())) { // change the class of the entry obfEntry = obfEntry.cloneToNewClass(resolvedObfClassEntry); diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index f8d3afe..1891ded 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -28,7 +28,7 @@ public class Main { } // DEBUG - // gui.getController().openDeclaration( new ClassEntry( "none/ces" ) ); + //gui.getController().openDeclaration(new ClassEntry("none/bxq")); } private static File getFile(String path) { diff --git a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java index b132305..3eaa391 100644 --- a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java @@ -51,8 +51,8 @@ public class ClassInheritanceTreeNode extends DefaultMutableTreeNode { public void load(TranslationIndex ancestries, boolean recurse) { // get all the child nodes List nodes = Lists.newArrayList(); - for (String subclassName : ancestries.getSubclassNames(m_obfClassName)) { - nodes.add(new ClassInheritanceTreeNode(m_deobfuscatingTranslator, subclassName)); + for (ClassEntry subclassEntry : ancestries.getSubclass(new ClassEntry(m_obfClassName))) { + nodes.add(new ClassInheritanceTreeNode(m_deobfuscatingTranslator, subclassEntry.getName())); } // add them to this node diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 4b03a33..c96d3bc 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -114,8 +114,8 @@ public class JarIndex { // step 3: index extends, implements, fields, and methods for (CtClass c : JarClassIterator.classes(jar)) { ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); + m_translationIndex.indexClass(c); String className = Descriptor.toJvmName(c.getName()); - m_translationIndex.addSuperclass(className, Descriptor.toJvmName(c.getClassFile().getSuperclass())); for (String interfaceName : c.getClassFile().getInterfaces()) { className = Descriptor.toJvmName(className); interfaceName = Descriptor.toJvmName(interfaceName); @@ -191,8 +191,6 @@ public class JarIndex { String className = Descriptor.toJvmName(field.getDeclaringClass().getName()); FieldEntry fieldEntry = new FieldEntry(new ClassEntry(className), field.getName()); - m_translationIndex.addField(className, field.getName()); - // is the field a class type? if (field.getSignature().startsWith("L")) { ClassEntry fieldTypeEntry = new ClassEntry(field.getSignature().substring(1, field.getSignature().length() - 1)); @@ -230,13 +228,12 @@ public class JarIndex { behavior.instrument(new ExprEditor() { @Override public void edit(MethodCall call) { - String className = Descriptor.toJvmName(call.getClassName()); MethodEntry calledMethodEntry = new MethodEntry( - new ClassEntry(className), + new ClassEntry(Descriptor.toJvmName(call.getClassName())), call.getMethodName(), call.getSignature() ); - ClassEntry resolvedClassEntry = resolveEntryClass(calledMethodEntry); + ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledMethodEntry); if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledMethodEntry.getClassEntry())) { calledMethodEntry = new MethodEntry( resolvedClassEntry, @@ -254,12 +251,11 @@ public class JarIndex { @Override public void edit(FieldAccess call) { - String className = Descriptor.toJvmName(call.getClassName()); FieldEntry calledFieldEntry = new FieldEntry( - new ClassEntry(className), + new ClassEntry(Descriptor.toJvmName(call.getClassName())), call.getFieldName() ); - ClassEntry resolvedClassEntry = resolveEntryClass(calledFieldEntry); + ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledFieldEntry); if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledFieldEntry.getClassEntry())) { calledFieldEntry = new FieldEntry(resolvedClassEntry, call.getFieldName()); } @@ -273,9 +269,8 @@ public class JarIndex { @Override public void edit(ConstructorCall call) { - String className = Descriptor.toJvmName(call.getClassName()); ConstructorEntry calledConstructorEntry = new ConstructorEntry( - new ClassEntry(className), + new ClassEntry(Descriptor.toJvmName(call.getClassName())), call.getSignature() ); EntryReference reference = new EntryReference( @@ -288,9 +283,8 @@ public class JarIndex { @Override public void edit(NewExpr call) { - String className = Descriptor.toJvmName(call.getClassName()); ConstructorEntry calledConstructorEntry = new ConstructorEntry( - new ClassEntry(className), + new ClassEntry(Descriptor.toJvmName(call.getClassName())), call.getSignature() ); EntryReference reference = new EntryReference( @@ -306,25 +300,6 @@ public class JarIndex { } } - public ClassEntry resolveEntryClass(Entry obfEntry) { - - // this entry could refer to a method on a class where the method is not actually implemented - // travel up the inheritance tree to find the closest implementation - while (!containsObfEntry(obfEntry)) { - // is there a parent class? - String superclassName = m_translationIndex.getSuperclassName(obfEntry.getClassName()); - if (superclassName == null) { - // this is probably a method from a class in a library - // we can't trace the implementation up any higher unless we index the library - return null; - } - - // move up to the parent class - obfEntry = obfEntry.cloneToNewClass(new ClassEntry(superclassName)); - } - return obfEntry.getClassEntry(); - } - private CtMethod getBridgedMethod(CtMethod method) { // bridge methods just call another method, cast it to the return type, and return the result @@ -402,9 +377,9 @@ public class JarIndex { if (reference.entry instanceof ConstructorEntry && reference.context instanceof ConstructorEntry) { // is the entry a superclass of the context? - String calledClassName = reference.entry.getClassName(); - String callerSuperclassName = m_translationIndex.getSuperclassName(reference.context.getClassName()); - if (callerSuperclassName != null && callerSuperclassName.equals(calledClassName)) { + ClassEntry calledClassEntry = reference.entry.getClassEntry(); + ClassEntry superclassEntry = m_translationIndex.getSuperclass(reference.context.getClassEntry()); + if (superclassEntry != null && superclassEntry.equals(calledClassEntry)) { // it's a super call, skip continue; } @@ -599,7 +574,9 @@ public class JarIndex { // get the root node List ancestry = Lists.newArrayList(); ancestry.add(obfClassEntry.getName()); - ancestry.addAll(m_translationIndex.getAncestry(obfClassEntry.getName())); + for (ClassEntry classEntry : m_translationIndex.getAncestry(obfClassEntry)) { + ancestry.add(classEntry.getName()); + } ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get(ancestry.size() - 1) @@ -625,21 +602,21 @@ public class JarIndex { public MethodInheritanceTreeNode getMethodInheritance(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { // travel to the ancestor implementation - String baseImplementationClassName = obfMethodEntry.getClassName(); - for (String ancestorClassName : m_translationIndex.getAncestry(obfMethodEntry.getClassName())) { + ClassEntry baseImplementationClassEntry = obfMethodEntry.getClassEntry(); + for (ClassEntry ancestorClassEntry : m_translationIndex.getAncestry(obfMethodEntry.getClassEntry())) { MethodEntry ancestorMethodEntry = new MethodEntry( - new ClassEntry(ancestorClassName), + new ClassEntry(ancestorClassEntry), obfMethodEntry.getName(), obfMethodEntry.getSignature() ); if (containsObfBehavior(ancestorMethodEntry)) { - baseImplementationClassName = ancestorClassName; + baseImplementationClassEntry = ancestorClassEntry; } } // make a root node at the base MethodEntry methodEntry = new MethodEntry( - new ClassEntry(baseImplementationClassName), + baseImplementationClassEntry, obfMethodEntry.getName(), obfMethodEntry.getSignature() ); @@ -781,8 +758,8 @@ public class JarIndex { public Set getInterfaces(String className) { Set interfaceNames = new HashSet(); interfaceNames.addAll(m_interfaces.get(className)); - for (String ancestor : m_translationIndex.getAncestry(className)) { - interfaceNames.addAll(m_interfaces.get(ancestor)); + for (ClassEntry ancestor : m_translationIndex.getAncestry(new ClassEntry(className))) { + interfaceNames.addAll(m_interfaces.get(ancestor.getName())); } return interfaceNames; } @@ -795,7 +772,7 @@ public class JarIndex { String interfaceName = entry.getValue(); if (interfaceName.equals(targetInterfaceName)) { classNames.add(className); - m_translationIndex.getSubclassNamesRecursively(classNames, className); + m_translationIndex.getSubclassNamesRecursively(classNames, new ClassEntry(className)); } } return classNames; diff --git a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java index eba8d87..8718220 100644 --- a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java @@ -71,9 +71,9 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode { public void load(JarIndex index, boolean recurse) { // get all the child nodes List nodes = Lists.newArrayList(); - for (String subclassName : index.getTranslationIndex().getSubclassNames(m_entry.getClassName())) { + for (ClassEntry subclassEntry : index.getTranslationIndex().getSubclass(m_entry.getClassEntry())) { MethodEntry methodEntry = new MethodEntry( - new ClassEntry(subclassName), + subclassEntry, m_entry.getName(), m_entry.getSignature() ); diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java index c14fd59..4a356eb 100644 --- a/src/cuchaz/enigma/analysis/TranslationIndex.java +++ b/src/cuchaz/enigma/analysis/TranslationIndex.java @@ -11,97 +11,185 @@ package cuchaz.enigma.analysis; import java.io.Serializable; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; -import javassist.bytecode.Descriptor; +import javassist.CtBehavior; +import javassist.CtClass; +import javassist.CtField; import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; +import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.JavassistUtil; +import cuchaz.enigma.mapping.Translator; + public class TranslationIndex implements Serializable { private static final long serialVersionUID = 738687982126844179L; - private Map m_superclasses; - private Multimap m_fields; + private Map m_superclasses; + private Multimap m_fieldEntries; + private Multimap m_behaviorEntries; public TranslationIndex() { m_superclasses = Maps.newHashMap(); - m_fields = HashMultimap.create(); - } - - public TranslationIndex(TranslationIndex other) { - m_superclasses = Maps.newHashMap(other.m_superclasses); - m_fields = HashMultimap.create(other.m_fields); + m_fieldEntries = HashMultimap.create(); + m_behaviorEntries = HashMultimap.create(); } - public void addSuperclass(String className, String superclassName) { - className = Descriptor.toJvmName(className); - superclassName = Descriptor.toJvmName(superclassName); + public TranslationIndex(TranslationIndex other, Translator translator) { - if (className.equals(superclassName)) { - throw new IllegalArgumentException("Class cannot be its own superclass! " + className); + // translate the superclasses + m_superclasses = Maps.newHashMap(); + for (Map.Entry mapEntry : other.m_superclasses.entrySet()) { + m_superclasses.put( + translator.translateEntry(mapEntry.getKey()), + translator.translateEntry(mapEntry.getValue()) + ); } - if (!isJre(className) && !isJre(superclassName)) { - m_superclasses.put(className, superclassName); + // translate the fields + m_fieldEntries = HashMultimap.create(); + for (Map.Entry mapEntry : other.m_fieldEntries.entries()) { + m_fieldEntries.put( + translator.translateEntry(mapEntry.getKey()), + translator.translateEntry(mapEntry.getValue()) + ); + } + + m_behaviorEntries = HashMultimap.create(); + for (Map.Entry mapEntry : other.m_behaviorEntries.entries()) { + m_behaviorEntries.put( + translator.translateEntry(mapEntry.getKey()), + translator.translateEntry(mapEntry.getValue()) + ); } } - public void addField(String className, String fieldName) { - m_fields.put(className, fieldName); + public void indexClass(CtClass c) { + + ClassEntry classEntry = JavassistUtil.getClassEntry(c); + + // add the superclass + ClassEntry superclassEntry = JavassistUtil.getSuperclassEntry(c); + if (!isJre(classEntry) && !isJre(superclassEntry)) { + m_superclasses.put(classEntry, superclassEntry); + } + + // add fields + for (CtField field : c.getDeclaredFields()) { + FieldEntry fieldEntry = JavassistUtil.getFieldEntry(field); + m_fieldEntries.put(fieldEntry.getClassEntry(), fieldEntry); + } + + // add behaviors + for (CtBehavior behavior : c.getDeclaredBehaviors()) { + BehaviorEntry behaviorEntry = JavassistUtil.getBehaviorEntry(behavior); + m_behaviorEntries.put(behaviorEntry.getClassEntry(), behaviorEntry); + } } public void renameClasses(Map renames) { EntryRenamer.renameClassesInMap(renames, m_superclasses); - EntryRenamer.renameClassesInMultimap(renames, m_fields); + EntryRenamer.renameClassesInMultimap(renames, m_fieldEntries); + EntryRenamer.renameClassesInMultimap(renames, m_behaviorEntries); } - public String getSuperclassName(String className) { - return m_superclasses.get(className); + public ClassEntry getSuperclass(ClassEntry classEntry) { + return m_superclasses.get(classEntry); } - public List getAncestry(String className) { - List ancestors = new ArrayList(); - while (className != null) { - className = getSuperclassName(className); - if (className != null) { - ancestors.add(className); + public List getAncestry(ClassEntry classEntry) { + List ancestors = Lists.newArrayList(); + while (classEntry != null) { + classEntry = getSuperclass(classEntry); + if (classEntry != null) { + ancestors.add(classEntry); } } return ancestors; } - public List getSubclassNames(String className) { + public List getSubclass(ClassEntry classEntry) { // linear search is fast enough for now - List subclasses = Lists.newArrayList(); - for (Map.Entry entry : m_superclasses.entrySet()) { - String subclass = entry.getKey(); - String superclass = entry.getValue(); - if (className.equals(superclass)) { + List subclasses = Lists.newArrayList(); + for (Map.Entry entry : m_superclasses.entrySet()) { + ClassEntry subclass = entry.getKey(); + ClassEntry superclass = entry.getValue(); + if (classEntry.equals(superclass)) { subclasses.add(subclass); } } return subclasses; } - public void getSubclassNamesRecursively(Set out, String className) { - for (String subclassName : getSubclassNames(className)) { - out.add(subclassName); - getSubclassNamesRecursively(out, subclassName); + public void getSubclassesRecursively(Set out, ClassEntry classEntry) { + for (ClassEntry subclassEntry : getSubclass(classEntry)) { + out.add(subclassEntry); + getSubclassesRecursively(out, subclassEntry); + } + } + + public void getSubclassNamesRecursively(Set out, ClassEntry classEntry) { + for (ClassEntry subclassEntry : getSubclass(classEntry)) { + out.add(subclassEntry.getName()); + getSubclassNamesRecursively(out, subclassEntry); } } - public boolean containsField(String className, String fieldName) { - return m_fields.containsEntry(className, fieldName); + public boolean entryExists(Entry entry) { + if (entry instanceof FieldEntry) { + return fieldExists((FieldEntry)entry); + } else if (entry instanceof BehaviorEntry) { + return behaviorExists((BehaviorEntry)entry); + } else if (entry instanceof ArgumentEntry) { + return behaviorExists(((ArgumentEntry)entry).getBehaviorEntry()); + } + throw new IllegalArgumentException("Cannot check existence for " + entry.getClass()); + } + + public boolean fieldExists(FieldEntry fieldEntry) { + return m_fieldEntries.containsEntry(fieldEntry.getClassEntry(), fieldEntry); + } + + public boolean behaviorExists(BehaviorEntry behaviorEntry) { + return m_behaviorEntries.containsEntry(behaviorEntry.getClassEntry(), behaviorEntry); + } + + public ClassEntry resolveEntryClass(Entry entry) { + + if (entry instanceof ClassEntry) { + return (ClassEntry)entry; + } + + // this entry could refer to a method on a class where the method is not actually implemented + // travel up the inheritance tree to find the closest implementation + while (!entryExists(entry)) { + + // is there a parent class? + ClassEntry superclassEntry = getSuperclass(entry.getClassEntry()); + if (superclassEntry == null) { + // this is probably a method from a class in a library + // we can't trace the implementation up any higher unless we index the library + return null; + } + + // move up to the parent class + entry = entry.cloneToNewClass(superclassEntry); + } + return entry.getClassEntry(); } - private boolean isJre(String className) { - return className.startsWith("java/") || className.startsWith("javax/"); + private boolean isJre(ClassEntry classEntry) { + return classEntry.getPackageName().startsWith("java") || classEntry.getPackageName().startsWith("javax"); } } diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java index 735a8fa..6441830 100644 --- a/src/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java @@ -38,6 +38,7 @@ public class ClassTranslator { } public void translate(CtClass c) { + // NOTE: the order of these translations is very important // translate all the field and method references in the code by editing the constant pool @@ -45,7 +46,9 @@ public class ClassTranslator { ConstPoolEditor editor = new ConstPoolEditor(constants); for (int i = 1; i < constants.getSize(); i++) { switch (constants.getTag(i)) { + case ConstPool.CONST_Fieldref: { + // translate the name FieldEntry entry = new FieldEntry( new ClassEntry(Descriptor.toJvmName(constants.getFieldrefClassName(i))), @@ -53,6 +56,11 @@ public class ClassTranslator { ); FieldEntry translatedEntry = m_translator.translateEntry(entry); + // TEMP + if (entry.toString().equals("none/bxq.m")) { + System.out.println("FIELD: " + entry + " -> " + translatedEntry); + } + // translate the type String type = constants.getFieldrefType(i); String translatedType = m_translator.translateSignature(type); @@ -65,6 +73,7 @@ public class ClassTranslator { case ConstPool.CONST_Methodref: case ConstPool.CONST_InterfaceMethodref: { + // translate the name and type BehaviorEntry entry = BehaviorEntryFactory.create( Descriptor.toJvmName(editor.getMemberrefClassname(i)), diff --git a/src/cuchaz/enigma/mapping/JavassistUtil.java b/src/cuchaz/enigma/mapping/JavassistUtil.java new file mode 100644 index 0000000..b011e0b --- /dev/null +++ b/src/cuchaz/enigma/mapping/JavassistUtil.java @@ -0,0 +1,55 @@ +package cuchaz.enigma.mapping; + +import javassist.CtBehavior; +import javassist.CtClass; +import javassist.CtConstructor; +import javassist.CtField; +import javassist.CtMethod; +import javassist.bytecode.Descriptor; +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MethodEntry; + +public class JavassistUtil { + + public static ClassEntry getClassEntry(CtClass c) { + return new ClassEntry(Descriptor.toJvmName(c.getName())); + } + + public static ClassEntry getSuperclassEntry(CtClass c) { + return new ClassEntry(Descriptor.toJvmName(c.getClassFile().getSuperclass())); + } + + public static MethodEntry getMethodEntry(CtMethod method) { + return new MethodEntry( + getClassEntry(method.getDeclaringClass()), + method.getName(), + method.getMethodInfo().getDescriptor() + ); + } + + public static ConstructorEntry getConstructorEntry(CtConstructor constructor) { + return new ConstructorEntry( + getClassEntry(constructor.getDeclaringClass()), + constructor.getMethodInfo().getDescriptor() + ); + } + + public static BehaviorEntry getBehaviorEntry(CtBehavior behavior) { + if (behavior instanceof CtMethod) { + return getMethodEntry((CtMethod)behavior); + } else if (behavior instanceof CtConstructor) { + return getConstructorEntry((CtConstructor)behavior); + } + throw new Error("behavior is neither Method nor Constructor!"); + } + + public static FieldEntry getFieldEntry(CtField field) { + return new FieldEntry( + getClassEntry(field.getDeclaringClass()), + field.getName() + ); + } +} diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index c5e38f4..cc560a8 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -24,6 +24,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import cuchaz.enigma.Util; +import cuchaz.enigma.analysis.TranslationIndex; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class Mappings implements Serializable { @@ -104,11 +105,11 @@ public class Mappings implements Serializable { return m_classesByDeobf.get(deobfName); } - public Translator getTranslator(TranslationDirection direction) { + public Translator getTranslator(TranslationDirection direction, TranslationIndex index) { switch (direction) { case Deobfuscating: - return new Translator(direction, m_classesByObf); + return new Translator(direction, m_classesByObf, index); case Obfuscating: @@ -122,7 +123,11 @@ public class Mappings implements Serializable { } } - return new Translator(direction, classes); + // translate the translation index + // NOTE: this isn't actually recursive + TranslationIndex deobfIndex = new TranslationIndex(index, getTranslator(TranslationDirection.Deobfuscating, index)); + + return new Translator(direction, classes, deobfIndex); default: throw new Error("Invalid translation direction!"); diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index cb95f42..3aac65a 100644 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -100,10 +100,10 @@ public class MappingsRenamer { deobfName = NameValidator.validateMethodName(deobfName); for (MethodEntry entry : implementations) { - String deobfSignature = m_mappings.getTranslator(TranslationDirection.Deobfuscating).translateSignature(obf.getSignature()); + String deobfSignature = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateSignature(obf.getSignature()); MethodEntry targetEntry = new MethodEntry(entry.getClassEntry(), deobfName, deobfSignature); if (m_mappings.containsDeobfMethod(entry.getClassEntry(), deobfName, entry.getSignature()) || m_index.containsObfBehavior(targetEntry)) { - String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating).translateClass(entry.getClassName()); + String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateClass(entry.getClassName()); throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); } } @@ -117,7 +117,7 @@ public class MappingsRenamer { deobfName = NameValidator.validateMethodName(deobfName); MethodEntry targetEntry = new MethodEntry(obf.getClassEntry(), deobfName, obf.getSignature()); if (m_mappings.containsDeobfMethod(obf.getClassEntry(), deobfName, obf.getSignature()) || m_index.containsObfBehavior(targetEntry)) { - String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating).translateClass(obf.getClassName()); + String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateClass(obf.getClassName()); throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); } diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index d8d9f48..a5a3e2f 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -14,21 +14,24 @@ import java.util.Map; import com.google.common.collect.Maps; +import cuchaz.enigma.analysis.TranslationIndex; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class Translator { private TranslationDirection m_direction; private Map m_classes; + private TranslationIndex m_index; public Translator() { m_direction = null; m_classes = Maps.newHashMap(); } - public Translator(TranslationDirection direction, Map classes) { + public Translator(TranslationDirection direction, Map classes, TranslationIndex index) { m_direction = direction; m_classes = classes; + m_index = index; } @SuppressWarnings("unchecked") @@ -100,17 +103,22 @@ public class Translator { public String translate(FieldEntry in) { - // look for the class - ClassMapping classMapping = findClassMapping(in.getClassEntry()); - if (classMapping != null) { - - // look for the field - String translatedName = m_direction.choose( - classMapping.getDeobfFieldName(in.getName()), - classMapping.getObfFieldName(in.getName()) - ); - if (translatedName != null) { - return translatedName; + // resolve the class entry + ClassEntry resolvedClassEntry = m_index.resolveEntryClass(in); + if (resolvedClassEntry != null) { + + // look for the class + ClassMapping classMapping = findClassMapping(resolvedClassEntry); + if (classMapping != null) { + + // look for the field + String translatedName = m_direction.choose( + classMapping.getDeobfFieldName(in.getName()), + classMapping.getObfFieldName(in.getName()) + ); + if (translatedName != null) { + return translatedName; + } } } return null; @@ -126,15 +134,22 @@ public class Translator { public String translate(MethodEntry in) { - // look for class - ClassMapping classMapping = findClassMapping(in.getClassEntry()); - if (classMapping != null) { - - // look for the method - MethodMapping methodMapping = m_direction.choose(classMapping.getMethodByObf(in.getName(), in.getSignature()), - classMapping.getMethodByDeobf(in.getName(), translateSignature(in.getSignature()))); - if (methodMapping != null) { - return m_direction.choose(methodMapping.getDeobfName(), methodMapping.getObfName()); + // resolve the class entry + ClassEntry resolvedClassEntry = m_index.resolveEntryClass(in); + if (resolvedClassEntry != null) { + + // look for class + ClassMapping classMapping = findClassMapping(resolvedClassEntry); + if (classMapping != null) { + + // look for the method + MethodMapping methodMapping = m_direction.choose( + classMapping.getMethodByObf(in.getName(), in.getSignature()), + classMapping.getMethodByDeobf(in.getName(), translateSignature(in.getSignature())) + ); + if (methodMapping != null) { + return m_direction.choose(methodMapping.getDeobfName(), methodMapping.getObfName()); + } } } return null; -- cgit v1.2.3