summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--src/main/java/cuchaz/enigma/CachingClasspathTypeLoader.java20
-rw-r--r--src/main/java/cuchaz/enigma/CachingTypeLoader.java38
-rw-r--r--src/main/java/cuchaz/enigma/Deobfuscator.java14
-rw-r--r--src/main/java/cuchaz/enigma/ITranslatingTypeLoader.java19
-rw-r--r--src/main/java/cuchaz/enigma/SynchronizedTypeLoader.java39
-rw-r--r--src/main/java/cuchaz/enigma/TranslatingTypeLoader.java47
-rw-r--r--src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java15
8 files changed, 158 insertions, 35 deletions
diff --git a/.gitignore b/.gitignore
index 1729e4d6..662e408b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -150,6 +150,7 @@ flycheck_*.el
150 150
151# IntelliJ 151# IntelliJ
152/out/ 152/out/
153.idea
153 154
154# mpeltonen/sbt-idea plugin 155# mpeltonen/sbt-idea plugin
155.idea_modules/ 156.idea_modules/
diff --git a/src/main/java/cuchaz/enigma/CachingClasspathTypeLoader.java b/src/main/java/cuchaz/enigma/CachingClasspathTypeLoader.java
new file mode 100644
index 00000000..fca2a47e
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/CachingClasspathTypeLoader.java
@@ -0,0 +1,20 @@
1package cuchaz.enigma;
2
3import com.strobel.assembler.metadata.Buffer;
4import com.strobel.assembler.metadata.ClasspathTypeLoader;
5import com.strobel.assembler.metadata.ITypeLoader;
6
7/**
8 * Caching version of {@link ClasspathTypeLoader}
9 */
10class CachingClasspathTypeLoader extends CachingTypeLoader {
11 private final ITypeLoader classpathLoader = new ClasspathTypeLoader();
12
13 protected byte[] doLoad(String className) {
14 Buffer parentBuf = new Buffer();
15 if (classpathLoader.tryLoadType(className, parentBuf)) {
16 return parentBuf.array();
17 }
18 return EMPTY_ARRAY;//need to return *something* as null means no store
19 }
20}
diff --git a/src/main/java/cuchaz/enigma/CachingTypeLoader.java b/src/main/java/cuchaz/enigma/CachingTypeLoader.java
new file mode 100644
index 00000000..22c31c63
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/CachingTypeLoader.java
@@ -0,0 +1,38 @@
1package cuchaz.enigma;
2
3import com.google.common.collect.Maps;
4import com.strobel.assembler.metadata.Buffer;
5import com.strobel.assembler.metadata.ITypeLoader;
6
7import java.util.Map;
8
9/**
10 * Common cache functions
11 */
12public abstract class CachingTypeLoader implements ITypeLoader {
13 protected static final byte[] EMPTY_ARRAY = {};
14
15 private final Map<String, byte[]> cache = Maps.newHashMap();
16
17 protected abstract byte[] doLoad(String className);
18
19 @Override
20 public boolean tryLoadType(String className, Buffer out) {
21
22 // check the cache
23 byte[] data = this.cache.computeIfAbsent(className, this::doLoad);
24
25 if (data == EMPTY_ARRAY) {
26 return false;
27 }
28
29 out.reset(data.length);
30 System.arraycopy(data, 0, out.array(), out.position(), data.length);
31 out.position(0);
32 return true;
33 }
34
35 public void clearCache() {
36 this.cache.clear();
37 }
38}
diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java
index 0e037536..b2cecfe2 100644
--- a/src/main/java/cuchaz/enigma/Deobfuscator.java
+++ b/src/main/java/cuchaz/enigma/Deobfuscator.java
@@ -163,6 +163,10 @@ public class Deobfuscator {
163 } 163 }
164 164
165 public CompilationUnit getSourceTree(String className) { 165 public CompilationUnit getSourceTree(String className) {
166 return getSourceTree(className, createTypeLoader());
167 }
168
169 public CompilationUnit getSourceTree(String className, ITranslatingTypeLoader loader) {
166 170
167 // we don't know if this class name is obfuscated or deobfuscated 171 // we don't know if this class name is obfuscated or deobfuscated
168 // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out 172 // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out
@@ -178,7 +182,6 @@ public class Deobfuscator {
178 } 182 }
179 183
180 // set the desc loader 184 // set the desc loader
181 TranslatingTypeLoader loader = createTypeLoader();
182 this.settings.setTypeLoader(loader); 185 this.settings.setTypeLoader(loader);
183 186
184 // see if procyon can find the desc 187 // see if procyon can find the desc
@@ -267,6 +270,10 @@ public class Deobfuscator {
267 progress.init(classEntries.size(), "Decompiling classes..."); 270 progress.init(classEntries.size(), "Decompiling classes...");
268 } 271 }
269 272
273 //create a common instance outside the loop as mappings shouldn't be changing while this is happening
274 //synchronized to make sure the parallelStream doesn't CME with the cache
275 ITranslatingTypeLoader typeLoader = new SynchronizedTypeLoader(createTypeLoader());
276
270 // DEOBFUSCATE ALL THE THINGS!! @_@ 277 // DEOBFUSCATE ALL THE THINGS!! @_@
271 Stopwatch stopwatch = Stopwatch.createStarted(); 278 Stopwatch stopwatch = Stopwatch.createStarted();
272 AtomicInteger count = new AtomicInteger(); 279 AtomicInteger count = new AtomicInteger();
@@ -278,7 +285,7 @@ public class Deobfuscator {
278 285
279 try { 286 try {
280 // get the source 287 // get the source
281 CompilationUnit sourceTree = getSourceTree(obfClassEntry.getName()); 288 CompilationUnit sourceTree = getSourceTree(obfClassEntry.getName(), typeLoader);
282 289
283 // write the file 290 // write the file
284 File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java"); 291 File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java");
@@ -295,7 +302,7 @@ public class Deobfuscator {
295 } 302 }
296 }); 303 });
297 stopwatch.stop(); 304 stopwatch.stop();
298 System.out.println("Done in : " + stopwatch.toString()); 305 System.out.println("writeSources Done in : " + stopwatch.toString());
299 if (progress != null) { 306 if (progress != null) {
300 progress.onProgress(count.get(), "Done:"); 307 progress.onProgress(count.get(), "Done:");
301 } 308 }
@@ -658,4 +665,5 @@ public class Deobfuscator {
658 public interface ClassTransformer { 665 public interface ClassTransformer {
659 String transform(ClassNode node, ClassWriter writer); 666 String transform(ClassNode node, ClassWriter writer);
660 } 667 }
668
661} 669}
diff --git a/src/main/java/cuchaz/enigma/ITranslatingTypeLoader.java b/src/main/java/cuchaz/enigma/ITranslatingTypeLoader.java
new file mode 100644
index 00000000..547ed0b2
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/ITranslatingTypeLoader.java
@@ -0,0 +1,19 @@
1package cuchaz.enigma;
2
3import com.strobel.assembler.metadata.ITypeLoader;
4import cuchaz.enigma.mapping.entry.ClassEntry;
5import org.objectweb.asm.ClassWriter;
6import org.objectweb.asm.tree.ClassNode;
7
8import java.util.List;
9
10/**
11 * For delegation of TranslatingTypeLoader without needing the subclass the whole thing
12 */
13public interface ITranslatingTypeLoader extends ITypeLoader {
14 List<String> getClassNamesToTry(String className);
15
16 List<String> getClassNamesToTry(ClassEntry obfClassEntry);
17
18 String transformInto(ClassNode node, ClassWriter writer);
19}
diff --git a/src/main/java/cuchaz/enigma/SynchronizedTypeLoader.java b/src/main/java/cuchaz/enigma/SynchronizedTypeLoader.java
new file mode 100644
index 00000000..9aa3c5e4
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/SynchronizedTypeLoader.java
@@ -0,0 +1,39 @@
1package cuchaz.enigma;
2
3import com.strobel.assembler.metadata.Buffer;
4import cuchaz.enigma.mapping.entry.ClassEntry;
5import org.objectweb.asm.ClassWriter;
6import org.objectweb.asm.tree.ClassNode;
7
8import java.util.List;
9
10/**
11 * Typeloader with synchronized tryLoadType method
12 */
13public class SynchronizedTypeLoader implements ITranslatingTypeLoader {
14 private final TranslatingTypeLoader delegate;
15
16 SynchronizedTypeLoader(TranslatingTypeLoader delegate) {
17 this.delegate = delegate;
18 }
19
20 @Override
21 public List<String> getClassNamesToTry(String className) {
22 return delegate.getClassNamesToTry(className);
23 }
24
25 @Override
26 public List<String> getClassNamesToTry(ClassEntry obfClassEntry) {
27 return delegate.getClassNamesToTry(obfClassEntry);
28 }
29
30 @Override
31 public String transformInto(ClassNode node, ClassWriter writer) {
32 return delegate.transformInto(node, writer);
33 }
34
35 @Override
36 public synchronized boolean tryLoadType(String internalName, Buffer buffer) {
37 return delegate.tryLoadType(internalName, buffer);
38 }
39}
diff --git a/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java b/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java
index 34901d52..eb780ee9 100644
--- a/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java
+++ b/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java
@@ -12,9 +12,7 @@
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import com.google.common.collect.Lists; 14import com.google.common.collect.Lists;
15import com.google.common.collect.Maps;
16import com.strobel.assembler.metadata.Buffer; 15import com.strobel.assembler.metadata.Buffer;
17import com.strobel.assembler.metadata.ClasspathTypeLoader;
18import com.strobel.assembler.metadata.ITypeLoader; 16import com.strobel.assembler.metadata.ITypeLoader;
19import cuchaz.enigma.analysis.JarIndex; 17import cuchaz.enigma.analysis.JarIndex;
20import cuchaz.enigma.analysis.ParsedJar; 18import cuchaz.enigma.analysis.ParsedJar;
@@ -27,17 +25,16 @@ import org.objectweb.asm.Opcodes;
27import org.objectweb.asm.tree.ClassNode; 25import org.objectweb.asm.tree.ClassNode;
28 26
29import java.util.List; 27import java.util.List;
30import java.util.Map;
31 28
32public class TranslatingTypeLoader implements ITypeLoader { 29public class TranslatingTypeLoader extends CachingTypeLoader implements ITranslatingTypeLoader {
30 //Store one instance as the classpath shouldnt change during load
31 private static final ITypeLoader defaultTypeLoader = new CachingClasspathTypeLoader();
33 32
34 private final ParsedJar jar; 33 private final ParsedJar jar;
35 private final JarIndex jarIndex; 34 private final JarIndex jarIndex;
36 private final ReferencedEntryPool entryPool; 35 private final ReferencedEntryPool entryPool;
37 private final Translator obfuscatingTranslator; 36 private final Translator obfuscatingTranslator;
38 private final Translator deobfuscatingTranslator; 37 private final Translator deobfuscatingTranslator;
39 private final Map<String, byte[]> cache;
40 private final ClasspathTypeLoader defaultTypeLoader;
41 38
42 public TranslatingTypeLoader(ParsedJar jar, JarIndex jarIndex, ReferencedEntryPool entryPool, Translator obfuscatingTranslator, Translator deobfuscatingTranslator) { 39 public TranslatingTypeLoader(ParsedJar jar, JarIndex jarIndex, ReferencedEntryPool entryPool, Translator obfuscatingTranslator, Translator deobfuscatingTranslator) {
43 this.jar = jar; 40 this.jar = jar;
@@ -45,37 +42,19 @@ public class TranslatingTypeLoader implements ITypeLoader {
45 this.entryPool = entryPool; 42 this.entryPool = entryPool;
46 this.obfuscatingTranslator = obfuscatingTranslator; 43 this.obfuscatingTranslator = obfuscatingTranslator;
47 this.deobfuscatingTranslator = deobfuscatingTranslator; 44 this.deobfuscatingTranslator = deobfuscatingTranslator;
48 this.cache = Maps.newHashMap();
49 this.defaultTypeLoader = new ClasspathTypeLoader();
50
51 }
52
53 public void clearCache() {
54 this.cache.clear();
55 } 45 }
56 46
57 @Override 47 protected byte[] doLoad(String className){
58 public boolean tryLoadType(String className, Buffer out) { 48 byte[] data = loadType(className);
59
60 // check the cache
61 byte[] data;
62 if (this.cache.containsKey(className)) {
63 data = this.cache.get(className);
64 } else {
65 data = loadType(className);
66 this.cache.put(className, data);
67 }
68
69 if (data == null) { 49 if (data == null) {
70 // chain to default desc loader 50 // chain to default desc loader
71 return this.defaultTypeLoader.tryLoadType(className, out); 51 Buffer parentBuf = new Buffer();
52 if (defaultTypeLoader.tryLoadType(className, parentBuf)){
53 return parentBuf.array();
54 }
55 return EMPTY_ARRAY;//need to return *something* as null means no store
72 } 56 }
73 57 return data;
74 // send the class to the decompiler
75 out.reset(data.length);
76 System.arraycopy(data, 0, out.array(), out.position(), data.length);
77 out.position(0);
78 return true;
79 } 58 }
80 59
81 private byte[] loadType(String className) { 60 private byte[] loadType(String className) {
@@ -131,10 +110,12 @@ public class TranslatingTypeLoader implements ITypeLoader {
131 return null; 110 return null;
132 } 111 }
133 112
113 @Override
134 public List<String> getClassNamesToTry(String className) { 114 public List<String> getClassNamesToTry(String className) {
135 return getClassNamesToTry(this.obfuscatingTranslator.getTranslatedClass(new ClassEntry(className))); 115 return getClassNamesToTry(this.obfuscatingTranslator.getTranslatedClass(new ClassEntry(className)));
136 } 116 }
137 117
118 @Override
138 public List<String> getClassNamesToTry(ClassEntry obfClassEntry) { 119 public List<String> getClassNamesToTry(ClassEntry obfClassEntry) {
139 List<String> classNamesToTry = Lists.newArrayList(); 120 List<String> classNamesToTry = Lists.newArrayList();
140 classNamesToTry.add(obfClassEntry.getName()); 121 classNamesToTry.add(obfClassEntry.getName());
@@ -145,8 +126,10 @@ public class TranslatingTypeLoader implements ITypeLoader {
145 return classNamesToTry; 126 return classNamesToTry;
146 } 127 }
147 128
129 @Override
148 public String transformInto(ClassNode node, ClassWriter writer) { 130 public String transformInto(ClassNode node, ClassWriter writer) {
149 node.accept(new TranslationClassVisitor(deobfuscatingTranslator, jarIndex, entryPool, Opcodes.ASM5, writer)); 131 node.accept(new TranslationClassVisitor(deobfuscatingTranslator, jarIndex, entryPool, Opcodes.ASM5, writer));
150 return deobfuscatingTranslator.getTranslatedClass(new ClassEntry(node.name)).getName(); 132 return deobfuscatingTranslator.getTranslatedClass(new ClassEntry(node.name)).getName();
151 } 133 }
134
152} 135}
diff --git a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java
index 928c6d19..e66b085f 100644
--- a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java
+++ b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java
@@ -3,12 +3,14 @@ package cuchaz.enigma.bytecode.translators;
3import org.objectweb.asm.Opcodes; 3import org.objectweb.asm.Opcodes;
4import org.objectweb.asm.signature.SignatureVisitor; 4import org.objectweb.asm.signature.SignatureVisitor;
5 5
6import java.util.Stack;
6import java.util.function.Function; 7import java.util.function.Function;
7 8
8public class TranslationSignatureVisitor extends SignatureVisitor { 9public class TranslationSignatureVisitor extends SignatureVisitor {
9 private final Function<String, String> remapper; 10 private final Function<String, String> remapper;
10 11
11 private final SignatureVisitor sv; 12 private final SignatureVisitor sv;
13 private final Stack<String> classStack = new Stack<>();
12 14
13 public TranslationSignatureVisitor(Function<String, String> remapper, SignatureVisitor sv) { 15 public TranslationSignatureVisitor(Function<String, String> remapper, SignatureVisitor sv) {
14 super(Opcodes.ASM5); 16 super(Opcodes.ASM5);
@@ -18,13 +20,24 @@ public class TranslationSignatureVisitor extends SignatureVisitor {
18 20
19 @Override 21 @Override
20 public void visitClassType(String name) { 22 public void visitClassType(String name) {
23 classStack.push(name);
21 String translatedEntry = this.remapper.apply(name); 24 String translatedEntry = this.remapper.apply(name);
22 this.sv.visitClassType(translatedEntry); 25 this.sv.visitClassType(translatedEntry);
23 } 26 }
24 27
25 @Override 28 @Override
26 public void visitInnerClassType(String name) { 29 public void visitInnerClassType(String name) {
30 String lastClass = classStack.pop();
31 if (!name.startsWith(lastClass+"$")){//todo see if there's a way to base this on whether there were type params or not
32 name = lastClass+"$"+name;
33 }
27 String translatedEntry = this.remapper.apply(name); 34 String translatedEntry = this.remapper.apply(name);
35 if (translatedEntry.contains("/")){
36 translatedEntry = translatedEntry.substring(translatedEntry.lastIndexOf("/")+1);
37 }
38 if (translatedEntry.contains("$")){
39 translatedEntry = translatedEntry.substring(translatedEntry.lastIndexOf("$")+1);
40 }
28 this.sv.visitInnerClassType(translatedEntry); 41 this.sv.visitInnerClassType(translatedEntry);
29 } 42 }
30 43
@@ -105,6 +118,8 @@ public class TranslationSignatureVisitor extends SignatureVisitor {
105 @Override 118 @Override
106 public void visitEnd() { 119 public void visitEnd() {
107 this.sv.visitEnd(); 120 this.sv.visitEnd();
121 if (!classStack.empty())
122 classStack.pop();
108 } 123 }
109 124
110 @Override 125 @Override