diff options
Diffstat (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java')
| -rw-r--r-- | src/main/java/cuchaz/enigma/Deobfuscator.java | 69 |
1 files changed, 55 insertions, 14 deletions
diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index 5980f1f..0c67158 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; | |||
| 15 | import com.google.common.collect.Lists; | 15 | import com.google.common.collect.Lists; |
| 16 | import com.google.common.collect.Maps; | 16 | import com.google.common.collect.Maps; |
| 17 | import com.google.common.collect.Sets; | 17 | import com.google.common.collect.Sets; |
| 18 | import com.strobel.assembler.metadata.ITypeLoader; | ||
| 18 | import com.strobel.assembler.metadata.MetadataSystem; | 19 | import com.strobel.assembler.metadata.MetadataSystem; |
| 19 | import com.strobel.assembler.metadata.TypeDefinition; | 20 | import com.strobel.assembler.metadata.TypeDefinition; |
| 20 | import com.strobel.assembler.metadata.TypeReference; | 21 | import com.strobel.assembler.metadata.TypeReference; |
| @@ -33,14 +34,18 @@ import cuchaz.enigma.mapping.*; | |||
| 33 | import cuchaz.enigma.mapping.entry.*; | 34 | import cuchaz.enigma.mapping.entry.*; |
| 34 | import cuchaz.enigma.throwables.IllegalNameException; | 35 | import cuchaz.enigma.throwables.IllegalNameException; |
| 35 | import cuchaz.enigma.utils.Utils; | 36 | import cuchaz.enigma.utils.Utils; |
| 37 | import oml.ast.transformers.InvalidIdentifierFix; | ||
| 38 | import oml.ast.transformers.Java8Generics; | ||
| 36 | import oml.ast.transformers.ObfuscatedEnumSwitchRewriterTransform; | 39 | import oml.ast.transformers.ObfuscatedEnumSwitchRewriterTransform; |
| 37 | import oml.ast.transformers.RemoveObjectCasts; | 40 | import oml.ast.transformers.RemoveObjectCasts; |
| 41 | import oml.ast.transformers.VarargsFixer; | ||
| 38 | import org.objectweb.asm.ClassWriter; | 42 | import org.objectweb.asm.ClassWriter; |
| 39 | import org.objectweb.asm.Opcodes; | 43 | import org.objectweb.asm.Opcodes; |
| 40 | import org.objectweb.asm.tree.ClassNode; | 44 | import org.objectweb.asm.tree.ClassNode; |
| 41 | 45 | ||
| 42 | import java.io.*; | 46 | import java.io.*; |
| 43 | import java.util.*; | 47 | import java.util.*; |
| 48 | import java.util.concurrent.ConcurrentHashMap; | ||
| 44 | import java.util.concurrent.atomic.AtomicInteger; | 49 | import java.util.concurrent.atomic.AtomicInteger; |
| 45 | import java.util.jar.JarEntry; | 50 | import java.util.jar.JarEntry; |
| 46 | import java.util.jar.JarFile; | 51 | import java.util.jar.JarFile; |
| @@ -170,6 +175,10 @@ public class Deobfuscator { | |||
| 170 | } | 175 | } |
| 171 | 176 | ||
| 172 | public CompilationUnit getSourceTree(String className, ITranslatingTypeLoader loader) { | 177 | public CompilationUnit getSourceTree(String className, ITranslatingTypeLoader loader) { |
| 178 | return getSourceTree(className, loader, new NoRetryMetadataSystem(loader)); | ||
| 179 | } | ||
| 180 | |||
| 181 | public CompilationUnit getSourceTree(String className, ITranslatingTypeLoader loader, MetadataSystem metadataSystem) { | ||
| 173 | 182 | ||
| 174 | // we don't know if this class name is obfuscated or deobfuscated | 183 | // we don't know if this class name is obfuscated or deobfuscated |
| 175 | // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out | 184 | // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out |
| @@ -188,7 +197,7 @@ public class Deobfuscator { | |||
| 188 | this.settings.setTypeLoader(loader); | 197 | this.settings.setTypeLoader(loader); |
| 189 | 198 | ||
| 190 | // see if procyon can find the desc | 199 | // see if procyon can find the desc |
| 191 | TypeReference type = new MetadataSystem(loader).lookupType(deobfClassName); | 200 | TypeReference type = metadataSystem.lookupType(deobfClassName); |
| 192 | if (type == null) { | 201 | if (type == null) { |
| 193 | throw new Error(String.format("Unable to find desc: %s (deobf: %s)\nTried class names: %s", | 202 | throw new Error(String.format("Unable to find desc: %s (deobf: %s)\nTried class names: %s", |
| 194 | className, deobfClassName, loader.getClassNamesToTry(deobfClassName) | 203 | className, deobfClassName, loader.getClassNamesToTry(deobfClassName) |
| @@ -278,6 +287,9 @@ public class Deobfuscator { | |||
| 278 | //synchronized to make sure the parallelStream doesn't CME with the cache | 287 | //synchronized to make sure the parallelStream doesn't CME with the cache |
| 279 | ITranslatingTypeLoader typeLoader = new SynchronizedTypeLoader(createTypeLoader()); | 288 | ITranslatingTypeLoader typeLoader = new SynchronizedTypeLoader(createTypeLoader()); |
| 280 | 289 | ||
| 290 | MetadataSystem metadataSystem = new NoRetryMetadataSystem(typeLoader); | ||
| 291 | metadataSystem.setEagerMethodLoadingEnabled(true);//ensures methods are loaded on classload and prevents race conditions | ||
| 292 | |||
| 281 | // DEOBFUSCATE ALL THE THINGS!! @_@ | 293 | // DEOBFUSCATE ALL THE THINGS!! @_@ |
| 282 | Stopwatch stopwatch = Stopwatch.createStarted(); | 294 | Stopwatch stopwatch = Stopwatch.createStarted(); |
| 283 | AtomicInteger count = new AtomicInteger(); | 295 | AtomicInteger count = new AtomicInteger(); |
| @@ -289,7 +301,7 @@ public class Deobfuscator { | |||
| 289 | 301 | ||
| 290 | try { | 302 | try { |
| 291 | // get the source | 303 | // get the source |
| 292 | CompilationUnit sourceTree = getSourceTree(obfClassEntry.getName(), typeLoader); | 304 | CompilationUnit sourceTree = getSourceTree(obfClassEntry.getName(), typeLoader, metadataSystem); |
| 293 | 305 | ||
| 294 | // write the file | 306 | // write the file |
| 295 | File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java"); | 307 | File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java"); |
| @@ -355,28 +367,28 @@ public class Deobfuscator { | |||
| 355 | } | 367 | } |
| 356 | 368 | ||
| 357 | public void rebuildMethodNames(ProgressListener progress) { | 369 | public void rebuildMethodNames(ProgressListener progress) { |
| 358 | int i = 0; | 370 | final AtomicInteger i = new AtomicInteger(); |
| 359 | Map<ClassMapping, Map<Entry, String>> renameClassMap = new HashMap<>(); | 371 | Map<ClassMapping, Map<Entry, String>> renameClassMap = new HashMap<>(); |
| 360 | 372 | ||
| 361 | progress.init(getMappings().classes().size() * 3, "Rebuilding method names"); | 373 | progress.init(getMappings().classes().size() * 3, "Rebuilding method names"); |
| 362 | 374 | ||
| 363 | for (ClassMapping classMapping : Lists.newArrayList(getMappings().classes())) { | 375 | Lists.newArrayList(getMappings().classes()).parallelStream().forEach(classMapping -> { |
| 364 | progress.onProgress(i++, classMapping.getDeobfName()); | 376 | progress.onProgress(i.getAndIncrement(), classMapping.getDeobfName()); |
| 365 | rebuildMethodNames(classMapping, renameClassMap); | 377 | rebuildMethodNames(classMapping, renameClassMap); |
| 366 | } | 378 | }); |
| 367 | 379 | ||
| 368 | for (Map.Entry<ClassMapping, Map<Entry, String>> renameClassMapEntry : renameClassMap.entrySet()) { | ||
| 369 | progress.onProgress(i++, renameClassMapEntry.getKey().getDeobfName()); | ||
| 370 | 380 | ||
| 381 | renameClassMap.entrySet().parallelStream().forEach(renameClassMapEntry -> { | ||
| 382 | progress.onProgress(i.getAndIncrement(), renameClassMapEntry.getKey().getDeobfName()); | ||
| 371 | for (Map.Entry<Entry, String> entry : renameClassMapEntry.getValue().entrySet()) { | 383 | for (Map.Entry<Entry, String> entry : renameClassMapEntry.getValue().entrySet()) { |
| 372 | Entry obfEntry = entry.getKey(); | 384 | Entry obfEntry = entry.getKey(); |
| 373 | 385 | ||
| 374 | removeMapping(obfEntry); | 386 | removeMapping(obfEntry); |
| 375 | } | 387 | } |
| 376 | } | 388 | }); |
| 377 | 389 | ||
| 378 | for (Map.Entry<ClassMapping, Map<Entry, String>> renameClassMapEntry : renameClassMap.entrySet()) { | 390 | renameClassMap.entrySet().parallelStream().forEach(renameClassMapEntry -> { |
| 379 | progress.onProgress(i++, renameClassMapEntry.getKey().getDeobfName()); | 391 | progress.onProgress(i.getAndIncrement(), renameClassMapEntry.getKey().getDeobfName()); |
| 380 | 392 | ||
| 381 | for (Map.Entry<Entry, String> entry : renameClassMapEntry.getValue().entrySet()) { | 393 | for (Map.Entry<Entry, String> entry : renameClassMapEntry.getValue().entrySet()) { |
| 382 | Entry obfEntry = entry.getKey(); | 394 | Entry obfEntry = entry.getKey(); |
| @@ -390,7 +402,7 @@ public class Deobfuscator { | |||
| 390 | } | 402 | } |
| 391 | } | 403 | } |
| 392 | } | 404 | } |
| 393 | } | 405 | }); |
| 394 | } | 406 | } |
| 395 | 407 | ||
| 396 | private void rebuildMethodNames(ClassMapping classMapping, Map<ClassMapping, Map<Entry, String>> renameClassMap) { | 408 | private void rebuildMethodNames(ClassMapping classMapping, Map<ClassMapping, Map<Entry, String>> renameClassMap) { |
| @@ -680,9 +692,12 @@ public class Deobfuscator { | |||
| 680 | public static void runCustomTransforms(AstBuilder builder, DecompilerContext context){ | 692 | public static void runCustomTransforms(AstBuilder builder, DecompilerContext context){ |
| 681 | List<IAstTransform> transformers = Arrays.asList( | 693 | List<IAstTransform> transformers = Arrays.asList( |
| 682 | new ObfuscatedEnumSwitchRewriterTransform(context), | 694 | new ObfuscatedEnumSwitchRewriterTransform(context), |
| 683 | new RemoveObjectCasts(context) | 695 | new VarargsFixer(context), |
| 696 | new RemoveObjectCasts(context), | ||
| 697 | new Java8Generics(), | ||
| 698 | new InvalidIdentifierFix() | ||
| 684 | ); | 699 | ); |
| 685 | for (IAstTransform transform : transformers){ | 700 | for (IAstTransform transform : transformers) { |
| 686 | transform.run(builder.getCompilationUnit()); | 701 | transform.run(builder.getCompilationUnit()); |
| 687 | } | 702 | } |
| 688 | } | 703 | } |
| @@ -697,4 +712,30 @@ public class Deobfuscator { | |||
| 697 | String transform(ClassNode node, ClassWriter writer); | 712 | String transform(ClassNode node, ClassWriter writer); |
| 698 | } | 713 | } |
| 699 | 714 | ||
| 715 | public static class NoRetryMetadataSystem extends MetadataSystem { | ||
| 716 | private final Set<String> _failedTypes = Collections.newSetFromMap(new ConcurrentHashMap<>()); | ||
| 717 | |||
| 718 | public NoRetryMetadataSystem(final ITypeLoader typeLoader) { | ||
| 719 | super(typeLoader); | ||
| 720 | } | ||
| 721 | |||
| 722 | @Override | ||
| 723 | protected synchronized TypeDefinition resolveType(final String descriptor, final boolean mightBePrimitive) { | ||
| 724 | if (_failedTypes.contains(descriptor)) { | ||
| 725 | return null; | ||
| 726 | } | ||
| 727 | |||
| 728 | final TypeDefinition result = super.resolveType(descriptor, mightBePrimitive); | ||
| 729 | |||
| 730 | if (result == null) { | ||
| 731 | _failedTypes.add(descriptor); | ||
| 732 | } | ||
| 733 | |||
| 734 | return result; | ||
| 735 | } | ||
| 736 | |||
| 737 | public synchronized TypeDefinition resolve(final TypeReference type) { | ||
| 738 | return super.resolve(type); | ||
| 739 | } | ||
| 740 | } | ||
| 700 | } | 741 | } |