From af1041731c8c0ce1846ff7e7b6052ed7327a5dbc Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 9 Feb 2015 22:23:45 -0500 Subject: fix translation issues, particularly with fields --- src/cuchaz/enigma/analysis/JarIndex.java | 57 ++++++------- .../analysis/MethodImplementationsTreeNode.java | 1 + .../enigma/analysis/RelatedMethodChecker.java | 96 ++++++++++++++++++++++ .../enigma/analysis/SourceIndexClassVisitor.java | 11 ++- src/cuchaz/enigma/analysis/TranslationIndex.java | 10 +-- 5 files changed, 134 insertions(+), 41 deletions(-) create mode 100644 src/cuchaz/enigma/analysis/RelatedMethodChecker.java (limited to 'src/cuchaz/enigma/analysis') diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index f54beda..24d110e 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -42,12 +42,11 @@ import cuchaz.enigma.Constants; import cuchaz.enigma.bytecode.ClassRenamer; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.BehaviorEntryFactory; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.EntryFactory; import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.JavassistUtil; import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.Translator; @@ -92,10 +91,10 @@ public class JarIndex { for (CtClass c : JarClassIterator.classes(jar)) { ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); for (CtField field : c.getDeclaredFields()) { - m_access.put(JavassistUtil.getFieldEntry(field), Access.get(field)); + m_access.put(EntryFactory.getFieldEntry(field), Access.get(field)); } for (CtBehavior behavior : c.getDeclaredBehaviors()) { - m_access.put(JavassistUtil.getBehaviorEntry(behavior), Access.get(behavior)); + m_access.put(EntryFactory.getBehaviorEntry(behavior), Access.get(behavior)); } } @@ -166,7 +165,7 @@ public class JarIndex { private void indexBehavior(CtBehavior behavior) { // get the behavior entry - final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior); + final BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); if (behaviorEntry instanceof MethodEntry) { MethodEntry methodEntry = (MethodEntry)behaviorEntry; @@ -178,12 +177,12 @@ public class JarIndex { private void indexBehaviorReferences(CtBehavior behavior) { // index method calls - final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior); + final BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); try { behavior.instrument(new ExprEditor() { @Override public void edit(MethodCall call) { - MethodEntry calledMethodEntry = JavassistUtil.getMethodEntry(call); + MethodEntry calledMethodEntry = EntryFactory.getMethodEntry(call); ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledMethodEntry); if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledMethodEntry.getClassEntry())) { calledMethodEntry = new MethodEntry( @@ -202,7 +201,7 @@ public class JarIndex { @Override public void edit(FieldAccess call) { - FieldEntry calledFieldEntry = JavassistUtil.getFieldEntry(call); + FieldEntry calledFieldEntry = EntryFactory.getFieldEntry(call); ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledFieldEntry); if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledFieldEntry.getClassEntry())) { calledFieldEntry = new FieldEntry(calledFieldEntry, resolvedClassEntry); @@ -217,7 +216,7 @@ public class JarIndex { @Override public void edit(ConstructorCall call) { - ConstructorEntry calledConstructorEntry = JavassistUtil.getConstructorEntry(call); + ConstructorEntry calledConstructorEntry = EntryFactory.getConstructorEntry(call); EntryReference reference = new EntryReference( calledConstructorEntry, call.getMethodName(), @@ -228,7 +227,7 @@ public class JarIndex { @Override public void edit(NewExpr call) { - ConstructorEntry calledConstructorEntry = JavassistUtil.getConstructorEntry(call); + ConstructorEntry calledConstructorEntry = EntryFactory.getConstructorEntry(call); EntryReference reference = new EntryReference( calledConstructorEntry, call.getClassName(), @@ -256,7 +255,7 @@ public class JarIndex { } ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); - ConstructorEntry constructorEntry = JavassistUtil.getConstructorEntry(constructor); + ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(constructor); // gather the classes from the illegally-set synthetic fields Set illegallySetClasses = Sets.newHashSet(); @@ -422,7 +421,7 @@ public class JarIndex { CtConstructor constructor = c.getDeclaredConstructors()[0]; // is this constructor called exactly once? - ConstructorEntry constructorEntry = JavassistUtil.getConstructorEntry(constructor); + ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(constructor); Collection> references = getBehaviorReferences(constructorEntry); if (references.size() != 1) { return null; @@ -520,17 +519,17 @@ public class JarIndex { return rootNode; } - public MethodImplementationsTreeNode getMethodImplementations(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { + public List getMethodImplementations(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { - MethodEntry interfaceMethodEntry; + List interfaceMethodEntries = Lists.newArrayList(); // is this method on an interface? if (isInterface(obfMethodEntry.getClassName())) { - interfaceMethodEntry = obfMethodEntry; + interfaceMethodEntries.add(obfMethodEntry); } else { // get the interface class - List methodInterfaces = Lists.newArrayList(); for (String interfaceName : getInterfaces(obfMethodEntry.getClassName())) { + // is this method defined in this interface? MethodEntry methodInterface = new MethodEntry( new ClassEntry(interfaceName), @@ -538,21 +537,20 @@ public class JarIndex { obfMethodEntry.getSignature() ); if (containsObfBehavior(methodInterface)) { - methodInterfaces.add(methodInterface); + interfaceMethodEntries.add(methodInterface); } } - if (methodInterfaces.isEmpty()) { - return null; - } - if (methodInterfaces.size() > 1) { - throw new Error("Too many interfaces define this method! This is not yet supported by Enigma!"); - } - interfaceMethodEntry = methodInterfaces.get(0); } - MethodImplementationsTreeNode rootNode = new MethodImplementationsTreeNode(deobfuscatingTranslator, interfaceMethodEntry); - rootNode.load(this); - return rootNode; + List nodes = Lists.newArrayList(); + if (!interfaceMethodEntries.isEmpty()) { + for (MethodEntry interfaceMethodEntry : interfaceMethodEntries) { + MethodImplementationsTreeNode node = new MethodImplementationsTreeNode(deobfuscatingTranslator, interfaceMethodEntry); + node.load(this); + nodes.add(node); + } + } + return nodes; } public Set getRelatedMethodImplementations(MethodEntry obfMethodEntry) { @@ -569,9 +567,8 @@ public class JarIndex { } // look at interface methods too - MethodImplementationsTreeNode implementations = getMethodImplementations(null, methodEntry); - if (implementations != null) { - getRelatedMethodImplementations(methodEntries, implementations); + for (MethodImplementationsTreeNode implementationsNode : getMethodImplementations(null, methodEntry)) { + getRelatedMethodImplementations(methodEntries, implementationsNode); } // recurse diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java index 1009226..6cafc55 100644 --- a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java @@ -63,6 +63,7 @@ public class MethodImplementationsTreeNode extends DefaultMutableTreeNode { } public void load(JarIndex index) { + // get all method implementations List nodes = Lists.newArrayList(); for (String implementingClassName : index.getImplementingClasses(m_entry.getClassName())) { diff --git a/src/cuchaz/enigma/analysis/RelatedMethodChecker.java b/src/cuchaz/enigma/analysis/RelatedMethodChecker.java new file mode 100644 index 0000000..5bd67a0 --- /dev/null +++ b/src/cuchaz/enigma/analysis/RelatedMethodChecker.java @@ -0,0 +1,96 @@ +package cuchaz.enigma.analysis; + +import java.util.Map; +import java.util.Set; + +import com.beust.jcommander.internal.Maps; +import com.google.common.collect.Sets; + +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.EntryFactory; +import cuchaz.enigma.mapping.MethodEntry; +import cuchaz.enigma.mapping.MethodMapping; + +public class RelatedMethodChecker { + + private JarIndex m_jarIndex; + private Map,String> m_deobfNamesByGroup; + private Map m_deobfNamesByObfMethod; + private Map> m_groupsByObfMethod; + private Set> m_inconsistentGroups; + + public RelatedMethodChecker(JarIndex jarIndex) { + m_jarIndex = jarIndex; + m_deobfNamesByGroup = Maps.newHashMap(); + m_deobfNamesByObfMethod = Maps.newHashMap(); + m_groupsByObfMethod = Maps.newHashMap(); + m_inconsistentGroups = Sets.newHashSet(); + } + + public void checkMethod(ClassEntry classEntry, MethodMapping methodMapping) { + + // TEMP: disable the expensive check for now, maybe we can optimize it later, or just use it for debugging + if (true) return; + + BehaviorEntry obfBehaviorEntry = EntryFactory.getObfBehaviorEntry(classEntry, methodMapping); + if (!(obfBehaviorEntry instanceof MethodEntry)) { + // only methods have related implementations + return; + } + MethodEntry obfMethodEntry = (MethodEntry)obfBehaviorEntry; + String deobfName = methodMapping.getDeobfName(); + m_deobfNamesByObfMethod.put(obfMethodEntry, deobfName); + + // have we seen this method's group before? + Set group = m_groupsByObfMethod.get(obfMethodEntry); + if (group == null) { + + // no, compute the group and save the name + group = m_jarIndex.getRelatedMethodImplementations(obfMethodEntry); + m_deobfNamesByGroup.put(group, deobfName); + + assert(group.contains(obfMethodEntry)); + for (MethodEntry relatedMethodEntry : group) { + m_groupsByObfMethod.put(relatedMethodEntry, group); + } + } + + // check the name + if (!sameName(m_deobfNamesByGroup.get(group), deobfName)) { + m_inconsistentGroups.add(group); + } + } + + private boolean sameName(String a, String b) { + if (a == null && b == null) { + return true; + } else if (a != null && b != null) { + return a.equals(b); + } + return false; + } + + public boolean hasProblems() { + return m_inconsistentGroups.size() > 0; + } + + public String getReport() { + StringBuilder buf = new StringBuilder(); + buf.append(m_inconsistentGroups.size()); + buf.append(" groups of methods related by inheritance and/or interfaces have different deobf names!\n"); + for (Set group : m_inconsistentGroups) { + buf.append("\tGroup with "); + buf.append(group.size()); + buf.append(" methods:\n"); + for (MethodEntry methodEntry : group) { + buf.append("\t\t"); + buf.append(methodEntry.toString()); + buf.append(" => "); + buf.append(m_deobfNamesByObfMethod.get(methodEntry)); + buf.append("\n"); + } + } + return buf.toString(); + } +} diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java index e2ff300..d6692f6 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java @@ -26,11 +26,10 @@ import com.strobel.decompiler.languages.java.ast.TypeDeclaration; import com.strobel.decompiler.languages.java.ast.VariableInitializer; import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.BehaviorEntryFactory; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; +import cuchaz.enigma.mapping.EntryFactory; import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.Signature; import cuchaz.enigma.mapping.Type; public class SourceIndexClassVisitor extends SourceIndexVisitor { @@ -69,12 +68,13 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor { @Override public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); - ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName()); - BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(classEntry, def.getName(), def.getSignature()); + BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(def); AstNode tokenNode = node.getNameToken(); + if (behaviorEntry instanceof ConstructorEntry) { ConstructorEntry constructorEntry = (ConstructorEntry)behaviorEntry; if (constructorEntry.isStatic()) { + // for static initializers, check elsewhere for the token node tokenNode = node.getModifiers().firstOrNullObject(); } } @@ -85,8 +85,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor { @Override public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); - ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName()); - ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, new Signature(def.getSignature())); + ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(def); index.addDeclaration(node.getNameToken(), constructorEntry); return node.acceptVisitor(new SourceIndexBehaviorVisitor(constructorEntry), index); } diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java index 7597c3a..8651ebd 100644 --- a/src/cuchaz/enigma/analysis/TranslationIndex.java +++ b/src/cuchaz/enigma/analysis/TranslationIndex.java @@ -37,7 +37,7 @@ 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.EntryFactory; import cuchaz.enigma.mapping.Translator; public class TranslationIndex implements Serializable { @@ -85,23 +85,23 @@ public class TranslationIndex implements Serializable { public void indexClass(CtClass c) { - ClassEntry classEntry = JavassistUtil.getClassEntry(c); + ClassEntry classEntry = EntryFactory.getClassEntry(c); // add the superclass - ClassEntry superclassEntry = JavassistUtil.getSuperclassEntry(c); + ClassEntry superclassEntry = EntryFactory.getSuperclassEntry(c); if (!isJre(classEntry) && superclassEntry != null && !isJre(superclassEntry)) { m_superclasses.put(classEntry, superclassEntry); } // add fields for (CtField field : c.getDeclaredFields()) { - FieldEntry fieldEntry = JavassistUtil.getFieldEntry(field); + FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); m_fieldEntries.put(fieldEntry.getClassEntry(), fieldEntry); } // add behaviors for (CtBehavior behavior : c.getDeclaredBehaviors()) { - BehaviorEntry behaviorEntry = JavassistUtil.getBehaviorEntry(behavior); + BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); m_behaviorEntries.put(behaviorEntry.getClassEntry(), behaviorEntry); } } -- cgit v1.2.3