From e27d5967029f4f3da8889dd673ba516dcd9f3ac8 Mon Sep 17 00:00:00 2001 From: gegy1000 Date: Sun, 16 Jun 2019 23:49:25 +0200 Subject: Plugin rework along with API rework: Enigma split from EnigmaProject; plugins now provide services configurable via a profile --- src/main/java/cuchaz/enigma/Deobfuscator.java | 435 -------------------------- 1 file changed, 435 deletions(-) delete mode 100644 src/main/java/cuchaz/enigma/Deobfuscator.java (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 deleted file mode 100644 index 32f7aa7..0000000 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ /dev/null @@ -1,435 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - *

- * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ - -package cuchaz.enigma; - -import com.google.common.base.Functions; -import com.google.common.base.Stopwatch; -import com.google.common.collect.Streams; -import com.strobel.assembler.metadata.ITypeLoader; -import com.strobel.assembler.metadata.MetadataSystem; -import com.strobel.assembler.metadata.TypeDefinition; -import com.strobel.assembler.metadata.TypeReference; -import com.strobel.decompiler.DecompilerSettings; -import com.strobel.decompiler.languages.java.ast.CompilationUnit; -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.analysis.IndexTreeBuilder; -import cuchaz.enigma.analysis.ParsedJar; -import cuchaz.enigma.analysis.index.JarIndex; -import cuchaz.enigma.api.EntryNameProposer; -import cuchaz.enigma.api.JarProcessor; -import cuchaz.enigma.bytecode.translators.SourceFixVisitor; -import cuchaz.enigma.bytecode.translators.TranslationClassVisitor; -import cuchaz.enigma.translation.Translatable; -import cuchaz.enigma.translation.Translator; -import cuchaz.enigma.translation.mapping.*; -import cuchaz.enigma.translation.mapping.tree.DeltaTrackingTree; -import cuchaz.enigma.translation.mapping.tree.EntryTree; -import cuchaz.enigma.translation.representation.entry.ClassEntry; -import cuchaz.enigma.translation.representation.entry.Entry; -import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; -import cuchaz.enigma.translation.representation.entry.MethodEntry; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.ClassNode; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.Writer; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.jar.JarOutputStream; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class Deobfuscator { - - private final ServiceLoader jarProcessors = ServiceLoader.load(JarProcessor.class); - private final ServiceLoader nameProposers = ServiceLoader.load(EntryNameProposer.class); - - private final ParsedJar parsedJar; - private final JarIndex jarIndex; - private final IndexTreeBuilder indexTreeBuilder; - - private final SourceProvider obfSourceProvider; - - private EntryRemapper mapper; - - public Deobfuscator(ParsedJar jar, Consumer listener) { - this.parsedJar = jar; - - // build the jar index - this.jarIndex = JarIndex.empty(); - this.jarIndex.indexJar(this.parsedJar, listener); - - listener.accept("Processing jar"); - this.jarProcessors.forEach(processor -> processor.accept(parsedJar, jarIndex)); - - this.indexTreeBuilder = new IndexTreeBuilder(jarIndex); - - listener.accept("Preparing..."); - - CompiledSourceTypeLoader typeLoader = new CompiledSourceTypeLoader(parsedJar); - typeLoader.addVisitor(visitor -> new SourceFixVisitor(Opcodes.ASM5, visitor, jarIndex)); - - this.obfSourceProvider = new SourceProvider(SourceProvider.createSettings(), typeLoader); - - // init mappings - mapper = new EntryRemapper(jarIndex); - } - - public Deobfuscator(JarFile jar, Consumer listener) throws IOException { - this(new ParsedJar(jar), listener); - } - - public Deobfuscator(ParsedJar jar) { - this(jar, (msg) -> { - }); - } - - public Deobfuscator(JarFile jar) throws IOException { - this(jar, (msg) -> { - }); - } - - public Stream getNameProposers() { - return Streams.stream(nameProposers); - } - - public ParsedJar getJar() { - return this.parsedJar; - } - - public JarIndex getJarIndex() { - return this.jarIndex; - } - - public IndexTreeBuilder getIndexTreeBuilder() { - return indexTreeBuilder; - } - - public EntryRemapper getMapper() { - return this.mapper; - } - - public void setMappings(EntryTree mappings) { - setMappings(mappings, ProgressListener.VOID); - } - - public void setMappings(EntryTree mappings, ProgressListener progress) { - if (mappings != null) { - Collection> dropped = dropMappings(mappings, progress); - mapper = new EntryRemapper(jarIndex, mappings); - - DeltaTrackingTree obfToDeobf = mapper.getObfToDeobf(); - for (Entry entry : dropped) { - obfToDeobf.trackChange(entry); - } - } else { - mapper = new EntryRemapper(jarIndex); - } - } - - private Collection> dropMappings(EntryTree mappings, ProgressListener progress) { - // drop mappings that don't match the jar - MappingsChecker checker = new MappingsChecker(jarIndex, mappings); - MappingsChecker.Dropped dropped = checker.dropBrokenMappings(progress); - - Map, String> droppedMappings = dropped.getDroppedMappings(); - for (Map.Entry, String> mapping : droppedMappings.entrySet()) { - System.out.println("WARNING: Couldn't find " + mapping.getKey() + " (" + mapping.getValue() + ") in jar. Mapping was dropped."); - } - - return droppedMappings.keySet(); - } - - public void getSeparatedClasses(List obfClasses, List deobfClasses) { - for (ClassEntry obfClassEntry : this.jarIndex.getEntryIndex().getClasses()) { - // skip inner classes - if (obfClassEntry.isInnerClass()) { - continue; - } - - // separate the classes - ClassEntry deobfClassEntry = mapper.deobfuscate(obfClassEntry); - if (!deobfClassEntry.equals(obfClassEntry)) { - // if the class has a mapping, clearly it's deobfuscated - deobfClasses.add(obfClassEntry); - } else if (obfClassEntry.getPackageName() != null) { - // also call it deobufscated if it's not in the none package - deobfClasses.add(obfClassEntry); - } else { - // otherwise, assume it's still obfuscated - obfClasses.add(obfClassEntry); - } - } - } - - public SourceProvider getObfSourceProvider() { - return obfSourceProvider; - } - - public void writeSources(Path outputDirectory, ProgressListener progress) { - // get the classes to decompile - Collection classEntries = jarIndex.getEntryIndex().getClasses(); - - Stopwatch stopwatch = Stopwatch.createStarted(); - - try { - Translator deobfuscator = mapper.getDeobfuscator(); - - // deobfuscate everything first - Map translatedNodes = deobfuscateClasses(progress, classEntries, deobfuscator); - - decompileClasses(outputDirectory, progress, translatedNodes); - } finally { - stopwatch.stop(); - - System.out.println("writeSources Done in : " + stopwatch.toString()); - } - } - - private Map deobfuscateClasses(ProgressListener progress, Collection classEntries, Translator translator) { - AtomicInteger count = new AtomicInteger(); - if (progress != null) { - progress.init(classEntries.size(), "Deobfuscating classes..."); - } - - return classEntries.parallelStream() - .map(entry -> { - ClassEntry translatedEntry = translator.translate(entry); - if (progress != null) { - progress.step(count.getAndIncrement(), translatedEntry.toString()); - } - - ClassNode node = parsedJar.getClassNode(entry.getFullName()); - if (node != null) { - ClassNode translatedNode = new ClassNode(); - node.accept(new TranslationClassVisitor(translator, Opcodes.ASM5, translatedNode)); - return translatedNode; - } - - return null; - }) - .filter(Objects::nonNull) - .collect(Collectors.toMap(n -> n.name, Functions.identity())); - } - - private void decompileClasses(Path outputDirectory, ProgressListener progress, Map translatedClasses) { - Collection decompileClasses = translatedClasses.values().stream() - .filter(classNode -> classNode.name.indexOf('$') == -1) - .collect(Collectors.toList()); - - if (progress != null) { - progress.init(decompileClasses.size(), "Decompiling classes..."); - } - - //create a common instance outside the loop as mappings shouldn't be changing while this is happening - CompiledSourceTypeLoader typeLoader = new CompiledSourceTypeLoader(translatedClasses::get); - typeLoader.addVisitor(visitor -> new SourceFixVisitor(Opcodes.ASM5, visitor, jarIndex)); - - //synchronized to make sure the parallelStream doesn't CME with the cache - ITypeLoader synchronizedTypeLoader = new SynchronizedTypeLoader(typeLoader); - - MetadataSystem metadataSystem = new Deobfuscator.NoRetryMetadataSystem(synchronizedTypeLoader); - - //ensures methods are loaded on classload and prevents race conditions - metadataSystem.setEagerMethodLoadingEnabled(true); - - DecompilerSettings settings = SourceProvider.createSettings(); - SourceProvider sourceProvider = new SourceProvider(settings, synchronizedTypeLoader, metadataSystem); - - AtomicInteger count = new AtomicInteger(); - - decompileClasses.parallelStream().forEach(translatedNode -> { - if (progress != null) { - progress.step(count.getAndIncrement(), translatedNode.name); - } - - decompileClass(outputDirectory, translatedNode, sourceProvider); - }); - } - - private void decompileClass(Path outputDirectory, ClassNode translatedNode, SourceProvider sourceProvider) { - try { - // get the source - CompilationUnit sourceTree = sourceProvider.getSources(translatedNode.name); - - Path path = outputDirectory.resolve(translatedNode.name.replace('.', '/') + ".java"); - Files.createDirectories(path.getParent()); - - try (Writer writer = Files.newBufferedWriter(path)) { - sourceProvider.writeSource(writer, sourceTree); - } - } catch (Throwable t) { - // don't crash the whole world here, just log the error and keep going - // TODO: set up logback via log4j - System.err.println("Unable to decompile class " + translatedNode.name); - t.printStackTrace(System.err); - } - } - - public void writeTransformedJar(File out, ProgressListener progress) { - Translator deobfuscator = mapper.getDeobfuscator(); - writeTransformedJar(out, progress, (node, visitor) -> { - ClassEntry entry = new ClassEntry(node.name); - node.accept(new TranslationClassVisitor(deobfuscator, Opcodes.ASM5, visitor)); - return deobfuscator.translate(entry).getFullName(); - }); - } - - public void writeTransformedJar(File out, ProgressListener progress, ClassTransformer transformer) { - try (JarOutputStream outJar = new JarOutputStream(new FileOutputStream(out))) { - if (progress != null) { - progress.init(parsedJar.getClassCount(), "Transforming classes..."); - } - - AtomicInteger count = new AtomicInteger(); - parsedJar.visitNode(node -> { - if (progress != null) { - progress.step(count.getAndIncrement(), node.name); - } - - try { - ClassWriter writer = new ClassWriter(0); - String transformedName = transformer.transform(node, writer); - outJar.putNextEntry(new JarEntry(transformedName.replace('.', '/') + ".class")); - outJar.write(writer.toByteArray()); - outJar.closeEntry(); - } catch (Throwable t) { - throw new Error("Unable to transform class " + node.name, t); - } - }); - } catch (IOException ex) { - throw new Error("Unable to write to Jar file!"); - } - } - - public AccessModifier getModifier(Entry entry) { - EntryMapping mapping = mapper.getDeobfMapping(entry); - if (mapping == null) { - return AccessModifier.UNCHANGED; - } - return mapping.getAccessModifier(); - } - - public void changeModifier(Entry entry, AccessModifier modifier) { - EntryMapping mapping = mapper.getDeobfMapping(entry); - if (mapping != null) { - mapper.mapFromObf(entry, new EntryMapping(mapping.getTargetName(), modifier)); - } else { - mapper.mapFromObf(entry, new EntryMapping(entry.getName(), modifier)); - } - } - - public boolean isRenamable(Entry obfEntry) { - if (obfEntry instanceof MethodEntry) { - // HACKHACK: Object methods are not obfuscated identifiers - MethodEntry obfMethodEntry = (MethodEntry) obfEntry; - String name = obfMethodEntry.getName(); - 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")) { - return false; - } else if (name.equals("finalize") && sig.equals("()V")) { - return false; - } else if (name.equals("getClass") && sig.equals("()Ljava/lang/Class;")) { - return false; - } else if (name.equals("hashCode") && sig.equals("()I")) { - return false; - } else if (name.equals("notify") && sig.equals("()V")) { - return false; - } else if (name.equals("notifyAll") && sig.equals("()V")) { - return false; - } else if (name.equals("toString") && sig.equals("()Ljava/lang/String;")) { - return false; - } else if (name.equals("wait") && sig.equals("()V")) { - return false; - } else if (name.equals("wait") && sig.equals("(J)V")) { - return false; - } else if (name.equals("wait") && sig.equals("(JI)V")) { - return false; - } - } else if (obfEntry instanceof LocalVariableEntry && !((LocalVariableEntry) obfEntry).isArgument()) { - return false; - } - - return this.jarIndex.getEntryIndex().hasEntry(obfEntry); - } - - public boolean isRenamable(EntryReference, Entry> obfReference) { - return obfReference.isNamed() && isRenamable(obfReference.getNameableEntry()); - } - - public boolean isRemapped(Entry entry) { - EntryResolver resolver = mapper.getObfResolver(); - DeltaTrackingTree mappings = mapper.getObfToDeobf(); - return resolver.resolveEntry(entry, ResolutionStrategy.RESOLVE_ROOT).stream() - .anyMatch(mappings::contains); - } - - public void rename(Entry obfEntry, String newName) { - mapper.mapFromObf(obfEntry, new EntryMapping(newName)); - } - - public void removeMapping(Entry obfEntry) { - mapper.removeByObf(obfEntry); - } - - public void markAsDeobfuscated(Entry obfEntry) { - mapper.mapFromObf(obfEntry, new EntryMapping(mapper.deobfuscate(obfEntry).getName())); - } - - public T deobfuscate(T translatable) { - return mapper.deobfuscate(translatable); - } - - public interface ClassTransformer { - String transform(ClassNode node, ClassVisitor visitor); - } - - public static class NoRetryMetadataSystem extends MetadataSystem { - private final Set _failedTypes = Collections.newSetFromMap(new ConcurrentHashMap<>()); - - public NoRetryMetadataSystem(final ITypeLoader typeLoader) { - super(typeLoader); - } - - @Override - protected synchronized TypeDefinition resolveType(final String descriptor, final boolean mightBePrimitive) { - if (_failedTypes.contains(descriptor)) { - return null; - } - - final TypeDefinition result = super.resolveType(descriptor, mightBePrimitive); - - if (result == null) { - _failedTypes.add(descriptor); - } - - return result; - } - - @Override - public synchronized TypeDefinition resolve(final TypeReference type) { - return super.resolve(type); - } - } -} -- cgit v1.2.3