diff options
| author | 2015-02-23 23:29:22 -0500 | |
|---|---|---|
| committer | 2015-02-23 23:29:22 -0500 | |
| commit | 2dc7428e37bdd7a119f53d02ce157675509b0d63 (patch) | |
| tree | 68f409ac726166e427eea3a199eb462130c53ccd /src/cuchaz/enigma/analysis/JarIndex.java | |
| parent | make types serializable (diff) | |
| download | enigma-fork-2dc7428e37bdd7a119f53d02ce157675509b0d63.tar.gz enigma-fork-2dc7428e37bdd7a119f53d02ce157675509b0d63.tar.xz enigma-fork-2dc7428e37bdd7a119f53d02ce157675509b0d63.zip | |
lots of work in better handling of inner classes
also working on recognizing unobfuscated and deobfuscated jars
(needed for M3L)
Diffstat (limited to 'src/cuchaz/enigma/analysis/JarIndex.java')
| -rw-r--r-- | src/cuchaz/enigma/analysis/JarIndex.java | 67 |
1 files changed, 35 insertions, 32 deletions
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 1c74f15..6e7c69d 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java | |||
| @@ -61,9 +61,9 @@ public class JarIndex { | |||
| 61 | private Multimap<String,MethodEntry> m_methodImplementations; | 61 | private Multimap<String,MethodEntry> m_methodImplementations; |
| 62 | private Multimap<BehaviorEntry,EntryReference<BehaviorEntry,BehaviorEntry>> m_behaviorReferences; | 62 | private Multimap<BehaviorEntry,EntryReference<BehaviorEntry,BehaviorEntry>> m_behaviorReferences; |
| 63 | private Multimap<FieldEntry,EntryReference<FieldEntry,BehaviorEntry>> m_fieldReferences; | 63 | private Multimap<FieldEntry,EntryReference<FieldEntry,BehaviorEntry>> m_fieldReferences; |
| 64 | private Multimap<String,String> m_innerClasses; | 64 | private Multimap<ClassEntry,ClassEntry> m_innerClassesByOuter; |
| 65 | private Map<String,String> m_outerClasses; | 65 | private Map<ClassEntry,ClassEntry> m_outerClassesByInner; |
| 66 | private Map<String,BehaviorEntry> m_anonymousClasses; | 66 | private Map<ClassEntry,BehaviorEntry> m_anonymousClasses; |
| 67 | private Map<MethodEntry,MethodEntry> m_bridgedMethods; | 67 | private Map<MethodEntry,MethodEntry> m_bridgedMethods; |
| 68 | 68 | ||
| 69 | public JarIndex() { | 69 | public JarIndex() { |
| @@ -74,8 +74,8 @@ public class JarIndex { | |||
| 74 | m_methodImplementations = HashMultimap.create(); | 74 | m_methodImplementations = HashMultimap.create(); |
| 75 | m_behaviorReferences = HashMultimap.create(); | 75 | m_behaviorReferences = HashMultimap.create(); |
| 76 | m_fieldReferences = HashMultimap.create(); | 76 | m_fieldReferences = HashMultimap.create(); |
| 77 | m_innerClasses = HashMultimap.create(); | 77 | m_innerClassesByOuter = HashMultimap.create(); |
| 78 | m_outerClasses = Maps.newHashMap(); | 78 | m_outerClassesByInner = Maps.newHashMap(); |
| 79 | m_anonymousClasses = Maps.newHashMap(); | 79 | m_anonymousClasses = Maps.newHashMap(); |
| 80 | m_bridgedMethods = Maps.newHashMap(); | 80 | m_bridgedMethods = Maps.newHashMap(); |
| 81 | } | 81 | } |
| @@ -129,33 +129,40 @@ public class JarIndex { | |||
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | if (buildInnerClasses) { | 131 | if (buildInnerClasses) { |
| 132 | |||
| 132 | // step 5: index inner classes and anonymous classes | 133 | // step 5: index inner classes and anonymous classes |
| 133 | for (CtClass c : JarClassIterator.classes(jar)) { | 134 | for (CtClass c : JarClassIterator.classes(jar)) { |
| 134 | ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); | 135 | ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); |
| 135 | String outerClassName = findOuterClass(c); | 136 | ClassEntry innerClassEntry = EntryFactory.getClassEntry(c); |
| 136 | if (outerClassName != null) { | 137 | ClassEntry outerClassEntry = findOuterClass(c); |
| 137 | String innerClassName = c.getSimpleName(); | 138 | if (outerClassEntry != null) { |
| 138 | m_innerClasses.put(outerClassName, innerClassName); | 139 | m_innerClassesByOuter.put(outerClassEntry, innerClassEntry); |
| 139 | boolean innerWasAdded = m_outerClasses.put(innerClassName, outerClassName) == null; | 140 | boolean innerWasAdded = m_outerClassesByInner.put(innerClassEntry, outerClassEntry) == null; |
| 140 | assert (innerWasAdded); | 141 | assert (innerWasAdded); |
| 141 | 142 | ||
| 142 | BehaviorEntry enclosingBehavior = isAnonymousClass(c, outerClassName); | 143 | BehaviorEntry enclosingBehavior = isAnonymousClass(c, outerClassEntry); |
| 143 | if (enclosingBehavior != null) { | 144 | if (enclosingBehavior != null) { |
| 144 | m_anonymousClasses.put(innerClassName, enclosingBehavior); | 145 | m_anonymousClasses.put(innerClassEntry, enclosingBehavior); |
| 145 | 146 | ||
| 146 | // DEBUG | 147 | // DEBUG |
| 147 | // System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); | 148 | //System.out.println("ANONYMOUS: " + outerClassEntry.getName() + "$" + innerClassEntry.getSimpleName()); |
| 148 | } else { | 149 | } else { |
| 149 | // DEBUG | 150 | // DEBUG |
| 150 | // System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); | 151 | //System.out.println("INNER: " + outerClassEntry.getName() + "$" + innerClassEntry.getSimpleName()); |
| 151 | } | 152 | } |
| 152 | } | 153 | } |
| 153 | } | 154 | } |
| 154 | 155 | ||
| 155 | // step 6: update other indices with inner class info | 156 | // step 6: update other indices with inner class info |
| 156 | Map<String,String> renames = Maps.newHashMap(); | 157 | Map<String,String> renames = Maps.newHashMap(); |
| 157 | for (Map.Entry<String,String> entry : m_outerClasses.entrySet()) { | 158 | for (Map.Entry<ClassEntry,ClassEntry> mapEntry : m_innerClassesByOuter.entries()) { |
| 158 | renames.put(Constants.NonePackage + "/" + entry.getKey(), entry.getValue() + "$" + entry.getKey()); | 159 | ClassEntry outerClassEntry = mapEntry.getKey(); |
| 160 | ClassEntry innerClassEntry = mapEntry.getValue(); | ||
| 161 | outerClassEntry = EntryFactory.getChainedOuterClassName(this, outerClassEntry); | ||
| 162 | String newName = outerClassEntry.getName() + "$" + innerClassEntry.getSimpleName(); | ||
| 163 | // DEBUG | ||
| 164 | //System.out.println("REPLACE: " + innerClassEntry.getName() + " WITH " + newName); | ||
| 165 | renames.put(innerClassEntry.getName(), newName); | ||
| 159 | } | 166 | } |
| 160 | EntryRenamer.renameClassesInSet(renames, m_obfClassEntries); | 167 | EntryRenamer.renameClassesInSet(renames, m_obfClassEntries); |
| 161 | m_translationIndex.renameClasses(renames); | 168 | m_translationIndex.renameClasses(renames); |
| @@ -290,7 +297,7 @@ public class JarIndex { | |||
| 290 | } | 297 | } |
| 291 | } | 298 | } |
| 292 | 299 | ||
| 293 | private String findOuterClass(CtClass c) { | 300 | private ClassEntry findOuterClass(CtClass c) { |
| 294 | 301 | ||
| 295 | // inner classes: | 302 | // inner classes: |
| 296 | // have constructors that can (illegally) set synthetic fields | 303 | // have constructors that can (illegally) set synthetic fields |
| @@ -341,19 +348,19 @@ public class JarIndex { | |||
| 341 | // do we have an answer yet? | 348 | // do we have an answer yet? |
| 342 | if (callerClasses.isEmpty()) { | 349 | if (callerClasses.isEmpty()) { |
| 343 | if (illegallySetClasses.size() == 1) { | 350 | if (illegallySetClasses.size() == 1) { |
| 344 | return illegallySetClasses.iterator().next().getName(); | 351 | return illegallySetClasses.iterator().next(); |
| 345 | } else { | 352 | } else { |
| 346 | System.out.println(String.format("WARNING: Unable to find outer class for %s. No caller and no illegally set field classes.", classEntry)); | 353 | System.out.println(String.format("WARNING: Unable to find outer class for %s. No caller and no illegally set field classes.", classEntry)); |
| 347 | } | 354 | } |
| 348 | } else { | 355 | } else { |
| 349 | if (callerClasses.size() == 1) { | 356 | if (callerClasses.size() == 1) { |
| 350 | return callerClasses.iterator().next().getName(); | 357 | return callerClasses.iterator().next(); |
| 351 | } else { | 358 | } else { |
| 352 | // multiple callers, do the illegally set classes narrow it down? | 359 | // multiple callers, do the illegally set classes narrow it down? |
| 353 | Set<ClassEntry> intersection = Sets.newHashSet(callerClasses); | 360 | Set<ClassEntry> intersection = Sets.newHashSet(callerClasses); |
| 354 | intersection.retainAll(illegallySetClasses); | 361 | intersection.retainAll(illegallySetClasses); |
| 355 | if (intersection.size() == 1) { | 362 | if (intersection.size() == 1) { |
| 356 | return intersection.iterator().next().getName(); | 363 | return intersection.iterator().next(); |
| 357 | } else { | 364 | } else { |
| 358 | System.out.println(String.format("WARNING: Unable to choose outer class for %s among options: %s", classEntry, callerClasses)); | 365 | System.out.println(String.format("WARNING: Unable to choose outer class for %s among options: %s", classEntry, callerClasses)); |
| 359 | } | 366 | } |
| @@ -448,7 +455,7 @@ public class JarIndex { | |||
| 448 | return true; | 455 | return true; |
| 449 | } | 456 | } |
| 450 | 457 | ||
| 451 | private BehaviorEntry isAnonymousClass(CtClass c, String outerClassName) { | 458 | private BehaviorEntry isAnonymousClass(CtClass c, ClassEntry outerClassEntry) { |
| 452 | 459 | ||
| 453 | ClassEntry innerClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); | 460 | ClassEntry innerClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); |
| 454 | 461 | ||
| @@ -669,23 +676,19 @@ public class JarIndex { | |||
| 669 | return behaviorEntries; | 676 | return behaviorEntries; |
| 670 | } | 677 | } |
| 671 | 678 | ||
| 672 | public Collection<String> getInnerClasses(String obfOuterClassName) { | 679 | public Collection<ClassEntry> getInnerClasses(ClassEntry obfOuterClassEntry) { |
| 673 | return m_innerClasses.get(obfOuterClassName); | 680 | return m_innerClassesByOuter.get(obfOuterClassEntry); |
| 674 | } | 681 | } |
| 675 | 682 | ||
| 676 | public String getOuterClass(String obfInnerClassName) { | 683 | public ClassEntry getOuterClass(ClassEntry obfInnerClassEntry) { |
| 677 | // make sure we use the right name | 684 | return m_outerClassesByInner.get(obfInnerClassEntry); |
| 678 | if (new ClassEntry(obfInnerClassName).getPackageName() != null) { | ||
| 679 | throw new IllegalArgumentException("Don't reference obfuscated inner classes using packages: " + obfInnerClassName); | ||
| 680 | } | ||
| 681 | return m_outerClasses.get(obfInnerClassName); | ||
| 682 | } | 685 | } |
| 683 | 686 | ||
| 684 | public boolean isAnonymousClass(String obfInnerClassName) { | 687 | public boolean isAnonymousClass(ClassEntry obfInnerClassEntry) { |
| 685 | return m_anonymousClasses.containsKey(obfInnerClassName); | 688 | return m_anonymousClasses.containsKey(obfInnerClassEntry); |
| 686 | } | 689 | } |
| 687 | 690 | ||
| 688 | public BehaviorEntry getAnonymousClassCaller(String obfInnerClassName) { | 691 | public BehaviorEntry getAnonymousClassCaller(ClassEntry obfInnerClassName) { |
| 689 | return m_anonymousClasses.get(obfInnerClassName); | 692 | return m_anonymousClasses.get(obfInnerClassName); |
| 690 | } | 693 | } |
| 691 | 694 | ||