summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/cuchaz/enigma/Deobfuscator.java91
-rw-r--r--src/main/java/cuchaz/enigma/analysis/Access.java13
-rw-r--r--src/main/java/cuchaz/enigma/analysis/JarIndex.java11
-rw-r--r--src/main/java/cuchaz/enigma/gui/GuiController.java4
-rw-r--r--src/main/java/cuchaz/enigma/gui/elements/MenuBar.java10
-rw-r--r--src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java4
-rw-r--r--src/main/java/cuchaz/enigma/mapping/Mappings.java4
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java56
8 files changed, 174 insertions, 19 deletions
diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java
index b3fb3158..2207999d 100644
--- a/src/main/java/cuchaz/enigma/Deobfuscator.java
+++ b/src/main/java/cuchaz/enigma/Deobfuscator.java
@@ -11,6 +11,7 @@
11package cuchaz.enigma; 11package cuchaz.enigma;
12 12
13import com.google.common.base.Charsets; 13import com.google.common.base.Charsets;
14import com.google.common.collect.Lists;
14import com.google.common.collect.Maps; 15import com.google.common.collect.Maps;
15import com.google.common.collect.Sets; 16import com.google.common.collect.Sets;
16import com.strobel.assembler.metadata.MetadataSystem; 17import com.strobel.assembler.metadata.MetadataSystem;
@@ -32,9 +33,7 @@ import javassist.CtClass;
32import javassist.bytecode.Descriptor; 33import javassist.bytecode.Descriptor;
33 34
34import java.io.*; 35import java.io.*;
35import java.util.List; 36import java.util.*;
36import java.util.Map;
37import java.util.Set;
38import java.util.jar.JarEntry; 37import java.util.jar.JarEntry;
39import java.util.jar.JarFile; 38import java.util.jar.JarFile;
40import java.util.jar.JarOutputStream; 39import java.util.jar.JarOutputStream;
@@ -297,6 +296,92 @@ public class Deobfuscator {
297 } 296 }
298 } 297 }
299 298
299 private void addAllPotentialAncestors(Set<ClassEntry> classEntries, ClassEntry classObfEntry) {
300 for (ClassEntry interfaceEntry : jarIndex.getTranslationIndex().getInterfaces(classObfEntry)) {
301 if (classEntries.add(interfaceEntry)) {
302 addAllPotentialAncestors(classEntries, interfaceEntry);
303 }
304 }
305
306 ClassEntry superClassEntry = jarIndex.getTranslationIndex().getSuperclass(classObfEntry);
307 if (superClassEntry != null && classEntries.add(superClassEntry)) {
308 addAllPotentialAncestors(classEntries, superClassEntry);
309 }
310 }
311
312 private boolean isBehaviorProvider(ClassEntry classObfEntry, BehaviorEntry behaviorEntry) {
313 if (behaviorEntry instanceof MethodEntry) {
314 MethodEntry methodEntry = (MethodEntry) behaviorEntry;
315
316 Set<ClassEntry> classEntries = new HashSet<>();
317 addAllPotentialAncestors(classEntries, classObfEntry);
318
319 for (ClassEntry parentEntry : classEntries) {
320 MethodEntry ancestorMethodEntry = new MethodEntry(parentEntry, methodEntry.getName(), methodEntry.getSignature());
321 if (jarIndex.containsObfBehavior(ancestorMethodEntry)) {
322 return false;
323 }
324 }
325 }
326
327 return true;
328 }
329
330 public void rebuildMethodNames(ProgressListener progress) {
331 int i = 0;
332 Map<ClassMapping, Map<Entry, String>> renameClassMap = new HashMap<>();
333
334 progress.init(getMappings().classes().size() * 3, "Rebuilding method names");
335
336 for (ClassMapping classMapping : Lists.newArrayList(getMappings().classes())) {
337 Map<Entry, String> renameEntries = new HashMap<>();
338
339 progress.onProgress(i++, classMapping.getDeobfName());
340
341 for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) {
342 ClassEntry classObfEntry = classMapping.getObfEntry();
343 BehaviorEntry obfEntry = methodMapping.getObfEntry(classObfEntry);
344
345 if (isBehaviorProvider(classObfEntry, obfEntry)) {
346 if (hasDeobfuscatedName(obfEntry) && !(obfEntry instanceof ConstructorEntry)
347 && !(methodMapping.getDeobfName().equals(methodMapping.getObfName()))) {
348 renameEntries.put(obfEntry, methodMapping.getDeobfName());
349 }
350
351 for (ArgumentMapping argumentMapping : Lists.newArrayList(methodMapping.arguments())) {
352 Entry argObfEntry = argumentMapping.getObfEntry(obfEntry);
353 if (hasDeobfuscatedName(argObfEntry)) {
354 renameEntries.put(argObfEntry, deobfuscateEntry(argObfEntry).getName());
355 }
356 }
357 }
358 }
359
360 renameClassMap.put(classMapping, renameEntries);
361 }
362
363 for (Map.Entry<ClassMapping, Map<Entry, String>> renameClassMapEntry : renameClassMap.entrySet()) {
364 progress.onProgress(i++, renameClassMapEntry.getKey().getDeobfName());
365
366 for (Map.Entry<Entry, String> entry : renameClassMapEntry.getValue().entrySet()) {
367 Entry obfEntry = entry.getKey();
368
369 removeMapping(obfEntry);
370 }
371 }
372
373 for (Map.Entry<ClassMapping, Map<Entry, String>> renameClassMapEntry : renameClassMap.entrySet()) {
374 progress.onProgress(i++, renameClassMapEntry.getKey().getDeobfName());
375
376 for (Map.Entry<Entry, String> entry : renameClassMapEntry.getValue().entrySet()) {
377 Entry obfEntry = entry.getKey();
378 String name = entry.getValue();
379
380 rename(obfEntry, name);
381 }
382 }
383 }
384
300 public void writeJar(File out, ProgressListener progress) { 385 public void writeJar(File out, ProgressListener progress) {
301 final TranslatingTypeLoader loader = new TranslatingTypeLoader( 386 final TranslatingTypeLoader loader = new TranslatingTypeLoader(
302 this.jar, 387 this.jar,
diff --git a/src/main/java/cuchaz/enigma/analysis/Access.java b/src/main/java/cuchaz/enigma/analysis/Access.java
index 877327f1..b8aafaa0 100644
--- a/src/main/java/cuchaz/enigma/analysis/Access.java
+++ b/src/main/java/cuchaz/enigma/analysis/Access.java
@@ -19,6 +19,7 @@ public enum Access {
19 19
20 Public, 20 Public,
21 Protected, 21 Protected,
22 Package,
22 Private; 23 Private;
23 24
24 public static Access get(CtBehavior behavior) { 25 public static Access get(CtBehavior behavior) {
@@ -30,12 +31,18 @@ public enum Access {
30 } 31 }
31 32
32 public static Access get(int modifiers) { 33 public static Access get(int modifiers) {
33 if (Modifier.isPublic(modifiers)) { 34 boolean isPublic = Modifier.isPublic(modifiers);
35 boolean isProtected = Modifier.isProtected(modifiers);
36 boolean isPrivate = Modifier.isPrivate(modifiers);
37
38 if (isPublic && !isProtected && !isPrivate) {
34 return Public; 39 return Public;
35 } else if (Modifier.isProtected(modifiers)) { 40 } else if (!isPublic && isProtected && !isPrivate) {
36 return Protected; 41 return Protected;
37 } else if (Modifier.isPrivate(modifiers)) { 42 } else if (!isPublic && !isProtected && isPrivate) {
38 return Private; 43 return Private;
44 } else if (!isPublic && !isProtected && !isPrivate) {
45 return Package;
39 } 46 }
40 // assume public by default 47 // assume public by default
41 return Public; 48 return Public;
diff --git a/src/main/java/cuchaz/enigma/analysis/JarIndex.java b/src/main/java/cuchaz/enigma/analysis/JarIndex.java
index 851f3faa..e501540d 100644
--- a/src/main/java/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/main/java/cuchaz/enigma/analysis/JarIndex.java
@@ -38,6 +38,7 @@ public class JarIndex {
38 private Map<ClassEntry, ClassEntry> outerClassesByInner; 38 private Map<ClassEntry, ClassEntry> outerClassesByInner;
39 private Map<ClassEntry, BehaviorEntry> anonymousClasses; 39 private Map<ClassEntry, BehaviorEntry> anonymousClasses;
40 private Map<MethodEntry, MethodEntry> bridgedMethods; 40 private Map<MethodEntry, MethodEntry> bridgedMethods;
41 private Set<MethodEntry> syntheticMethods;
41 42
42 public JarIndex() { 43 public JarIndex() {
43 this.obfClassEntries = Sets.newHashSet(); 44 this.obfClassEntries = Sets.newHashSet();
@@ -52,6 +53,7 @@ public class JarIndex {
52 this.outerClassesByInner = Maps.newHashMap(); 53 this.outerClassesByInner = Maps.newHashMap();
53 this.anonymousClasses = Maps.newHashMap(); 54 this.anonymousClasses = Maps.newHashMap();
54 this.bridgedMethods = Maps.newHashMap(); 55 this.bridgedMethods = Maps.newHashMap();
56 this.syntheticMethods = Sets.newHashSet();
55 } 57 }
56 58
57 public void indexJar(JarFile jar, boolean buildInnerClasses) { 59 public void indexJar(JarFile jar, boolean buildInnerClasses) {
@@ -155,6 +157,11 @@ public class JarIndex {
155 if (behaviorEntry instanceof MethodEntry) { 157 if (behaviorEntry instanceof MethodEntry) {
156 MethodEntry methodEntry = (MethodEntry) behaviorEntry; 158 MethodEntry methodEntry = (MethodEntry) behaviorEntry;
157 159
160 // is synthetic
161 if ((behavior.getModifiers() & AccessFlag.SYNTHETIC) != 0) {
162 syntheticMethods.add(methodEntry);
163 }
164
158 // index implementation 165 // index implementation
159 this.methodImplementations.put(behaviorEntry.getClassName(), methodEntry); 166 this.methodImplementations.put(behaviorEntry.getClassName(), methodEntry);
160 167
@@ -720,6 +727,10 @@ public class JarIndex {
720 return this.anonymousClasses.containsKey(obfInnerClassEntry); 727 return this.anonymousClasses.containsKey(obfInnerClassEntry);
721 } 728 }
722 729
730 public boolean isSyntheticMethod(MethodEntry methodEntry) {
731 return this.syntheticMethods.contains(methodEntry);
732 }
733
723 public BehaviorEntry getAnonymousClassCaller(ClassEntry obfInnerClassName) { 734 public BehaviorEntry getAnonymousClassCaller(ClassEntry obfInnerClassName) {
724 return this.anonymousClasses.get(obfInnerClassName); 735 return this.anonymousClasses.get(obfInnerClassName);
725 } 736 }
diff --git a/src/main/java/cuchaz/enigma/gui/GuiController.java b/src/main/java/cuchaz/enigma/gui/GuiController.java
index 1deb7d2a..3188ff02 100644
--- a/src/main/java/cuchaz/enigma/gui/GuiController.java
+++ b/src/main/java/cuchaz/enigma/gui/GuiController.java
@@ -100,6 +100,10 @@ public class GuiController {
100 refreshCurrentClass(); 100 refreshCurrentClass();
101 } 101 }
102 102
103 public void rebuildMethodNames() {
104 ProgressDialog.runInThread(this.gui.getFrame(), progress -> this.deobfuscator.rebuildMethodNames(progress));
105 }
106
103 public void exportSource(final File dirOut) { 107 public void exportSource(final File dirOut) {
104 ProgressDialog.runInThread(this.gui.getFrame(), progress -> this.deobfuscator.writeSources(dirOut, progress)); 108 ProgressDialog.runInThread(this.gui.getFrame(), progress -> this.deobfuscator.writeSources(dirOut, progress));
105 } 109 }
diff --git a/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java b/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java
index befe1291..dcd7c93a 100644
--- a/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java
+++ b/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java
@@ -25,6 +25,7 @@ public class MenuBar extends JMenuBar {
25 public final JMenuItem saveMappingsSrgMenu; 25 public final JMenuItem saveMappingsSrgMenu;
26 public final JMenuItem closeMappingsMenu; 26 public final JMenuItem closeMappingsMenu;
27 27
28 public final JMenuItem rebuildMethodNamesMenu;
28 29
29 public final JMenuItem exportSourceMenu; 30 public final JMenuItem exportSourceMenu;
30 public final JMenuItem exportJarMenu; 31 public final JMenuItem exportJarMenu;
@@ -174,6 +175,15 @@ public class MenuBar extends JMenuBar {
174 } 175 }
175 menu.addSeparator(); 176 menu.addSeparator();
176 { 177 {
178 JMenuItem item = new JMenuItem("Rebuild Method Names");
179 menu.add(item);
180 item.addActionListener(event -> {
181 this.gui.getController().rebuildMethodNames();
182 });
183 this.rebuildMethodNamesMenu = item;
184 }
185 menu.addSeparator();
186 {
177 JMenuItem item = new JMenuItem("Export Source..."); 187 JMenuItem item = new JMenuItem("Export Source...");
178 menu.add(item); 188 menu.add(item);
179 item.addActionListener(event -> { 189 item.addActionListener(event -> {
diff --git a/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java b/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java
index d117de02..e3f89272 100644
--- a/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java
@@ -38,6 +38,10 @@ public class ArgumentMapping implements Comparable<ArgumentMapping> {
38 this.name = NameValidator.validateArgumentName(val); 38 this.name = NameValidator.validateArgumentName(val);
39 } 39 }
40 40
41 public ArgumentEntry getObfEntry(BehaviorEntry behaviorEntry) {
42 return new ArgumentEntry(behaviorEntry, index, name);
43 }
44
41 @Override 45 @Override
42 public int compareTo(ArgumentMapping other) { 46 public int compareTo(ArgumentMapping other) {
43 return Integer.compare(this.index, other.index); 47 return Integer.compare(this.index, other.index);
diff --git a/src/main/java/cuchaz/enigma/mapping/Mappings.java b/src/main/java/cuchaz/enigma/mapping/Mappings.java
index 47c42324..7061be79 100644
--- a/src/main/java/cuchaz/enigma/mapping/Mappings.java
+++ b/src/main/java/cuchaz/enigma/mapping/Mappings.java
@@ -175,9 +175,9 @@ public class Mappings {
175 return classMapping != null && classMapping.containsDeobfField(deobfName, obfType); 175 return classMapping != null && classMapping.containsDeobfField(deobfName, obfType);
176 } 176 }
177 177
178 public boolean containsDeobfMethod(ClassEntry obfClassEntry, String deobfName, Signature deobfSignature) { 178 public boolean containsDeobfMethod(ClassEntry obfClassEntry, String deobfName, Signature obfSignature) {
179 ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName()); 179 ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName());
180 return classMapping != null && classMapping.containsDeobfMethod(deobfName, deobfSignature); 180 return classMapping != null && classMapping.containsDeobfMethod(deobfName, obfSignature);
181 } 181 }
182 182
183 public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) { 183 public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) {
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
index f244748f..7c6c8318 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
@@ -17,6 +17,7 @@ import java.util.List;
17import java.util.Set; 17import java.util.Set;
18import java.util.zip.GZIPOutputStream; 18import java.util.zip.GZIPOutputStream;
19 19
20import com.google.common.collect.Lists;
20import cuchaz.enigma.analysis.JarIndex; 21import cuchaz.enigma.analysis.JarIndex;
21import cuchaz.enigma.throwables.IllegalNameException; 22import cuchaz.enigma.throwables.IllegalNameException;
22import cuchaz.enigma.throwables.MappingConflict; 23import cuchaz.enigma.throwables.MappingConflict;
@@ -110,10 +111,16 @@ public class MappingsRenamer {
110 111
111 deobfName = NameValidator.validateMethodName(deobfName); 112 deobfName = NameValidator.validateMethodName(deobfName);
112 for (MethodEntry entry : implementations) { 113 for (MethodEntry entry : implementations) {
113 Signature deobfSignature = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateSignature(obf.getSignature()); 114 MethodEntry targetEntry = new MethodEntry(entry.getClassEntry(), deobfName, entry.getSignature());
114 MethodEntry targetEntry = new MethodEntry(entry.getClassEntry(), deobfName, deobfSignature); 115
115 if (m_mappings.containsDeobfMethod(entry.getClassEntry(), deobfName, entry.getSignature()) || m_index.containsObfBehavior(targetEntry)) { 116 // TODO: Verify if I don't break things
117 ClassMapping classMapping = m_mappings.getClassByObf(entry.getClassEntry());
118 if ((classMapping != null && classMapping.containsDeobfMethod(deobfName, entry.getSignature()) && classMapping.getMethodByObf(entry.getName(), entry.getSignature()) != classMapping.getMethodByDeobf(deobfName, entry.getSignature()))
119 || m_index.containsObfBehavior(targetEntry)) {
116 String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateClass(entry.getClassName()); 120 String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateClass(entry.getClassName());
121 if (deobfClassName == null) {
122 deobfClassName = entry.getClassName();
123 }
117 throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); 124 throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName);
118 } 125 }
119 } 126 }
@@ -126,12 +133,18 @@ public class MappingsRenamer {
126 public void setMethodName(MethodEntry obf, String deobfName) { 133 public void setMethodName(MethodEntry obf, String deobfName) {
127 deobfName = NameValidator.validateMethodName(deobfName); 134 deobfName = NameValidator.validateMethodName(deobfName);
128 MethodEntry targetEntry = new MethodEntry(obf.getClassEntry(), deobfName, obf.getSignature()); 135 MethodEntry targetEntry = new MethodEntry(obf.getClassEntry(), deobfName, obf.getSignature());
129 if (m_mappings.containsDeobfMethod(obf.getClassEntry(), deobfName, obf.getSignature()) || m_index.containsObfBehavior(targetEntry)) { 136 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
137
138 // TODO: Verify if I don't break things
139 if ((m_mappings.containsDeobfMethod(obf.getClassEntry(), deobfName, obf.getSignature()) && classMapping.getMethodByObf(obf.getName(), obf.getSignature()) != classMapping.getMethodByDeobf(deobfName, obf.getSignature()))
140 || m_index.containsObfBehavior(targetEntry)) {
130 String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateClass(obf.getClassName()); 141 String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateClass(obf.getClassName());
142 if (deobfClassName == null) {
143 deobfClassName = obf.getClassName();
144 }
131 throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); 145 throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName);
132 } 146 }
133 147
134 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
135 classMapping.setMethodName(obf.getName(), obf.getSignature(), deobfName); 148 classMapping.setMethodName(obf.getName(), obf.getSignature(), deobfName);
136 } 149 }
137 150
@@ -163,9 +176,21 @@ public class MappingsRenamer {
163 176
164 Set<MethodEntry> implementations = m_index.getRelatedMethodImplementations(obfMethod); 177 Set<MethodEntry> implementations = m_index.getRelatedMethodImplementations(obfMethod);
165 for (MethodEntry entry : implementations) { 178 for (MethodEntry entry : implementations) {
166 // NOTE: don't need to check arguments for name collisions with names determined by Procyon 179 ClassMapping classMapping = m_mappings.getClassByObf(entry.getClassEntry());
167 if (m_mappings.containsArgument(entry, deobfName)) { 180 if (classMapping != null) {
168 throw new IllegalNameException(deobfName, "There is already an argument with that name"); 181 MethodMapping mapping = classMapping.getMethodByObf(entry.getName(), entry.getSignature());
182 // NOTE: don't need to check arguments for name collisions with names determined by Procyon
183 // TODO: Verify if I don't break things
184 if (mapping != null) {
185 for (ArgumentMapping argumentMapping : Lists.newArrayList(mapping.arguments())) {
186 if (argumentMapping.getIndex() != obf.getIndex()) {
187 if (mapping.getDeobfArgumentName(argumentMapping.getIndex()).equals(deobfName)
188 || argumentMapping.getName().equals(deobfName)) {
189 throw new IllegalNameException(deobfName, "There is already an argument with that name");
190 }
191 }
192 }
193 }
169 } 194 }
170 } 195 }
171 196
@@ -176,12 +201,21 @@ public class MappingsRenamer {
176 201
177 public void setArgumentName(ArgumentEntry obf, String deobfName) { 202 public void setArgumentName(ArgumentEntry obf, String deobfName) {
178 deobfName = NameValidator.validateArgumentName(deobfName); 203 deobfName = NameValidator.validateArgumentName(deobfName);
204 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
205 MethodMapping mapping = classMapping.getMethodByObf(obf.getMethodName(), obf.getMethodSignature());
179 // NOTE: don't need to check arguments for name collisions with names determined by Procyon 206 // NOTE: don't need to check arguments for name collisions with names determined by Procyon
180 if (m_mappings.containsArgument(obf.getBehaviorEntry(), deobfName)) { 207 // TODO: Verify if I don't break things
181 throw new IllegalNameException(deobfName, "There is already an argument with that name"); 208 if (mapping != null) {
209 for (ArgumentMapping argumentMapping : Lists.newArrayList(mapping.arguments())) {
210 if (argumentMapping.getIndex() != obf.getIndex()) {
211 if (mapping.getDeobfArgumentName(argumentMapping.getIndex()).equals(deobfName)
212 || argumentMapping.getName().equals(deobfName)) {
213 throw new IllegalNameException(deobfName, "There is already an argument with that name");
214 }
215 }
216 }
182 } 217 }
183 218
184 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
185 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName); 219 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName);
186 } 220 }
187 221