From 2b2249e873c4adfd2dd6e8f1f2489ccd9f6aa021 Mon Sep 17 00:00:00 2001 From: gegy1000 Date: Sat, 19 May 2018 17:02:46 +0200 Subject: Initial port to ASM --- src/main/java/cuchaz/enigma/Deobfuscator.java | 225 ++++++++++++++------------ 1 file changed, 119 insertions(+), 106 deletions(-) (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java') diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index 1e99af2..e1454c7 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java @@ -31,50 +31,55 @@ import cuchaz.enigma.bytecode.ClassPublifier; import cuchaz.enigma.mapping.*; import cuchaz.enigma.throwables.IllegalNameException; import cuchaz.enigma.utils.Utils; -import javassist.CtClass; -import javassist.bytecode.Descriptor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; import java.io.*; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarOutputStream; public class Deobfuscator { + private final ReferencedEntryPool entryPool = new ReferencedEntryPool(); private final JarFile jar; + private final ParsedJar parsedJar; private final DecompilerSettings settings; private final JarIndex jarIndex; private final MappingsRenamer renamer; private final Map translatorCache; private Mappings mappings; - public Deobfuscator(JarFile jar) { + public Deobfuscator(JarFile jar) throws IOException { this.jar = jar; + this.parsedJar = new ParsedJar(jar); // build the jar index - this.jarIndex = new JarIndex(); - this.jarIndex.indexJar(this.jar, true); + this.jarIndex = new JarIndex(entryPool); + this.jarIndex.indexJar(this.parsedJar, true); // config the decompiler this.settings = DecompilerSettings.javaDefaults(); this.settings.setMergeVariables(Utils.getSystemPropertyAsBoolean("enigma.mergeVariables", true)); this.settings.setForceExplicitImports(Utils.getSystemPropertyAsBoolean("enigma.forceExplicitImports", true)); this.settings.setForceExplicitTypeArguments( - Utils.getSystemPropertyAsBoolean("enigma.forceExplicitTypeArguments", true)); + Utils.getSystemPropertyAsBoolean("enigma.forceExplicitTypeArguments", true)); // DEBUG this.settings.setShowDebugLineNumbers(Utils.getSystemPropertyAsBoolean("enigma.showDebugLineNumbers", false)); this.settings.setShowSyntheticMembers(Utils.getSystemPropertyAsBoolean("enigma.showSyntheticMembers", false)); // init defaults this.translatorCache = Maps.newTreeMap(); - this.renamer = new MappingsRenamer(this.jarIndex, null); + this.renamer = new MappingsRenamer(this.jarIndex, null, this.entryPool); // init mappings setMappings(new Mappings()); } - public JarFile getJar() { - return this.jar; + public ParsedJar getJar() { + return this.parsedJar; } public String getJarName() { @@ -102,16 +107,16 @@ public class Deobfuscator { MappingsChecker checker = new MappingsChecker(this.jarIndex); checker.dropBrokenMappings(val); if (warnAboutDrops) { - for (java.util.Map.Entry mapping : checker.getDroppedClassMappings().entrySet()) { + for (Map.Entry mapping : checker.getDroppedClassMappings().entrySet()) { System.out.println("WARNING: Couldn't find class entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); } - for (java.util.Map.Entry mapping : checker.getDroppedInnerClassMappings().entrySet()) { + for (Map.Entry mapping : checker.getDroppedInnerClassMappings().entrySet()) { System.out.println("WARNING: Couldn't find inner class entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); } - for (java.util.Map.Entry mapping : checker.getDroppedFieldMappings().entrySet()) { + for (Map.Entry mapping : checker.getDroppedFieldMappings().entrySet()) { System.out.println("WARNING: Couldn't find field entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); } - for (java.util.Map.Entry mapping : checker.getDroppedMethodMappings().entrySet()) { + for (Map.Entry mapping : checker.getDroppedMethodMappings().entrySet()) { System.out.println("WARNING: Couldn't find behavior entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); } } @@ -123,7 +128,7 @@ public class Deobfuscator { public Translator getTranslator(TranslationDirection direction) { return this.translatorCache.computeIfAbsent(direction, - k -> this.mappings.getTranslator(direction, this.jarIndex.getTranslationIndex())); + k -> this.mappings.getTranslator(direction, this.jarIndex.getTranslationIndex())); } public void getSeparatedClasses(List obfClasses, List deobfClasses) { @@ -150,10 +155,11 @@ public class Deobfuscator { public TranslatingTypeLoader createTypeLoader() { return new TranslatingTypeLoader( - this.jar, - this.jarIndex, - getTranslator(TranslationDirection.Obfuscating), - getTranslator(TranslationDirection.Deobfuscating) + this.parsedJar, + this.jarIndex, + this.entryPool, + getTranslator(TranslationDirection.OBFUSCATING), + getTranslator(TranslationDirection.DEOBFUSCATING) ); } @@ -172,15 +178,15 @@ public class Deobfuscator { deobfClassName = classMapping.getDeobfName(); } - // set the type loader + // set the desc loader TranslatingTypeLoader loader = createTypeLoader(); this.settings.setTypeLoader(loader); - // see if procyon can find the type + // see if procyon can find the desc TypeReference type = new MetadataSystem(loader).lookupType(deobfClassName); if (type == null) { - throw new Error(String.format("Unable to find type: %s (deobf: %s)\nTried class names: %s", - className, deobfClassName, loader.getClassNamesToTry(deobfClassName) + throw new Error(String.format("Unable to find desc: %s (deobf: %s)\nTried class names: %s", + className, deobfClassName, loader.getClassNamesToTry(deobfClassName) )); } TypeDefinition resolvedType = type.resolve(); @@ -208,7 +214,7 @@ public class Deobfuscator { } else { index = new SourceIndex(source); } - sourceTree.acceptVisitor(new SourceIndexVisitor(), index); + sourceTree.acceptVisitor(new SourceIndexVisitor(entryPool), index); // DEBUG // sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); @@ -221,10 +227,10 @@ public class Deobfuscator { Entry obfEntry = obfuscateEntry(deobfReference.entry); // try to resolve the class - ClassEntry resolvedObfClassEntry = this.jarIndex.getTranslationIndex().resolveEntryClass(obfEntry); - if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(obfEntry.getClassEntry())) { + ClassEntry resolvedObfClassEntry = this.jarIndex.getTranslationIndex().resolveEntryOwner(obfEntry); + if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(obfEntry.getOwnerClassEntry())) { // change the class of the entry - obfEntry = obfEntry.cloneToNewClass(resolvedObfClassEntry); + obfEntry = obfEntry.updateOwnership(resolvedObfClassEntry); // save the new deobfuscated reference deobfReference.entry = deobfuscateEntry(obfEntry); @@ -305,18 +311,14 @@ public class Deobfuscator { } } - private boolean isBehaviorProvider(ClassEntry classObfEntry, BehaviorEntry behaviorEntry) { - if (behaviorEntry instanceof MethodEntry) { - MethodEntry methodEntry = (MethodEntry) behaviorEntry; + private boolean isMethodProvider(ClassEntry classObfEntry, MethodEntry methodEntry) { + Set classEntries = new HashSet<>(); + addAllPotentialAncestors(classEntries, classObfEntry); - Set classEntries = new HashSet<>(); - addAllPotentialAncestors(classEntries, classObfEntry); - - for (ClassEntry parentEntry : classEntries) { - MethodEntry ancestorMethodEntry = new MethodEntry(parentEntry, methodEntry.getName(), methodEntry.getSignature()); - if (jarIndex.containsObfBehavior(ancestorMethodEntry)) { - return false; - } + for (ClassEntry parentEntry : classEntries) { + MethodEntry ancestorMethodEntry = entryPool.getMethod(parentEntry, methodEntry.getName(), methodEntry.getDesc()); + if (jarIndex.containsObfMethod(ancestorMethodEntry)) { + return false; } } @@ -332,7 +334,7 @@ public class Deobfuscator { for (ClassMapping classMapping : Lists.newArrayList(getMappings().classes())) { progress.onProgress(i++, classMapping.getDeobfName()); rebuildMethodNames(classMapping, renameClassMap); - for(ClassMapping innerClass : classMapping.innerClasses()){ + for (ClassMapping innerClass : classMapping.innerClasses()) { rebuildMethodNames(innerClass, renameClassMap); } } @@ -356,29 +358,29 @@ public class Deobfuscator { try { rename(obfEntry, name); - } catch (IllegalNameException exception) - { + } catch (IllegalNameException exception) { System.out.println("WARNING: " + exception.getMessage()); } } } } - private void rebuildMethodNames(ClassMapping classMapping, Map> renameClassMap){ + private void rebuildMethodNames(ClassMapping classMapping, Map> renameClassMap) { Map renameEntries = new HashMap<>(); for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) { ClassEntry classObfEntry = classMapping.getObfEntry(); - BehaviorEntry obfEntry = methodMapping.getObfEntry(classObfEntry); + MethodEntry obfEntry = methodMapping.getObfEntry(classObfEntry); - if (isBehaviorProvider(classObfEntry, obfEntry)) { - if (hasDeobfuscatedName(obfEntry) && !(obfEntry instanceof ConstructorEntry) - && !(methodMapping.getDeobfName().equals(methodMapping.getObfName()))) { + if (isMethodProvider(classObfEntry, obfEntry)) { + if (hasDeobfuscatedName(obfEntry) + && !(methodMapping.getDeobfName().equals(methodMapping.getObfName()))) { renameEntries.put(obfEntry, methodMapping.getDeobfName()); } - for (ArgumentMapping argumentMapping : Lists.newArrayList(methodMapping.arguments())) { - Entry argObfEntry = argumentMapping.getObfEntry(obfEntry); + ArrayList arguments = Lists.newArrayList(methodMapping.arguments()); + for (LocalVariableMapping localVariableMapping : arguments) { + Entry argObfEntry = localVariableMapping.getObfEntry(obfEntry); if (hasDeobfuscatedName(argObfEntry)) { renameEntries.put(argObfEntry, deobfuscateEntry(argObfEntry).getName()); } @@ -390,45 +392,44 @@ public class Deobfuscator { } - public void writeJar(File out, ProgressListener progress) { - transformJar(out, progress, createTypeLoader()::transformClass); + transformJar(out, progress, createTypeLoader()::createTransformer); } public void protectifyJar(File out, ProgressListener progress) { - transformJar(out, progress, ClassProtectifier::protectify); + transformJar(out, progress, (node, writer) -> node.accept(new ClassProtectifier(Opcodes.ASM5, writer))); } public void publifyJar(File out, ProgressListener progress) { - transformJar(out, progress, ClassPublifier::publify); + transformJar(out, progress, (node, writer) -> node.accept(new ClassPublifier(Opcodes.ASM5, writer))); } public void transformJar(File out, ProgressListener progress, ClassTransformer transformer) { try (JarOutputStream outJar = new JarOutputStream(new FileOutputStream(out))) { if (progress != null) { - progress.init(JarClassIterator.getClassEntries(this.jar).size(), "Transforming classes..."); + progress.init(parsedJar.getClassCount(), "Transforming classes..."); } - int i = 0; - for (CtClass c : JarClassIterator.classes(this.jar)) { + AtomicInteger i = new AtomicInteger(); + parsedJar.visit(node -> { if (progress != null) { - progress.onProgress(i++, c.getName()); + progress.onProgress(i.getAndIncrement(), node.name); } try { - c = transformer.transform(c); - outJar.putNextEntry(new JarEntry(c.getName().replace('.', '/') + ".class")); - outJar.write(c.toBytecode()); + ClassWriter writer = new ClassWriter(0); + transformer.write(node, writer); + outJar.putNextEntry(new JarEntry(node.name.replace('.', '/') + ".class")); + outJar.write(writer.toByteArray()); outJar.closeEntry(); } catch (Throwable t) { - throw new Error("Unable to transform class " + c.getName(), t); + throw new Error("Unable to transform class " + node.name, t); } - } + }); + if (progress != null) { - progress.onProgress(i, "Done!"); + progress.onProgress(i.get(), "Done!"); } - - outJar.close(); } catch (IOException ex) { throw new Error("Unable to write to Jar file!"); } @@ -438,14 +439,22 @@ public class Deobfuscator { if (deobfEntry == null) { return null; } - return getTranslator(TranslationDirection.Obfuscating).translateEntry(deobfEntry); + T translatedEntry = getTranslator(TranslationDirection.OBFUSCATING).getTranslatedEntry(deobfEntry); + if (translatedEntry == null) { + return deobfEntry; + } + return translatedEntry; } public T deobfuscateEntry(T obfEntry) { if (obfEntry == null) { return null; } - return getTranslator(TranslationDirection.Deobfuscating).translateEntry(obfEntry); + T translatedEntry = getTranslator(TranslationDirection.DEOBFUSCATING).getTranslatedEntry(obfEntry); + if (translatedEntry == null) { + return obfEntry; + } + return translatedEntry; } public EntryReference obfuscateReference(EntryReference deobfReference) { @@ -473,7 +482,7 @@ public class Deobfuscator { // HACKHACK: Object methods are not obfuscated identifiers MethodEntry obfMethodEntry = (MethodEntry) obfEntry; String name = obfMethodEntry.getName(); - String sig = obfMethodEntry.getSignature().toString(); + String sig = obfMethodEntry.getDesc().toString(); if (name.equals("clone") && sig.equals("()Ljava/lang/Object;")) { return false; } else if (name.equals("equals") && sig.equals("(Ljava/lang/Object;)Z")) { @@ -499,7 +508,7 @@ public class Deobfuscator { } // FIXME: HACK EVEN MORE HACK! - if (hack && this.jarIndex.containsObfEntry(obfEntry.getClassEntry())) + if (hack && this.jarIndex.containsObfEntry(obfEntry.getOwnerClassEntry())) return true; } @@ -515,27 +524,24 @@ public class Deobfuscator { } public boolean hasDeobfuscatedName(Entry obfEntry) { - Translator translator = getTranslator(TranslationDirection.Deobfuscating); + Translator translator = getTranslator(TranslationDirection.DEOBFUSCATING); if (obfEntry instanceof ClassEntry) { ClassEntry obfClass = (ClassEntry) obfEntry; List mappingChain = this.mappings.getClassMappingChain(obfClass); ClassMapping classMapping = mappingChain.get(mappingChain.size() - 1); return classMapping != null && classMapping.getDeobfName() != null; } else if (obfEntry instanceof FieldEntry) { - return translator.translate((FieldEntry) obfEntry) != null; + return translator.getTranslatedField((FieldEntry) obfEntry) != null; } else if (obfEntry instanceof MethodEntry) { - return translator.translate((MethodEntry) obfEntry) != null; - } else if (obfEntry instanceof ConstructorEntry) { - // constructors have no names - return false; - } else if (obfEntry instanceof ArgumentEntry) { - return translator.translate((ArgumentEntry) obfEntry) != null; + MethodEntry methodEntry = (MethodEntry) obfEntry; + if (methodEntry.isConstructor()) { + return false; + } + return translator.getTranslatedMethod(methodEntry) != null; } else if (obfEntry instanceof LocalVariableEntry) { - // TODO: Implement it - //return translator.translate((LocalVariableEntry)obfEntry) != null; - return false; + return translator.getTranslatedVariable((LocalVariableEntry) obfEntry) != null; } else { - throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); + throw new Error("Unknown entry desc: " + obfEntry.getClass().getName()); } } @@ -547,19 +553,18 @@ public class Deobfuscator { public void rename(Entry obfEntry, String newName, boolean clearCache) { if (obfEntry instanceof ClassEntry) { - this.renamer.setClassName((ClassEntry) obfEntry, Descriptor.toJvmName(newName)); + this.renamer.setClassName((ClassEntry) obfEntry, newName); } else if (obfEntry instanceof FieldEntry) { this.renamer.setFieldName((FieldEntry) obfEntry, newName); } else if (obfEntry instanceof MethodEntry) { + if (((MethodEntry) obfEntry).isConstructor()) { + throw new IllegalArgumentException("Cannot rename constructors"); + } this.renamer.setMethodTreeName((MethodEntry) obfEntry, newName); - } else if (obfEntry instanceof ConstructorEntry) { - throw new IllegalArgumentException("Cannot rename constructors"); - } else if (obfEntry instanceof ArgumentEntry) { - this.renamer.setArgumentTreeName((ArgumentEntry) obfEntry, newName); } else if (obfEntry instanceof LocalVariableEntry) { - // TODO: Implement it + this.renamer.setLocalVariableTreeName((LocalVariableEntry) obfEntry, newName); } else { - throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); + throw new Error("Unknown entry desc: " + obfEntry.getClass().getName()); } // clear caches @@ -573,13 +578,14 @@ public class Deobfuscator { } else if (obfEntry instanceof FieldEntry) { this.renamer.removeFieldMapping((FieldEntry) obfEntry); } else if (obfEntry instanceof MethodEntry) { + if (((MethodEntry) obfEntry).isConstructor()) { + throw new IllegalArgumentException("Cannot rename constructors"); + } this.renamer.removeMethodTreeMapping((MethodEntry) obfEntry); - } else if (obfEntry instanceof ConstructorEntry) { - throw new IllegalArgumentException("Cannot rename constructors"); - } else if (obfEntry instanceof ArgumentEntry) { - this.renamer.removeArgumentMapping((ArgumentEntry) obfEntry); + } else if (obfEntry instanceof LocalVariableEntry) { + this.renamer.removeLocalVariableMapping((LocalVariableEntry) obfEntry); } else { - throw new Error("Unknown entry type: " + obfEntry); + throw new Error("Unknown entry desc: " + obfEntry); } // clear caches @@ -592,15 +598,15 @@ public class Deobfuscator { } else if (obfEntry instanceof FieldEntry) { this.renamer.markFieldAsDeobfuscated((FieldEntry) obfEntry); } else if (obfEntry instanceof MethodEntry) { - this.renamer.markMethodTreeAsDeobfuscated((MethodEntry) obfEntry); - } else if (obfEntry instanceof ConstructorEntry) { - throw new IllegalArgumentException("Cannot rename constructors"); - } else if (obfEntry instanceof ArgumentEntry) { - this.renamer.markArgumentAsDeobfuscated((ArgumentEntry) obfEntry); + MethodEntry methodEntry = (MethodEntry) obfEntry; + if (methodEntry.isConstructor()) { + throw new IllegalArgumentException("Cannot rename constructors"); + } + this.renamer.markMethodTreeAsDeobfuscated(methodEntry); } else if (obfEntry instanceof LocalVariableEntry) { - // TODO: Implement it + this.renamer.markArgumentAsDeobfuscated((LocalVariableEntry) obfEntry); } else { - throw new Error("Unknown entry type: " + obfEntry); + throw new Error("Unknown entry desc: " + obfEntry); } // clear caches @@ -613,17 +619,24 @@ public class Deobfuscator { this.renamer.setClassModifier((ClassEntry) obfEntry, modifierEntry); else if (obfEntry instanceof FieldEntry) this.renamer.setFieldModifier((FieldEntry) obfEntry, modifierEntry); - else if (obfEntry instanceof BehaviorEntry) - this.renamer.setMethodModifier((BehaviorEntry) obfEntry, modifierEntry); + else if (obfEntry instanceof MethodEntry) + this.renamer.setMethodModifier((MethodEntry) obfEntry, modifierEntry); else - throw new Error("Unknown entry type: " + obfEntry); + throw new Error("Unknown entry desc: " + obfEntry); } - public Mappings.EntryModifier getModifier(Entry obEntry) { - Entry entry = obfuscateEntry(obEntry); + public Mappings.EntryModifier getModifier(Entry obfEntry) { + Entry entry = obfuscateEntry(obfEntry); if (entry != null) - obEntry = entry; - return getTranslator(TranslationDirection.Deobfuscating).getModifier(obEntry); + obfEntry = entry; + if (obfEntry instanceof ClassEntry) + return this.renamer.getClassModifier((ClassEntry) obfEntry); + else if (obfEntry instanceof FieldEntry) + return this.renamer.getFieldModifier((FieldEntry) obfEntry); + else if (obfEntry instanceof MethodEntry) + return this.renamer.getMethodModfifier((MethodEntry) obfEntry); + else + throw new Error("Unknown entry desc: " + obfEntry); } public interface ProgressListener { @@ -633,6 +646,6 @@ public class Deobfuscator { } public interface ClassTransformer { - CtClass transform(CtClass c) throws Exception; + void write(ClassNode node, ClassWriter writer); } } -- cgit v1.2.3 From 406b9a89318473571d27de60b8aa1b51f84af245 Mon Sep 17 00:00:00 2001 From: gegy1000 Date: Sat, 19 May 2018 17:06:26 +0200 Subject: Package updates --- src/main/java/cuchaz/enigma/Deobfuscator.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java') diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index e1454c7..3433ca9 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java @@ -29,6 +29,7 @@ import cuchaz.enigma.analysis.*; import cuchaz.enigma.bytecode.ClassProtectifier; import cuchaz.enigma.bytecode.ClassPublifier; import cuchaz.enigma.mapping.*; +import cuchaz.enigma.mapping.entry.*; import cuchaz.enigma.throwables.IllegalNameException; import cuchaz.enigma.utils.Utils; import org.objectweb.asm.ClassWriter; -- cgit v1.2.3 From 227ccb35a48529724ecf28c94a9156af2f699481 Mon Sep 17 00:00:00 2001 From: gegy1000 Date: Sat, 19 May 2018 20:00:12 +0200 Subject: More bytecode translation --- src/main/java/cuchaz/enigma/Deobfuscator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java') diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index 3433ca9..cb03d45 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java @@ -532,15 +532,15 @@ public class Deobfuscator { ClassMapping classMapping = mappingChain.get(mappingChain.size() - 1); return classMapping != null && classMapping.getDeobfName() != null; } else if (obfEntry instanceof FieldEntry) { - return translator.getTranslatedField((FieldEntry) obfEntry) != null; + return translator.hasFieldMapping((FieldEntry) obfEntry); } else if (obfEntry instanceof MethodEntry) { MethodEntry methodEntry = (MethodEntry) obfEntry; if (methodEntry.isConstructor()) { return false; } - return translator.getTranslatedMethod(methodEntry) != null; + return translator.hasMethodMapping(methodEntry); } else if (obfEntry instanceof LocalVariableEntry) { - return translator.getTranslatedVariable((LocalVariableEntry) obfEntry) != null; + return translator.hasLocalVariableMapping((LocalVariableEntry) obfEntry); } else { throw new Error("Unknown entry desc: " + obfEntry.getClass().getName()); } -- cgit v1.2.3 From 2ea0c243fd3ceed585a514dd487ce04866c8aede Mon Sep 17 00:00:00 2001 From: gegy1000 Date: Sun, 20 May 2018 12:41:44 +0200 Subject: Fix anonymous class generation --- src/main/java/cuchaz/enigma/Deobfuscator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java') diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index cb03d45..cf5d061 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java @@ -284,7 +284,7 @@ public class Deobfuscator { // write the file File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java"); file.getParentFile().mkdirs(); - try (OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8)) { + try (OutputStreamWriter out = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(file)), Charsets.UTF_8)) { out.write(source); } } catch (Throwable t) { -- cgit v1.2.3 From dbd881184fb4955b3ecd027b35b57258fd9f3480 Mon Sep 17 00:00:00 2001 From: gegy1000 Date: Thu, 21 Jun 2018 18:43:42 +0200 Subject: Fix issues with inner class signature transformation --- src/main/java/cuchaz/enigma/Deobfuscator.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java') diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index cf5d061..6bbfd07 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java @@ -335,9 +335,6 @@ public class Deobfuscator { for (ClassMapping classMapping : Lists.newArrayList(getMappings().classes())) { progress.onProgress(i++, classMapping.getDeobfName()); rebuildMethodNames(classMapping, renameClassMap); - for (ClassMapping innerClass : classMapping.innerClasses()) { - rebuildMethodNames(innerClass, renameClassMap); - } } for (Map.Entry> renameClassMapEntry : renameClassMap.entrySet()) { @@ -389,7 +386,11 @@ public class Deobfuscator { } } + classMapping.markDirty(); renameClassMap.put(classMapping, renameEntries); + for(ClassMapping innerClass : classMapping.innerClasses()){ + rebuildMethodNames(innerClass, renameClassMap); + } } -- cgit v1.2.3 From 7ec433f1ecc5b44f8b690c7443d5e38ac0e6422d Mon Sep 17 00:00:00 2001 From: gegy1000 Date: Fri, 22 Jun 2018 22:29:41 +0200 Subject: Resolve all failed tests --- src/main/java/cuchaz/enigma/Deobfuscator.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java') diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index 6bbfd07..bdd8873 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java @@ -46,7 +46,6 @@ import java.util.jar.JarOutputStream; public class Deobfuscator { private final ReferencedEntryPool entryPool = new ReferencedEntryPool(); - private final JarFile jar; private final ParsedJar parsedJar; private final DecompilerSettings settings; private final JarIndex jarIndex; @@ -54,9 +53,8 @@ public class Deobfuscator { private final Map translatorCache; private Mappings mappings; - public Deobfuscator(JarFile jar) throws IOException { - this.jar = jar; - this.parsedJar = new ParsedJar(jar); + public Deobfuscator(ParsedJar jar) { + this.parsedJar = jar; // build the jar index this.jarIndex = new JarIndex(entryPool); @@ -79,12 +77,12 @@ public class Deobfuscator { setMappings(new Mappings()); } - public ParsedJar getJar() { - return this.parsedJar; + public Deobfuscator(JarFile jar) throws IOException { + this(new ParsedJar(jar)); } - public String getJarName() { - return this.jar.getName(); + public ParsedJar getJar() { + return this.parsedJar; } public JarIndex getJarIndex() { @@ -388,7 +386,7 @@ public class Deobfuscator { classMapping.markDirty(); renameClassMap.put(classMapping, renameEntries); - for(ClassMapping innerClass : classMapping.innerClasses()){ + for (ClassMapping innerClass : classMapping.innerClasses()) { rebuildMethodNames(innerClass, renameClassMap); } } -- cgit v1.2.3 From 236c79260e965d6cd6ca6b4e5a72a8125b132920 Mon Sep 17 00:00:00 2001 From: gegy1000 Date: Sat, 23 Jun 2018 15:56:05 +0200 Subject: Apply deobfuscated name to transformed classes --- src/main/java/cuchaz/enigma/Deobfuscator.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java') diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index bdd8873..ccd099c 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java @@ -393,15 +393,21 @@ public class Deobfuscator { public void writeJar(File out, ProgressListener progress) { - transformJar(out, progress, createTypeLoader()::createTransformer); + transformJar(out, progress, createTypeLoader()::transformInto); } public void protectifyJar(File out, ProgressListener progress) { - transformJar(out, progress, (node, writer) -> node.accept(new ClassProtectifier(Opcodes.ASM5, writer))); + transformJar(out, progress, (node, writer) -> { + node.accept(new ClassProtectifier(Opcodes.ASM5, writer)); + return node.name; + }); } public void publifyJar(File out, ProgressListener progress) { - transformJar(out, progress, (node, writer) -> node.accept(new ClassPublifier(Opcodes.ASM5, writer))); + transformJar(out, progress, (node, writer) -> { + node.accept(new ClassPublifier(Opcodes.ASM5, writer)); + return node.name; + }); } public void transformJar(File out, ProgressListener progress, ClassTransformer transformer) { @@ -418,8 +424,8 @@ public class Deobfuscator { try { ClassWriter writer = new ClassWriter(0); - transformer.write(node, writer); - outJar.putNextEntry(new JarEntry(node.name.replace('.', '/') + ".class")); + String transformedName = transformer.transform(node, writer); + outJar.putNextEntry(new JarEntry(transformedName.replace('.', '/') + ".class")); outJar.write(writer.toByteArray()); outJar.closeEntry(); } catch (Throwable t) { @@ -646,6 +652,6 @@ public class Deobfuscator { } public interface ClassTransformer { - void write(ClassNode node, ClassWriter writer); + String transform(ClassNode node, ClassWriter writer); } } -- cgit v1.2.3 From f967021ea4a78de9aea0873eeb3e1359a4664a2b Mon Sep 17 00:00:00 2001 From: gegy1000 Date: Tue, 3 Jul 2018 14:41:14 +0200 Subject: Output directly to file on source export --- src/main/java/cuchaz/enigma/Deobfuscator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java') diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index ccd099c..6fe6e64 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java @@ -11,7 +11,6 @@ package cuchaz.enigma; -import com.google.common.base.Charsets; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -277,13 +276,14 @@ public class Deobfuscator { try { // get the source - String source = getSource(getSourceTree(obfClassEntry.getName())); + CompilationUnit sourceTree = getSourceTree(obfClassEntry.getName()); // write the file File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java"); file.getParentFile().mkdirs(); - try (OutputStreamWriter out = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(file)), Charsets.UTF_8)) { - out.write(source); + try (Writer writer = new BufferedWriter(new FileWriter(file))) { + sourceTree.acceptVisitor(new InsertParenthesesVisitor(), null); + sourceTree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(writer), this.settings), null); } } catch (Throwable t) { // don't crash the whole world here, just log the error and keep going -- cgit v1.2.3 From 3fde8f31d5e35256935de6945f6d36757e8e4adc Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Tue, 3 Jul 2018 14:24:20 +0100 Subject: Make decompile parallel --- src/main/java/cuchaz/enigma/Deobfuscator.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java') diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index 6fe6e64..5e0bcb8 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java @@ -11,6 +11,7 @@ package cuchaz.enigma; +import com.google.common.base.Stopwatch; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -267,11 +268,12 @@ public class Deobfuscator { } // DEOBFUSCATE ALL THE THINGS!! @_@ - int i = 0; - for (ClassEntry obfClassEntry : classEntries) { + Stopwatch stopwatch = Stopwatch.createStarted(); + AtomicInteger count = new AtomicInteger(); + classEntries.parallelStream().forEach(obfClassEntry -> { ClassEntry deobfClassEntry = deobfuscateEntry(new ClassEntry(obfClassEntry)); if (progress != null) { - progress.onProgress(i++, deobfClassEntry.toString()); + progress.onProgress(count.getAndIncrement(), deobfClassEntry.toString()); } try { @@ -283,7 +285,7 @@ public class Deobfuscator { file.getParentFile().mkdirs(); try (Writer writer = new BufferedWriter(new FileWriter(file))) { sourceTree.acceptVisitor(new InsertParenthesesVisitor(), null); - sourceTree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(writer), this.settings), null); + sourceTree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(writer), settings), null); } } catch (Throwable t) { // don't crash the whole world here, just log the error and keep going @@ -291,9 +293,11 @@ public class Deobfuscator { System.err.println("Unable to deobfuscate class " + deobfClassEntry + " (" + obfClassEntry + ")"); t.printStackTrace(System.err); } - } + }); + stopwatch.stop(); + System.out.println("Done in : " + stopwatch.toString()); if (progress != null) { - progress.onProgress(i, "Done!"); + progress.onProgress(count.get(), "Done:"); } } -- cgit v1.2.3 From c2653186fd557b06ab36c4c064a2e82985edc01e Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Thu, 5 Jul 2018 16:29:18 +0100 Subject: make isMethodProvider public (cherry picked from commit ebad6a9) --- src/main/java/cuchaz/enigma/Deobfuscator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java') diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index 5e0bcb8..0e03753 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java @@ -314,7 +314,7 @@ public class Deobfuscator { } } - private boolean isMethodProvider(ClassEntry classObfEntry, MethodEntry methodEntry) { + public boolean isMethodProvider(ClassEntry classObfEntry, MethodEntry methodEntry) { Set classEntries = new HashSet<>(); addAllPotentialAncestors(classEntries, classObfEntry); -- cgit v1.2.3 From 027d79e46569321d7fe2d1049a512bf59370a47f Mon Sep 17 00:00:00 2001 From: Thiakil Date: Fri, 6 Jul 2018 13:03:02 +0800 Subject: speed up Deobfuscator's getSources by using a single TranslatingTypeloader and caching the ClassLoaderTypeloader --- src/main/java/cuchaz/enigma/Deobfuscator.java | 42 +++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java') diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index 0e03753..cb02ffa 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; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.strobel.assembler.metadata.Buffer; import com.strobel.assembler.metadata.MetadataSystem; import com.strobel.assembler.metadata.TypeDefinition; import com.strobel.assembler.metadata.TypeReference; @@ -163,6 +164,10 @@ public class Deobfuscator { } public CompilationUnit getSourceTree(String className) { + return getSourceTree(className, createTypeLoader()); + } + + public CompilationUnit getSourceTree(String className, ITranslatingTypeLoader loader) { // we don't know if this class name is obfuscated or deobfuscated // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out @@ -178,7 +183,6 @@ public class Deobfuscator { } // set the desc loader - TranslatingTypeLoader loader = createTypeLoader(); this.settings.setTypeLoader(loader); // see if procyon can find the desc @@ -267,6 +271,10 @@ public class Deobfuscator { progress.init(classEntries.size(), "Decompiling classes..."); } + //create a common instance outside the loop as mappings shouldn't be changing while this is happening + //synchronized to make sure the parallelStream doesn't CME with the cache + ITranslatingTypeLoader typeLoader = new SynchronizedTypeLoader(createTypeLoader()); + // DEOBFUSCATE ALL THE THINGS!! @_@ Stopwatch stopwatch = Stopwatch.createStarted(); AtomicInteger count = new AtomicInteger(); @@ -278,7 +286,7 @@ public class Deobfuscator { try { // get the source - CompilationUnit sourceTree = getSourceTree(obfClassEntry.getName()); + CompilationUnit sourceTree = getSourceTree(obfClassEntry.getName(), typeLoader); // write the file File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java"); @@ -295,7 +303,7 @@ public class Deobfuscator { } }); stopwatch.stop(); - System.out.println("Done in : " + stopwatch.toString()); + System.out.println("writeSources Done in : " + stopwatch.toString()); if (progress != null) { progress.onProgress(count.get(), "Done:"); } @@ -658,4 +666,32 @@ public class Deobfuscator { public interface ClassTransformer { String transform(ClassNode node, ClassWriter writer); } + + private class SynchronizedTypeLoader implements ITranslatingTypeLoader { + private final TranslatingTypeLoader delegate; + + private SynchronizedTypeLoader(TranslatingTypeLoader delegate) { + this.delegate = delegate; + } + + @Override + public List getClassNamesToTry(String className) { + return delegate.getClassNamesToTry(className); + } + + @Override + public List getClassNamesToTry(ClassEntry obfClassEntry) { + return delegate.getClassNamesToTry(obfClassEntry); + } + + @Override + public String transformInto(ClassNode node, ClassWriter writer) { + return delegate.transformInto(node, writer); + } + + @Override + public synchronized boolean tryLoadType(String internalName, Buffer buffer) { + return delegate.tryLoadType(internalName, buffer); + } + } } -- cgit v1.2.3 From 4297fa87848d379e15e80ebc0d3106082c4647e0 Mon Sep 17 00:00:00 2001 From: Thiakil Date: Fri, 6 Jul 2018 22:52:33 +0800 Subject: move SynchronizedTypeLoader to a non-inner --- src/main/java/cuchaz/enigma/Deobfuscator.java | 28 --------------------------- 1 file changed, 28 deletions(-) (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java') diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index cb02ffa..b2cecfe 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java @@ -15,7 +15,6 @@ import com.google.common.base.Stopwatch; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import com.strobel.assembler.metadata.Buffer; import com.strobel.assembler.metadata.MetadataSystem; import com.strobel.assembler.metadata.TypeDefinition; import com.strobel.assembler.metadata.TypeReference; @@ -667,31 +666,4 @@ public class Deobfuscator { String transform(ClassNode node, ClassWriter writer); } - private class SynchronizedTypeLoader implements ITranslatingTypeLoader { - private final TranslatingTypeLoader delegate; - - private SynchronizedTypeLoader(TranslatingTypeLoader delegate) { - this.delegate = delegate; - } - - @Override - public List getClassNamesToTry(String className) { - return delegate.getClassNamesToTry(className); - } - - @Override - public List getClassNamesToTry(ClassEntry obfClassEntry) { - return delegate.getClassNamesToTry(obfClassEntry); - } - - @Override - public String transformInto(ClassNode node, ClassWriter writer) { - return delegate.transformInto(node, writer); - } - - @Override - public synchronized boolean tryLoadType(String internalName, Buffer buffer) { - return delegate.tryLoadType(internalName, buffer); - } - } } -- cgit v1.2.3 From fb3e7bbf5b450138ab0b8493ff725f36407ee5bc Mon Sep 17 00:00:00 2001 From: Thiakil Date: Wed, 11 Jul 2018 15:58:19 +0800 Subject: support enum switches with obfuscated SwitchMaps --- src/main/java/cuchaz/enigma/Deobfuscator.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java') diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index b2cecfe..6ea1c40 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java @@ -25,6 +25,7 @@ import com.strobel.decompiler.languages.java.JavaOutputVisitor; import com.strobel.decompiler.languages.java.ast.AstBuilder; import com.strobel.decompiler.languages.java.ast.CompilationUnit; import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; +import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; import cuchaz.enigma.analysis.*; import cuchaz.enigma.bytecode.ClassProtectifier; import cuchaz.enigma.bytecode.ClassPublifier; @@ -32,6 +33,7 @@ import cuchaz.enigma.mapping.*; import cuchaz.enigma.mapping.entry.*; import cuchaz.enigma.throwables.IllegalNameException; import cuchaz.enigma.utils.Utils; +import oml.ast.transformers.ObfuscatedEnumSwitchRewriterTransform; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; @@ -200,6 +202,7 @@ public class Deobfuscator { AstBuilder builder = new AstBuilder(context); builder.addType(resolvedType); builder.runTransformations(null); + runCustomTransforms(builder, context); return builder.getCompilationUnit(); } @@ -656,6 +659,15 @@ public class Deobfuscator { throw new Error("Unknown entry desc: " + obfEntry); } + public static void runCustomTransforms(AstBuilder builder, DecompilerContext context){ + List transformers = Arrays.asList( + new ObfuscatedEnumSwitchRewriterTransform(context) + ); + for (IAstTransform transform : transformers){ + transform.run(builder.getCompilationUnit()); + } + } + public interface ProgressListener { void init(int totalWork, String title); -- cgit v1.2.3