From 2dc7428e37bdd7a119f53d02ce157675509b0d63 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 23 Feb 2015 23:29:22 -0500 Subject: lots of work in better handling of inner classes also working on recognizing unobfuscated and deobfuscated jars (needed for M3L) --- src/cuchaz/enigma/mapping/ClassMapping.java | 41 ++++--- src/cuchaz/enigma/mapping/EntryFactory.java | 35 +++--- src/cuchaz/enigma/mapping/Mappings.java | 14 +-- src/cuchaz/enigma/mapping/MappingsRenamer.java | 2 +- src/cuchaz/enigma/mapping/MappingsWriter.java | 4 +- src/cuchaz/enigma/mapping/Translator.java | 154 ++++++++++++++++++------- 6 files changed, 164 insertions(+), 86 deletions(-) (limited to 'src/cuchaz/enigma/mapping') diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index 885400b..3610e33 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -20,7 +20,8 @@ public class ClassMapping implements Serializable, Comparable { private static final long serialVersionUID = -5148491146902340107L; - private String m_obfName; + private String m_obfFullName; + private String m_obfSimpleName; private String m_deobfName; private Map m_innerClassesByObf; private Map m_innerClassesByDeobf; @@ -34,7 +35,8 @@ public class ClassMapping implements Serializable, Comparable { } public ClassMapping(String obfName, String deobfName) { - m_obfName = obfName; + m_obfFullName = obfName; + m_obfSimpleName = new ClassEntry(obfName).getSimpleName(); m_deobfName = NameValidator.validateClassName(deobfName, false); m_innerClassesByObf = Maps.newHashMap(); m_innerClassesByDeobf = Maps.newHashMap(); @@ -44,8 +46,12 @@ public class ClassMapping implements Serializable, Comparable { m_methodsByDeobf = Maps.newHashMap(); } - public String getObfName() { - return m_obfName; + public String getObfFullName() { + return m_obfFullName; + } + + public String getObfSimpleName() { + return m_obfSimpleName; } public String getDeobfName() { @@ -64,8 +70,7 @@ public class ClassMapping implements Serializable, Comparable { } public void addInnerClassMapping(ClassMapping classMapping) { - assert (isSimpleClassName(classMapping.getObfName())); - boolean obfWasAdded = m_innerClassesByObf.put(classMapping.getObfName(), classMapping) == null; + boolean obfWasAdded = m_innerClassesByObf.put(classMapping.getObfSimpleName(), classMapping) == null; assert (obfWasAdded); if (classMapping.getDeobfName() != null) { assert (isSimpleClassName(classMapping.getDeobfName())); @@ -75,7 +80,7 @@ public class ClassMapping implements Serializable, Comparable { } public void removeInnerClassMapping(ClassMapping classMapping) { - boolean obfWasRemoved = m_innerClassesByObf.remove(classMapping.getObfName()) != null; + boolean obfWasRemoved = m_innerClassesByObf.remove(classMapping.getObfSimpleName()) != null; assert (obfWasRemoved); if (classMapping.getDeobfName() != null) { boolean deobfWasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; @@ -112,11 +117,11 @@ public class ClassMapping implements Serializable, Comparable { return classMapping; } - public String getObfInnerClassName(String deobfName) { + public String getObfInnerClassSimpleName(String deobfName) { assert (isSimpleClassName(deobfName)); ClassMapping classMapping = m_innerClassesByDeobf.get(deobfName); if (classMapping != null) { - return classMapping.getObfName(); + return classMapping.getObfSimpleName(); } return null; } @@ -163,7 +168,7 @@ public class ClassMapping implements Serializable, Comparable { public void addFieldMapping(FieldMapping fieldMapping) { String obfKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType()); if (m_fieldsByObf.containsKey(obfKey)) { - throw new Error("Already have mapping for " + m_obfName + "." + obfKey); + throw new Error("Already have mapping for " + m_obfFullName + "." + obfKey); } String deobfKey = getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType()); if (m_fieldsByDeobf.containsKey(deobfKey)) { @@ -257,7 +262,7 @@ public class ClassMapping implements Serializable, Comparable { public void addMethodMapping(MethodMapping methodMapping) { String obfKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()); if (m_methodsByObf.containsKey(obfKey)) { - throw new Error("Already have mapping for " + m_obfName + "." + obfKey); + throw new Error("Already have mapping for " + m_obfFullName + "." + obfKey); } boolean wasAdded = m_methodsByObf.put(obfKey, methodMapping) == null; assert (wasAdded); @@ -339,7 +344,7 @@ public class ClassMapping implements Serializable, Comparable { @Override public String toString() { StringBuilder buf = new StringBuilder(); - buf.append(m_obfName); + buf.append(m_obfFullName); buf.append(" <-> "); buf.append(m_deobfName); buf.append("\n"); @@ -359,7 +364,7 @@ public class ClassMapping implements Serializable, Comparable { buf.append("Inner Classes:\n"); for (ClassMapping classMapping : m_innerClassesByObf.values()) { buf.append("\t"); - buf.append(classMapping.getObfName()); + buf.append(classMapping.getObfSimpleName()); buf.append(" <-> "); buf.append(classMapping.getDeobfName()); buf.append("\n"); @@ -370,10 +375,10 @@ public class ClassMapping implements Serializable, Comparable { @Override public int compareTo(ClassMapping other) { // sort by a, b, c, ... aa, ab, etc - if (m_obfName.length() != other.m_obfName.length()) { - return m_obfName.length() - other.m_obfName.length(); + if (m_obfFullName.length() != other.m_obfFullName.length()) { + return m_obfFullName.length() - other.m_obfFullName.length(); } - return m_obfName.compareTo(other.m_obfName); + return m_obfFullName.compareTo(other.m_obfFullName); } public boolean renameObfClass(String oldObfClassName, String newObfClassName) { @@ -399,9 +404,9 @@ public class ClassMapping implements Serializable, Comparable { } } - if (m_obfName.equals(oldObfClassName)) { + if (m_obfFullName.equals(oldObfClassName)) { // rename this class - m_obfName = newObfClassName; + m_obfFullName = newObfClassName; return true; } return false; diff --git a/src/cuchaz/enigma/mapping/EntryFactory.java b/src/cuchaz/enigma/mapping/EntryFactory.java index dceea29..bbdfa73 100644 --- a/src/cuchaz/enigma/mapping/EntryFactory.java +++ b/src/cuchaz/enigma/mapping/EntryFactory.java @@ -25,25 +25,19 @@ public class EntryFactory { } public static ClassEntry getObfClassEntry(JarIndex jarIndex, ClassMapping classMapping) { - return new ClassEntry(getChainedOuterClassName(jarIndex, classMapping.getObfName())); + return getChainedOuterClassName(jarIndex, new ClassEntry(classMapping.getObfFullName())); } - private static String getChainedOuterClassName(JarIndex jarIndex, String obfClassName) { + public static ClassEntry getChainedOuterClassName(JarIndex jarIndex, ClassEntry obfClassEntry) { // lookup the chain of outer classes - List obfOuterClassNames = Lists.newArrayList(); - String checkName = obfClassName; + List obfClassChain = Lists.newArrayList(obfClassEntry); + ClassEntry checkClassEntry = obfClassEntry; while (true) { - - // if this class name has a package, then it can't be an inner class - if (!new ClassEntry(checkName).isInDefaultPackage()) { - break; - } - - String obfOuterClassName = jarIndex.getOuterClass(checkName); - if (obfOuterClassName != null) { - obfOuterClassNames.add(obfOuterClassName); - checkName = obfOuterClassName; + ClassEntry obfOuterClassEntry = jarIndex.getOuterClass(checkClassEntry); + if (obfOuterClassEntry != null) { + obfClassChain.add(obfOuterClassEntry); + checkClassEntry = obfOuterClassEntry; } else { break; } @@ -51,12 +45,15 @@ public class EntryFactory { // build the chained class name StringBuilder buf = new StringBuilder(); - for (int i=obfOuterClassNames.size()-1; i>=0; i--) { - buf.append(obfOuterClassNames.get(i)); - buf.append("$"); + for (int i=obfClassChain.size()-1; i>=0; i--) { + if (buf.length() == 0) { + buf.append(obfClassChain.get(i).getName()); + } else { + buf.append("$"); + buf.append(obfClassChain.get(i).getSimpleName()); + } } - buf.append(obfClassName); - return buf.toString(); + return new ClassEntry(buf.toString()); } public static ClassEntry getDeobfClassEntry(ClassMapping classMapping) { diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index 675fdf1..a85bcbf 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -37,7 +37,7 @@ public class Mappings implements Serializable { this(); for (ClassMapping classMapping : classes) { - m_classesByObf.put(classMapping.getObfName(), classMapping); + m_classesByObf.put(classMapping.getObfFullName(), classMapping); if (classMapping.getDeobfName() != null) { m_classesByDeobf.put(classMapping.getDeobfName(), classMapping); } @@ -50,10 +50,10 @@ public class Mappings implements Serializable { } public void addClassMapping(ClassMapping classMapping) { - if (m_classesByObf.containsKey(classMapping.getObfName())) { - throw new Error("Already have mapping for " + classMapping.getObfName()); + if (m_classesByObf.containsKey(classMapping.getObfFullName())) { + throw new Error("Already have mapping for " + classMapping.getObfFullName()); } - boolean obfWasAdded = m_classesByObf.put(classMapping.getObfName(), classMapping) == null; + boolean obfWasAdded = m_classesByObf.put(classMapping.getObfFullName(), classMapping) == null; assert (obfWasAdded); if (classMapping.getDeobfName() != null) { if (m_classesByDeobf.containsKey(classMapping.getDeobfName())) { @@ -65,7 +65,7 @@ public class Mappings implements Serializable { } public void removeClassMapping(ClassMapping classMapping) { - boolean obfWasRemoved = m_classesByObf.remove(classMapping.getObfName()) != null; + boolean obfWasRemoved = m_classesByObf.remove(classMapping.getObfFullName()) != null; assert (obfWasRemoved); if (classMapping.getDeobfName() != null) { boolean deobfWasRemoved = m_classesByDeobf.remove(classMapping.getDeobfName()) != null; @@ -103,7 +103,7 @@ public class Mappings implements Serializable { if (classMapping.getDeobfName() != null) { classes.put(classMapping.getDeobfName(), classMapping); } else { - classes.put(classMapping.getObfName(), classMapping); + classes.put(classMapping.getObfFullName(), classMapping); } } @@ -144,7 +144,7 @@ public class Mappings implements Serializable { for (ClassMapping classMapping : classes()) { // add the class name - classNames.add(classMapping.getObfName()); + classNames.add(classMapping.getObfFullName()); // add classes from method signatures for (MethodMapping methodMapping : classMapping.methods()) { diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index ea343c4..16f700d 100644 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -213,7 +213,7 @@ public class MappingsRenamer { ClassMapping classMapping = m_mappings.m_classesByObf.get(obfClassName); if (classMapping == null) { classMapping = new ClassMapping(obfClassName); - boolean obfWasAdded = m_mappings.m_classesByObf.put(classMapping.getObfName(), classMapping) == null; + boolean obfWasAdded = m_mappings.m_classesByObf.put(classMapping.getObfFullName(), classMapping) == null; assert (obfWasAdded); } return classMapping; diff --git a/src/cuchaz/enigma/mapping/MappingsWriter.java b/src/cuchaz/enigma/mapping/MappingsWriter.java index c7c2cc0..8b62db8 100644 --- a/src/cuchaz/enigma/mapping/MappingsWriter.java +++ b/src/cuchaz/enigma/mapping/MappingsWriter.java @@ -31,9 +31,9 @@ public class MappingsWriter { private void write(PrintWriter out, ClassMapping classMapping, int depth) throws IOException { if (classMapping.getDeobfName() == null) { - out.format("%sCLASS %s\n", getIndent(depth), classMapping.getObfName()); + out.format("%sCLASS %s\n", getIndent(depth), classMapping.getObfFullName()); } else { - out.format("%sCLASS %s %s\n", getIndent(depth), classMapping.getObfName(), classMapping.getDeobfName()); + out.format("%sCLASS %s %s\n", getIndent(depth), classMapping.getObfFullName(), classMapping.getDeobfName()); } for (ClassMapping innerClassMapping : sorted(classMapping.innerClasses())) { diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index 759dddf..d985032 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -10,8 +10,10 @@ ******************************************************************************/ package cuchaz.enigma.mapping; +import java.util.List; import java.util.Map; +import com.beust.jcommander.internal.Lists; import com.google.common.collect.Maps; import cuchaz.enigma.analysis.TranslationIndex; @@ -50,54 +52,106 @@ public class Translator { } } + public String translate(T entry) { + if (entry instanceof ClassEntry) { + return translate((ClassEntry)entry); + } else if (entry instanceof FieldEntry) { + return translate((FieldEntry)entry); + } else if (entry instanceof MethodEntry) { + return translate((MethodEntry)entry); + } else if (entry instanceof ConstructorEntry) { + return translate((ConstructorEntry)entry); + } else if (entry instanceof ArgumentEntry) { + return translate((ArgumentEntry)entry); + } else { + throw new Error("Unknown entry type: " + entry.getClass().getName()); + } + } + public String translateClass(String className) { return translate(new ClassEntry(className)); } public String translate(ClassEntry in) { - ClassMapping classMapping = m_classes.get(in.getOuterClassName()); - if (classMapping != null) { - if (in.isInnerClass()) { - // translate the inner class - String translatedInnerClassName = m_direction.choose( - classMapping.getDeobfInnerClassName(in.getInnerClassName()), - classMapping.getObfInnerClassName(in.getInnerClassName()) + + if (in.isInnerClass()) { + + // translate everything in the class chain, or return null + List mappingsChain = getClassMappingChain(in); + StringBuilder buf = new StringBuilder(); + for (ClassMapping classMapping : mappingsChain) { + if (classMapping == null) { + return null; + } + boolean isFirstClass = buf.length() == 0; + String name = m_direction.choose( + classMapping.getDeobfName(), + isFirstClass ? classMapping.getObfFullName() : classMapping.getObfSimpleName() ); - if (translatedInnerClassName != null) { - // try to translate the outer name - String translatedOuterClassName = m_direction.choose(classMapping.getDeobfName(), classMapping.getObfName()); - if (translatedOuterClassName != null) { - return translatedOuterClassName + "$" + translatedInnerClassName; - } else { - return in.getOuterClassName() + "$" + translatedInnerClassName; - } + if (name == null) { + return null; + } + if (!isFirstClass) { + buf.append("$"); } - } else { - // just return outer - return m_direction.choose(classMapping.getDeobfName(), classMapping.getObfName()); + buf.append(name); } + return buf.toString(); + + } else { + + // normal classes are easier + ClassMapping classMapping = m_classes.get(in.getName()); + if (classMapping == null) { + return null; + } + return m_direction.choose( + classMapping.getDeobfName(), + classMapping.getObfFullName() + ); } - return null; } public ClassEntry translateEntry(ClassEntry in) { - // can we translate the inner class? - String name = translate(in); - if (name != null) { - return new ClassEntry(name); - } - if (in.isInnerClass()) { - // guess not. just translate the outer class name then - String outerClassName = translate(in.getOuterClassEntry()); - if (outerClassName != null) { - return new ClassEntry(outerClassName + "$" + in.getInnerClassName()); + // translate as much of the class chain as we can + List mappingsChain = getClassMappingChain(in); + String[] obfClassNames = in.getName().split("\\$"); + StringBuilder buf = new StringBuilder(); + for (int i=0; i mappingChain = getClassMappingChain(in); + return mappingChain.get(mappingChain.size() - 1); + } + + private List getClassMappingChain(ClassEntry in) { + + // get a list of all the classes in the hierarchy + String[] parts = in.getName().split("\\$"); + List mappingsChain = Lists.newArrayList(); + + // get mappings for the outer class + ClassMapping outerClassMapping = m_classes.get(parts[0]); + mappingsChain.add(outerClassMapping); + + for (int i=1; i