summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Thiakil2018-07-06 13:03:02 +0800
committerGravatar Thiakil2018-07-06 13:03:02 +0800
commit027d79e46569321d7fe2d1049a512bf59370a47f (patch)
tree20e8b9b7d5bd00f28f001411da57697ac7324401
parentmake isMethodProvider public (diff)
downloadenigma-027d79e46569321d7fe2d1049a512bf59370a47f.tar.gz
enigma-027d79e46569321d7fe2d1049a512bf59370a47f.tar.xz
enigma-027d79e46569321d7fe2d1049a512bf59370a47f.zip
speed up Deobfuscator's getSources by using a single TranslatingTypeloader and caching the ClassLoaderTypeloader
-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.java42
-rw-r--r--src/main/java/cuchaz/enigma/ITranslatingTypeLoader.java19
-rw-r--r--src/main/java/cuchaz/enigma/TranslatingTypeLoader.java47
5 files changed, 131 insertions, 35 deletions
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..cb02ffab 100644
--- a/src/main/java/cuchaz/enigma/Deobfuscator.java
+++ b/src/main/java/cuchaz/enigma/Deobfuscator.java
@@ -15,6 +15,7 @@ import com.google.common.base.Stopwatch;
15import com.google.common.collect.Lists; 15import com.google.common.collect.Lists;
16import com.google.common.collect.Maps; 16import com.google.common.collect.Maps;
17import com.google.common.collect.Sets; 17import com.google.common.collect.Sets;
18import com.strobel.assembler.metadata.Buffer;
18import com.strobel.assembler.metadata.MetadataSystem; 19import com.strobel.assembler.metadata.MetadataSystem;
19import com.strobel.assembler.metadata.TypeDefinition; 20import com.strobel.assembler.metadata.TypeDefinition;
20import com.strobel.assembler.metadata.TypeReference; 21import com.strobel.assembler.metadata.TypeReference;
@@ -163,6 +164,10 @@ public class Deobfuscator {
163 } 164 }
164 165
165 public CompilationUnit getSourceTree(String className) { 166 public CompilationUnit getSourceTree(String className) {
167 return getSourceTree(className, createTypeLoader());
168 }
169
170 public CompilationUnit getSourceTree(String className, ITranslatingTypeLoader loader) {
166 171
167 // we don't know if this class name is obfuscated or deobfuscated 172 // 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 173 // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out
@@ -178,7 +183,6 @@ public class Deobfuscator {
178 } 183 }
179 184
180 // set the desc loader 185 // set the desc loader
181 TranslatingTypeLoader loader = createTypeLoader();
182 this.settings.setTypeLoader(loader); 186 this.settings.setTypeLoader(loader);
183 187
184 // see if procyon can find the desc 188 // see if procyon can find the desc
@@ -267,6 +271,10 @@ public class Deobfuscator {
267 progress.init(classEntries.size(), "Decompiling classes..."); 271 progress.init(classEntries.size(), "Decompiling classes...");
268 } 272 }
269 273
274 //create a common instance outside the loop as mappings shouldn't be changing while this is happening
275 //synchronized to make sure the parallelStream doesn't CME with the cache
276 ITranslatingTypeLoader typeLoader = new SynchronizedTypeLoader(createTypeLoader());
277
270 // DEOBFUSCATE ALL THE THINGS!! @_@ 278 // DEOBFUSCATE ALL THE THINGS!! @_@
271 Stopwatch stopwatch = Stopwatch.createStarted(); 279 Stopwatch stopwatch = Stopwatch.createStarted();
272 AtomicInteger count = new AtomicInteger(); 280 AtomicInteger count = new AtomicInteger();
@@ -278,7 +286,7 @@ public class Deobfuscator {
278 286
279 try { 287 try {
280 // get the source 288 // get the source
281 CompilationUnit sourceTree = getSourceTree(obfClassEntry.getName()); 289 CompilationUnit sourceTree = getSourceTree(obfClassEntry.getName(), typeLoader);
282 290
283 // write the file 291 // write the file
284 File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java"); 292 File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java");
@@ -295,7 +303,7 @@ public class Deobfuscator {
295 } 303 }
296 }); 304 });
297 stopwatch.stop(); 305 stopwatch.stop();
298 System.out.println("Done in : " + stopwatch.toString()); 306 System.out.println("writeSources Done in : " + stopwatch.toString());
299 if (progress != null) { 307 if (progress != null) {
300 progress.onProgress(count.get(), "Done:"); 308 progress.onProgress(count.get(), "Done:");
301 } 309 }
@@ -658,4 +666,32 @@ public class Deobfuscator {
658 public interface ClassTransformer { 666 public interface ClassTransformer {
659 String transform(ClassNode node, ClassWriter writer); 667 String transform(ClassNode node, ClassWriter writer);
660 } 668 }
669
670 private class SynchronizedTypeLoader implements ITranslatingTypeLoader {
671 private final TranslatingTypeLoader delegate;
672
673 private SynchronizedTypeLoader(TranslatingTypeLoader delegate) {
674 this.delegate = delegate;
675 }
676
677 @Override
678 public List<String> getClassNamesToTry(String className) {
679 return delegate.getClassNamesToTry(className);
680 }
681
682 @Override
683 public List<String> getClassNamesToTry(ClassEntry obfClassEntry) {
684 return delegate.getClassNamesToTry(obfClassEntry);
685 }
686
687 @Override
688 public String transformInto(ClassNode node, ClassWriter writer) {
689 return delegate.transformInto(node, writer);
690 }
691
692 @Override
693 public synchronized boolean tryLoadType(String internalName, Buffer buffer) {
694 return delegate.tryLoadType(internalName, buffer);
695 }
696 }
661} 697}
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/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}