diff options
Diffstat (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java')
| -rw-r--r-- | src/main/java/cuchaz/enigma/Deobfuscator.java | 225 |
1 files changed, 119 insertions, 106 deletions
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; | |||
| 31 | import cuchaz.enigma.mapping.*; | 31 | import cuchaz.enigma.mapping.*; |
| 32 | import cuchaz.enigma.throwables.IllegalNameException; | 32 | import cuchaz.enigma.throwables.IllegalNameException; |
| 33 | import cuchaz.enigma.utils.Utils; | 33 | import cuchaz.enigma.utils.Utils; |
| 34 | import javassist.CtClass; | 34 | import org.objectweb.asm.ClassWriter; |
| 35 | import javassist.bytecode.Descriptor; | 35 | import org.objectweb.asm.Opcodes; |
| 36 | import org.objectweb.asm.tree.ClassNode; | ||
| 36 | 37 | ||
| 37 | import java.io.*; | 38 | import java.io.*; |
| 38 | import java.util.*; | 39 | import java.util.*; |
| 40 | import java.util.concurrent.atomic.AtomicInteger; | ||
| 39 | import java.util.jar.JarEntry; | 41 | import java.util.jar.JarEntry; |
| 40 | import java.util.jar.JarFile; | 42 | import java.util.jar.JarFile; |
| 41 | import java.util.jar.JarOutputStream; | 43 | import java.util.jar.JarOutputStream; |
| 42 | 44 | ||
| 43 | public class Deobfuscator { | 45 | public class Deobfuscator { |
| 44 | 46 | ||
| 47 | private final ReferencedEntryPool entryPool = new ReferencedEntryPool(); | ||
| 45 | private final JarFile jar; | 48 | private final JarFile jar; |
| 49 | private final ParsedJar parsedJar; | ||
| 46 | private final DecompilerSettings settings; | 50 | private final DecompilerSettings settings; |
| 47 | private final JarIndex jarIndex; | 51 | private final JarIndex jarIndex; |
| 48 | private final MappingsRenamer renamer; | 52 | private final MappingsRenamer renamer; |
| 49 | private final Map<TranslationDirection, Translator> translatorCache; | 53 | private final Map<TranslationDirection, Translator> translatorCache; |
| 50 | private Mappings mappings; | 54 | private Mappings mappings; |
| 51 | 55 | ||
| 52 | public Deobfuscator(JarFile jar) { | 56 | public Deobfuscator(JarFile jar) throws IOException { |
| 53 | this.jar = jar; | 57 | this.jar = jar; |
| 58 | this.parsedJar = new ParsedJar(jar); | ||
| 54 | 59 | ||
| 55 | // build the jar index | 60 | // build the jar index |
| 56 | this.jarIndex = new JarIndex(); | 61 | this.jarIndex = new JarIndex(entryPool); |
| 57 | this.jarIndex.indexJar(this.jar, true); | 62 | this.jarIndex.indexJar(this.parsedJar, true); |
| 58 | 63 | ||
| 59 | // config the decompiler | 64 | // config the decompiler |
| 60 | this.settings = DecompilerSettings.javaDefaults(); | 65 | this.settings = DecompilerSettings.javaDefaults(); |
| 61 | this.settings.setMergeVariables(Utils.getSystemPropertyAsBoolean("enigma.mergeVariables", true)); | 66 | this.settings.setMergeVariables(Utils.getSystemPropertyAsBoolean("enigma.mergeVariables", true)); |
| 62 | this.settings.setForceExplicitImports(Utils.getSystemPropertyAsBoolean("enigma.forceExplicitImports", true)); | 67 | this.settings.setForceExplicitImports(Utils.getSystemPropertyAsBoolean("enigma.forceExplicitImports", true)); |
| 63 | this.settings.setForceExplicitTypeArguments( | 68 | this.settings.setForceExplicitTypeArguments( |
| 64 | Utils.getSystemPropertyAsBoolean("enigma.forceExplicitTypeArguments", true)); | 69 | Utils.getSystemPropertyAsBoolean("enigma.forceExplicitTypeArguments", true)); |
| 65 | // DEBUG | 70 | // DEBUG |
| 66 | this.settings.setShowDebugLineNumbers(Utils.getSystemPropertyAsBoolean("enigma.showDebugLineNumbers", false)); | 71 | this.settings.setShowDebugLineNumbers(Utils.getSystemPropertyAsBoolean("enigma.showDebugLineNumbers", false)); |
| 67 | this.settings.setShowSyntheticMembers(Utils.getSystemPropertyAsBoolean("enigma.showSyntheticMembers", false)); | 72 | this.settings.setShowSyntheticMembers(Utils.getSystemPropertyAsBoolean("enigma.showSyntheticMembers", false)); |
| 68 | 73 | ||
| 69 | // init defaults | 74 | // init defaults |
| 70 | this.translatorCache = Maps.newTreeMap(); | 75 | this.translatorCache = Maps.newTreeMap(); |
| 71 | this.renamer = new MappingsRenamer(this.jarIndex, null); | 76 | this.renamer = new MappingsRenamer(this.jarIndex, null, this.entryPool); |
| 72 | // init mappings | 77 | // init mappings |
| 73 | setMappings(new Mappings()); | 78 | setMappings(new Mappings()); |
| 74 | } | 79 | } |
| 75 | 80 | ||
| 76 | public JarFile getJar() { | 81 | public ParsedJar getJar() { |
| 77 | return this.jar; | 82 | return this.parsedJar; |
| 78 | } | 83 | } |
| 79 | 84 | ||
| 80 | public String getJarName() { | 85 | public String getJarName() { |
| @@ -102,16 +107,16 @@ public class Deobfuscator { | |||
| 102 | MappingsChecker checker = new MappingsChecker(this.jarIndex); | 107 | MappingsChecker checker = new MappingsChecker(this.jarIndex); |
| 103 | checker.dropBrokenMappings(val); | 108 | checker.dropBrokenMappings(val); |
| 104 | if (warnAboutDrops) { | 109 | if (warnAboutDrops) { |
| 105 | for (java.util.Map.Entry<ClassEntry, ClassMapping> mapping : checker.getDroppedClassMappings().entrySet()) { | 110 | for (Map.Entry<ClassEntry, ClassMapping> mapping : checker.getDroppedClassMappings().entrySet()) { |
| 106 | System.out.println("WARNING: Couldn't find class entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); | 111 | System.out.println("WARNING: Couldn't find class entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); |
| 107 | } | 112 | } |
| 108 | for (java.util.Map.Entry<ClassEntry, ClassMapping> mapping : checker.getDroppedInnerClassMappings().entrySet()) { | 113 | for (Map.Entry<ClassEntry, ClassMapping> mapping : checker.getDroppedInnerClassMappings().entrySet()) { |
| 109 | System.out.println("WARNING: Couldn't find inner class entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); | 114 | System.out.println("WARNING: Couldn't find inner class entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); |
| 110 | } | 115 | } |
| 111 | for (java.util.Map.Entry<FieldEntry, FieldMapping> mapping : checker.getDroppedFieldMappings().entrySet()) { | 116 | for (Map.Entry<FieldEntry, FieldMapping> mapping : checker.getDroppedFieldMappings().entrySet()) { |
| 112 | System.out.println("WARNING: Couldn't find field entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); | 117 | System.out.println("WARNING: Couldn't find field entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); |
| 113 | } | 118 | } |
| 114 | for (java.util.Map.Entry<BehaviorEntry, MethodMapping> mapping : checker.getDroppedMethodMappings().entrySet()) { | 119 | for (Map.Entry<MethodEntry, MethodMapping> mapping : checker.getDroppedMethodMappings().entrySet()) { |
| 115 | System.out.println("WARNING: Couldn't find behavior entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); | 120 | System.out.println("WARNING: Couldn't find behavior entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); |
| 116 | } | 121 | } |
| 117 | } | 122 | } |
| @@ -123,7 +128,7 @@ public class Deobfuscator { | |||
| 123 | 128 | ||
| 124 | public Translator getTranslator(TranslationDirection direction) { | 129 | public Translator getTranslator(TranslationDirection direction) { |
| 125 | return this.translatorCache.computeIfAbsent(direction, | 130 | return this.translatorCache.computeIfAbsent(direction, |
| 126 | k -> this.mappings.getTranslator(direction, this.jarIndex.getTranslationIndex())); | 131 | k -> this.mappings.getTranslator(direction, this.jarIndex.getTranslationIndex())); |
| 127 | } | 132 | } |
| 128 | 133 | ||
| 129 | public void getSeparatedClasses(List<ClassEntry> obfClasses, List<ClassEntry> deobfClasses) { | 134 | public void getSeparatedClasses(List<ClassEntry> obfClasses, List<ClassEntry> deobfClasses) { |
| @@ -150,10 +155,11 @@ public class Deobfuscator { | |||
| 150 | 155 | ||
| 151 | public TranslatingTypeLoader createTypeLoader() { | 156 | public TranslatingTypeLoader createTypeLoader() { |
| 152 | return new TranslatingTypeLoader( | 157 | return new TranslatingTypeLoader( |
| 153 | this.jar, | 158 | this.parsedJar, |
| 154 | this.jarIndex, | 159 | this.jarIndex, |
| 155 | getTranslator(TranslationDirection.Obfuscating), | 160 | this.entryPool, |
| 156 | getTranslator(TranslationDirection.Deobfuscating) | 161 | getTranslator(TranslationDirection.OBFUSCATING), |
| 162 | getTranslator(TranslationDirection.DEOBFUSCATING) | ||
| 157 | ); | 163 | ); |
| 158 | } | 164 | } |
| 159 | 165 | ||
| @@ -172,15 +178,15 @@ public class Deobfuscator { | |||
| 172 | deobfClassName = classMapping.getDeobfName(); | 178 | deobfClassName = classMapping.getDeobfName(); |
| 173 | } | 179 | } |
| 174 | 180 | ||
| 175 | // set the type loader | 181 | // set the desc loader |
| 176 | TranslatingTypeLoader loader = createTypeLoader(); | 182 | TranslatingTypeLoader loader = createTypeLoader(); |
| 177 | this.settings.setTypeLoader(loader); | 183 | this.settings.setTypeLoader(loader); |
| 178 | 184 | ||
| 179 | // see if procyon can find the type | 185 | // see if procyon can find the desc |
| 180 | TypeReference type = new MetadataSystem(loader).lookupType(deobfClassName); | 186 | TypeReference type = new MetadataSystem(loader).lookupType(deobfClassName); |
| 181 | if (type == null) { | 187 | if (type == null) { |
| 182 | throw new Error(String.format("Unable to find type: %s (deobf: %s)\nTried class names: %s", | 188 | throw new Error(String.format("Unable to find desc: %s (deobf: %s)\nTried class names: %s", |
| 183 | className, deobfClassName, loader.getClassNamesToTry(deobfClassName) | 189 | className, deobfClassName, loader.getClassNamesToTry(deobfClassName) |
| 184 | )); | 190 | )); |
| 185 | } | 191 | } |
| 186 | TypeDefinition resolvedType = type.resolve(); | 192 | TypeDefinition resolvedType = type.resolve(); |
| @@ -208,7 +214,7 @@ public class Deobfuscator { | |||
| 208 | } else { | 214 | } else { |
| 209 | index = new SourceIndex(source); | 215 | index = new SourceIndex(source); |
| 210 | } | 216 | } |
| 211 | sourceTree.acceptVisitor(new SourceIndexVisitor(), index); | 217 | sourceTree.acceptVisitor(new SourceIndexVisitor(entryPool), index); |
| 212 | 218 | ||
| 213 | // DEBUG | 219 | // DEBUG |
| 214 | // sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); | 220 | // sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); |
| @@ -221,10 +227,10 @@ public class Deobfuscator { | |||
| 221 | Entry obfEntry = obfuscateEntry(deobfReference.entry); | 227 | Entry obfEntry = obfuscateEntry(deobfReference.entry); |
| 222 | 228 | ||
| 223 | // try to resolve the class | 229 | // try to resolve the class |
| 224 | ClassEntry resolvedObfClassEntry = this.jarIndex.getTranslationIndex().resolveEntryClass(obfEntry); | 230 | ClassEntry resolvedObfClassEntry = this.jarIndex.getTranslationIndex().resolveEntryOwner(obfEntry); |
| 225 | if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(obfEntry.getClassEntry())) { | 231 | if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(obfEntry.getOwnerClassEntry())) { |
| 226 | // change the class of the entry | 232 | // change the class of the entry |
| 227 | obfEntry = obfEntry.cloneToNewClass(resolvedObfClassEntry); | 233 | obfEntry = obfEntry.updateOwnership(resolvedObfClassEntry); |
| 228 | 234 | ||
| 229 | // save the new deobfuscated reference | 235 | // save the new deobfuscated reference |
| 230 | deobfReference.entry = deobfuscateEntry(obfEntry); | 236 | deobfReference.entry = deobfuscateEntry(obfEntry); |
| @@ -305,18 +311,14 @@ public class Deobfuscator { | |||
| 305 | } | 311 | } |
| 306 | } | 312 | } |
| 307 | 313 | ||
| 308 | private boolean isBehaviorProvider(ClassEntry classObfEntry, BehaviorEntry behaviorEntry) { | 314 | private boolean isMethodProvider(ClassEntry classObfEntry, MethodEntry methodEntry) { |
| 309 | if (behaviorEntry instanceof MethodEntry) { | 315 | Set<ClassEntry> classEntries = new HashSet<>(); |
| 310 | MethodEntry methodEntry = (MethodEntry) behaviorEntry; | 316 | addAllPotentialAncestors(classEntries, classObfEntry); |
| 311 | 317 | ||
| 312 | Set<ClassEntry> classEntries = new HashSet<>(); | 318 | for (ClassEntry parentEntry : classEntries) { |
| 313 | addAllPotentialAncestors(classEntries, classObfEntry); | 319 | MethodEntry ancestorMethodEntry = entryPool.getMethod(parentEntry, methodEntry.getName(), methodEntry.getDesc()); |
| 314 | 320 | if (jarIndex.containsObfMethod(ancestorMethodEntry)) { | |
| 315 | for (ClassEntry parentEntry : classEntries) { | 321 | return false; |
| 316 | MethodEntry ancestorMethodEntry = new MethodEntry(parentEntry, methodEntry.getName(), methodEntry.getSignature()); | ||
| 317 | if (jarIndex.containsObfBehavior(ancestorMethodEntry)) { | ||
| 318 | return false; | ||
| 319 | } | ||
| 320 | } | 322 | } |
| 321 | } | 323 | } |
| 322 | 324 | ||
| @@ -332,7 +334,7 @@ public class Deobfuscator { | |||
| 332 | for (ClassMapping classMapping : Lists.newArrayList(getMappings().classes())) { | 334 | for (ClassMapping classMapping : Lists.newArrayList(getMappings().classes())) { |
| 333 | progress.onProgress(i++, classMapping.getDeobfName()); | 335 | progress.onProgress(i++, classMapping.getDeobfName()); |
| 334 | rebuildMethodNames(classMapping, renameClassMap); | 336 | rebuildMethodNames(classMapping, renameClassMap); |
| 335 | for(ClassMapping innerClass : classMapping.innerClasses()){ | 337 | for (ClassMapping innerClass : classMapping.innerClasses()) { |
| 336 | rebuildMethodNames(innerClass, renameClassMap); | 338 | rebuildMethodNames(innerClass, renameClassMap); |
| 337 | } | 339 | } |
| 338 | } | 340 | } |
| @@ -356,29 +358,29 @@ public class Deobfuscator { | |||
| 356 | 358 | ||
| 357 | try { | 359 | try { |
| 358 | rename(obfEntry, name); | 360 | rename(obfEntry, name); |
| 359 | } catch (IllegalNameException exception) | 361 | } catch (IllegalNameException exception) { |
| 360 | { | ||
| 361 | System.out.println("WARNING: " + exception.getMessage()); | 362 | System.out.println("WARNING: " + exception.getMessage()); |
| 362 | } | 363 | } |
| 363 | } | 364 | } |
| 364 | } | 365 | } |
| 365 | } | 366 | } |
| 366 | 367 | ||
| 367 | private void rebuildMethodNames(ClassMapping classMapping, Map<ClassMapping, Map<Entry, String>> renameClassMap){ | 368 | private void rebuildMethodNames(ClassMapping classMapping, Map<ClassMapping, Map<Entry, String>> renameClassMap) { |
| 368 | Map<Entry, String> renameEntries = new HashMap<>(); | 369 | Map<Entry, String> renameEntries = new HashMap<>(); |
| 369 | 370 | ||
| 370 | for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) { | 371 | for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) { |
| 371 | ClassEntry classObfEntry = classMapping.getObfEntry(); | 372 | ClassEntry classObfEntry = classMapping.getObfEntry(); |
| 372 | BehaviorEntry obfEntry = methodMapping.getObfEntry(classObfEntry); | 373 | MethodEntry obfEntry = methodMapping.getObfEntry(classObfEntry); |
| 373 | 374 | ||
| 374 | if (isBehaviorProvider(classObfEntry, obfEntry)) { | 375 | if (isMethodProvider(classObfEntry, obfEntry)) { |
| 375 | if (hasDeobfuscatedName(obfEntry) && !(obfEntry instanceof ConstructorEntry) | 376 | if (hasDeobfuscatedName(obfEntry) |
| 376 | && !(methodMapping.getDeobfName().equals(methodMapping.getObfName()))) { | 377 | && !(methodMapping.getDeobfName().equals(methodMapping.getObfName()))) { |
| 377 | renameEntries.put(obfEntry, methodMapping.getDeobfName()); | 378 | renameEntries.put(obfEntry, methodMapping.getDeobfName()); |
| 378 | } | 379 | } |
| 379 | 380 | ||
| 380 | for (ArgumentMapping argumentMapping : Lists.newArrayList(methodMapping.arguments())) { | 381 | ArrayList<LocalVariableMapping> arguments = Lists.newArrayList(methodMapping.arguments()); |
| 381 | Entry argObfEntry = argumentMapping.getObfEntry(obfEntry); | 382 | for (LocalVariableMapping localVariableMapping : arguments) { |
| 383 | Entry argObfEntry = localVariableMapping.getObfEntry(obfEntry); | ||
| 382 | if (hasDeobfuscatedName(argObfEntry)) { | 384 | if (hasDeobfuscatedName(argObfEntry)) { |
| 383 | renameEntries.put(argObfEntry, deobfuscateEntry(argObfEntry).getName()); | 385 | renameEntries.put(argObfEntry, deobfuscateEntry(argObfEntry).getName()); |
| 384 | } | 386 | } |
| @@ -390,45 +392,44 @@ public class Deobfuscator { | |||
| 390 | } | 392 | } |
| 391 | 393 | ||
| 392 | 394 | ||
| 393 | |||
| 394 | public void writeJar(File out, ProgressListener progress) { | 395 | public void writeJar(File out, ProgressListener progress) { |
| 395 | transformJar(out, progress, createTypeLoader()::transformClass); | 396 | transformJar(out, progress, createTypeLoader()::createTransformer); |
| 396 | } | 397 | } |
| 397 | 398 | ||
| 398 | public void protectifyJar(File out, ProgressListener progress) { | 399 | public void protectifyJar(File out, ProgressListener progress) { |
| 399 | transformJar(out, progress, ClassProtectifier::protectify); | 400 | transformJar(out, progress, (node, writer) -> node.accept(new ClassProtectifier(Opcodes.ASM5, writer))); |
| 400 | } | 401 | } |
| 401 | 402 | ||
| 402 | public void publifyJar(File out, ProgressListener progress) { | 403 | public void publifyJar(File out, ProgressListener progress) { |
| 403 | transformJar(out, progress, ClassPublifier::publify); | 404 | transformJar(out, progress, (node, writer) -> node.accept(new ClassPublifier(Opcodes.ASM5, writer))); |
| 404 | } | 405 | } |
| 405 | 406 | ||
| 406 | public void transformJar(File out, ProgressListener progress, ClassTransformer transformer) { | 407 | public void transformJar(File out, ProgressListener progress, ClassTransformer transformer) { |
| 407 | try (JarOutputStream outJar = new JarOutputStream(new FileOutputStream(out))) { | 408 | try (JarOutputStream outJar = new JarOutputStream(new FileOutputStream(out))) { |
| 408 | if (progress != null) { | 409 | if (progress != null) { |
| 409 | progress.init(JarClassIterator.getClassEntries(this.jar).size(), "Transforming classes..."); | 410 | progress.init(parsedJar.getClassCount(), "Transforming classes..."); |
| 410 | } | 411 | } |
| 411 | 412 | ||
| 412 | int i = 0; | 413 | AtomicInteger i = new AtomicInteger(); |
| 413 | for (CtClass c : JarClassIterator.classes(this.jar)) { | 414 | parsedJar.visit(node -> { |
| 414 | if (progress != null) { | 415 | if (progress != null) { |
| 415 | progress.onProgress(i++, c.getName()); | 416 | progress.onProgress(i.getAndIncrement(), node.name); |
| 416 | } | 417 | } |
| 417 | 418 | ||
| 418 | try { | 419 | try { |
| 419 | c = transformer.transform(c); | 420 | ClassWriter writer = new ClassWriter(0); |
| 420 | outJar.putNextEntry(new JarEntry(c.getName().replace('.', '/') + ".class")); | 421 | transformer.write(node, writer); |
| 421 | outJar.write(c.toBytecode()); | 422 | outJar.putNextEntry(new JarEntry(node.name.replace('.', '/') + ".class")); |
| 423 | outJar.write(writer.toByteArray()); | ||
| 422 | outJar.closeEntry(); | 424 | outJar.closeEntry(); |
| 423 | } catch (Throwable t) { | 425 | } catch (Throwable t) { |
| 424 | throw new Error("Unable to transform class " + c.getName(), t); | 426 | throw new Error("Unable to transform class " + node.name, t); |
| 425 | } | 427 | } |
| 426 | } | 428 | }); |
| 429 | |||
| 427 | if (progress != null) { | 430 | if (progress != null) { |
| 428 | progress.onProgress(i, "Done!"); | 431 | progress.onProgress(i.get(), "Done!"); |
| 429 | } | 432 | } |
| 430 | |||
| 431 | outJar.close(); | ||
| 432 | } catch (IOException ex) { | 433 | } catch (IOException ex) { |
| 433 | throw new Error("Unable to write to Jar file!"); | 434 | throw new Error("Unable to write to Jar file!"); |
| 434 | } | 435 | } |
| @@ -438,14 +439,22 @@ public class Deobfuscator { | |||
| 438 | if (deobfEntry == null) { | 439 | if (deobfEntry == null) { |
| 439 | return null; | 440 | return null; |
| 440 | } | 441 | } |
| 441 | return getTranslator(TranslationDirection.Obfuscating).translateEntry(deobfEntry); | 442 | T translatedEntry = getTranslator(TranslationDirection.OBFUSCATING).getTranslatedEntry(deobfEntry); |
| 443 | if (translatedEntry == null) { | ||
| 444 | return deobfEntry; | ||
| 445 | } | ||
| 446 | return translatedEntry; | ||
| 442 | } | 447 | } |
| 443 | 448 | ||
| 444 | public <T extends Entry> T deobfuscateEntry(T obfEntry) { | 449 | public <T extends Entry> T deobfuscateEntry(T obfEntry) { |
| 445 | if (obfEntry == null) { | 450 | if (obfEntry == null) { |
| 446 | return null; | 451 | return null; |
| 447 | } | 452 | } |
| 448 | return getTranslator(TranslationDirection.Deobfuscating).translateEntry(obfEntry); | 453 | T translatedEntry = getTranslator(TranslationDirection.DEOBFUSCATING).getTranslatedEntry(obfEntry); |
| 454 | if (translatedEntry == null) { | ||
| 455 | return obfEntry; | ||
| 456 | } | ||
| 457 | return translatedEntry; | ||
| 449 | } | 458 | } |
| 450 | 459 | ||
| 451 | public <E extends Entry, C extends Entry> EntryReference<E, C> obfuscateReference(EntryReference<E, C> deobfReference) { | 460 | public <E extends Entry, C extends Entry> EntryReference<E, C> obfuscateReference(EntryReference<E, C> deobfReference) { |
| @@ -473,7 +482,7 @@ public class Deobfuscator { | |||
| 473 | // HACKHACK: Object methods are not obfuscated identifiers | 482 | // HACKHACK: Object methods are not obfuscated identifiers |
| 474 | MethodEntry obfMethodEntry = (MethodEntry) obfEntry; | 483 | MethodEntry obfMethodEntry = (MethodEntry) obfEntry; |
| 475 | String name = obfMethodEntry.getName(); | 484 | String name = obfMethodEntry.getName(); |
| 476 | String sig = obfMethodEntry.getSignature().toString(); | 485 | String sig = obfMethodEntry.getDesc().toString(); |
| 477 | if (name.equals("clone") && sig.equals("()Ljava/lang/Object;")) { | 486 | if (name.equals("clone") && sig.equals("()Ljava/lang/Object;")) { |
| 478 | return false; | 487 | return false; |
| 479 | } else if (name.equals("equals") && sig.equals("(Ljava/lang/Object;)Z")) { | 488 | } else if (name.equals("equals") && sig.equals("(Ljava/lang/Object;)Z")) { |
| @@ -499,7 +508,7 @@ public class Deobfuscator { | |||
| 499 | } | 508 | } |
| 500 | 509 | ||
| 501 | // FIXME: HACK EVEN MORE HACK! | 510 | // FIXME: HACK EVEN MORE HACK! |
| 502 | if (hack && this.jarIndex.containsObfEntry(obfEntry.getClassEntry())) | 511 | if (hack && this.jarIndex.containsObfEntry(obfEntry.getOwnerClassEntry())) |
| 503 | return true; | 512 | return true; |
| 504 | } | 513 | } |
| 505 | 514 | ||
| @@ -515,27 +524,24 @@ public class Deobfuscator { | |||
| 515 | } | 524 | } |
| 516 | 525 | ||
| 517 | public boolean hasDeobfuscatedName(Entry obfEntry) { | 526 | public boolean hasDeobfuscatedName(Entry obfEntry) { |
| 518 | Translator translator = getTranslator(TranslationDirection.Deobfuscating); | 527 | Translator translator = getTranslator(TranslationDirection.DEOBFUSCATING); |
| 519 | if (obfEntry instanceof ClassEntry) { | 528 | if (obfEntry instanceof ClassEntry) { |
| 520 | ClassEntry obfClass = (ClassEntry) obfEntry; | 529 | ClassEntry obfClass = (ClassEntry) obfEntry; |
| 521 | List<ClassMapping> mappingChain = this.mappings.getClassMappingChain(obfClass); | 530 | List<ClassMapping> mappingChain = this.mappings.getClassMappingChain(obfClass); |
| 522 | ClassMapping classMapping = mappingChain.get(mappingChain.size() - 1); | 531 | ClassMapping classMapping = mappingChain.get(mappingChain.size() - 1); |
| 523 | return classMapping != null && classMapping.getDeobfName() != null; | 532 | return classMapping != null && classMapping.getDeobfName() != null; |
| 524 | } else if (obfEntry instanceof FieldEntry) { | 533 | } else if (obfEntry instanceof FieldEntry) { |
| 525 | return translator.translate((FieldEntry) obfEntry) != null; | 534 | return translator.getTranslatedField((FieldEntry) obfEntry) != null; |
| 526 | } else if (obfEntry instanceof MethodEntry) { | 535 | } else if (obfEntry instanceof MethodEntry) { |
| 527 | return translator.translate((MethodEntry) obfEntry) != null; | 536 | MethodEntry methodEntry = (MethodEntry) obfEntry; |
| 528 | } else if (obfEntry instanceof ConstructorEntry) { | 537 | if (methodEntry.isConstructor()) { |
| 529 | // constructors have no names | 538 | return false; |
| 530 | return false; | 539 | } |
| 531 | } else if (obfEntry instanceof ArgumentEntry) { | 540 | return translator.getTranslatedMethod(methodEntry) != null; |
| 532 | return translator.translate((ArgumentEntry) obfEntry) != null; | ||
| 533 | } else if (obfEntry instanceof LocalVariableEntry) { | 541 | } else if (obfEntry instanceof LocalVariableEntry) { |
| 534 | // TODO: Implement it | 542 | return translator.getTranslatedVariable((LocalVariableEntry) obfEntry) != null; |
| 535 | //return translator.translate((LocalVariableEntry)obfEntry) != null; | ||
| 536 | return false; | ||
| 537 | } else { | 543 | } else { |
| 538 | throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); | 544 | throw new Error("Unknown entry desc: " + obfEntry.getClass().getName()); |
| 539 | } | 545 | } |
| 540 | } | 546 | } |
| 541 | 547 | ||
| @@ -547,19 +553,18 @@ public class Deobfuscator { | |||
| 547 | 553 | ||
| 548 | public void rename(Entry obfEntry, String newName, boolean clearCache) { | 554 | public void rename(Entry obfEntry, String newName, boolean clearCache) { |
| 549 | if (obfEntry instanceof ClassEntry) { | 555 | if (obfEntry instanceof ClassEntry) { |
| 550 | this.renamer.setClassName((ClassEntry) obfEntry, Descriptor.toJvmName(newName)); | 556 | this.renamer.setClassName((ClassEntry) obfEntry, newName); |
| 551 | } else if (obfEntry instanceof FieldEntry) { | 557 | } else if (obfEntry instanceof FieldEntry) { |
| 552 | this.renamer.setFieldName((FieldEntry) obfEntry, newName); | 558 | this.renamer.setFieldName((FieldEntry) obfEntry, newName); |
| 553 | } else if (obfEntry instanceof MethodEntry) { | 559 | } else if (obfEntry instanceof MethodEntry) { |
| 560 | if (((MethodEntry) obfEntry).isConstructor()) { | ||
| 561 | throw new IllegalArgumentException("Cannot rename constructors"); | ||
| 562 | } | ||
| 554 | this.renamer.setMethodTreeName((MethodEntry) obfEntry, newName); | 563 | this.renamer.setMethodTreeName((MethodEntry) obfEntry, newName); |
| 555 | } else if (obfEntry instanceof ConstructorEntry) { | ||
| 556 | throw new IllegalArgumentException("Cannot rename constructors"); | ||
| 557 | } else if (obfEntry instanceof ArgumentEntry) { | ||
| 558 | this.renamer.setArgumentTreeName((ArgumentEntry) obfEntry, newName); | ||
| 559 | } else if (obfEntry instanceof LocalVariableEntry) { | 564 | } else if (obfEntry instanceof LocalVariableEntry) { |
| 560 | // TODO: Implement it | 565 | this.renamer.setLocalVariableTreeName((LocalVariableEntry) obfEntry, newName); |
| 561 | } else { | 566 | } else { |
| 562 | throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); | 567 | throw new Error("Unknown entry desc: " + obfEntry.getClass().getName()); |
| 563 | } | 568 | } |
| 564 | 569 | ||
| 565 | // clear caches | 570 | // clear caches |
| @@ -573,13 +578,14 @@ public class Deobfuscator { | |||
| 573 | } else if (obfEntry instanceof FieldEntry) { | 578 | } else if (obfEntry instanceof FieldEntry) { |
| 574 | this.renamer.removeFieldMapping((FieldEntry) obfEntry); | 579 | this.renamer.removeFieldMapping((FieldEntry) obfEntry); |
| 575 | } else if (obfEntry instanceof MethodEntry) { | 580 | } else if (obfEntry instanceof MethodEntry) { |
| 581 | if (((MethodEntry) obfEntry).isConstructor()) { | ||
| 582 | throw new IllegalArgumentException("Cannot rename constructors"); | ||
| 583 | } | ||
| 576 | this.renamer.removeMethodTreeMapping((MethodEntry) obfEntry); | 584 | this.renamer.removeMethodTreeMapping((MethodEntry) obfEntry); |
| 577 | } else if (obfEntry instanceof ConstructorEntry) { | 585 | } else if (obfEntry instanceof LocalVariableEntry) { |
| 578 | throw new IllegalArgumentException("Cannot rename constructors"); | 586 | this.renamer.removeLocalVariableMapping((LocalVariableEntry) obfEntry); |
| 579 | } else if (obfEntry instanceof ArgumentEntry) { | ||
| 580 | this.renamer.removeArgumentMapping((ArgumentEntry) obfEntry); | ||
| 581 | } else { | 587 | } else { |
| 582 | throw new Error("Unknown entry type: " + obfEntry); | 588 | throw new Error("Unknown entry desc: " + obfEntry); |
| 583 | } | 589 | } |
| 584 | 590 | ||
| 585 | // clear caches | 591 | // clear caches |
| @@ -592,15 +598,15 @@ public class Deobfuscator { | |||
| 592 | } else if (obfEntry instanceof FieldEntry) { | 598 | } else if (obfEntry instanceof FieldEntry) { |
| 593 | this.renamer.markFieldAsDeobfuscated((FieldEntry) obfEntry); | 599 | this.renamer.markFieldAsDeobfuscated((FieldEntry) obfEntry); |
| 594 | } else if (obfEntry instanceof MethodEntry) { | 600 | } else if (obfEntry instanceof MethodEntry) { |
| 595 | this.renamer.markMethodTreeAsDeobfuscated((MethodEntry) obfEntry); | 601 | MethodEntry methodEntry = (MethodEntry) obfEntry; |
| 596 | } else if (obfEntry instanceof ConstructorEntry) { | 602 | if (methodEntry.isConstructor()) { |
| 597 | throw new IllegalArgumentException("Cannot rename constructors"); | 603 | throw new IllegalArgumentException("Cannot rename constructors"); |
| 598 | } else if (obfEntry instanceof ArgumentEntry) { | 604 | } |
| 599 | this.renamer.markArgumentAsDeobfuscated((ArgumentEntry) obfEntry); | 605 | this.renamer.markMethodTreeAsDeobfuscated(methodEntry); |
| 600 | } else if (obfEntry instanceof LocalVariableEntry) { | 606 | } else if (obfEntry instanceof LocalVariableEntry) { |
| 601 | // TODO: Implement it | 607 | this.renamer.markArgumentAsDeobfuscated((LocalVariableEntry) obfEntry); |
| 602 | } else { | 608 | } else { |
| 603 | throw new Error("Unknown entry type: " + obfEntry); | 609 | throw new Error("Unknown entry desc: " + obfEntry); |
| 604 | } | 610 | } |
| 605 | 611 | ||
| 606 | // clear caches | 612 | // clear caches |
| @@ -613,17 +619,24 @@ public class Deobfuscator { | |||
| 613 | this.renamer.setClassModifier((ClassEntry) obfEntry, modifierEntry); | 619 | this.renamer.setClassModifier((ClassEntry) obfEntry, modifierEntry); |
| 614 | else if (obfEntry instanceof FieldEntry) | 620 | else if (obfEntry instanceof FieldEntry) |
| 615 | this.renamer.setFieldModifier((FieldEntry) obfEntry, modifierEntry); | 621 | this.renamer.setFieldModifier((FieldEntry) obfEntry, modifierEntry); |
| 616 | else if (obfEntry instanceof BehaviorEntry) | 622 | else if (obfEntry instanceof MethodEntry) |
| 617 | this.renamer.setMethodModifier((BehaviorEntry) obfEntry, modifierEntry); | 623 | this.renamer.setMethodModifier((MethodEntry) obfEntry, modifierEntry); |
| 618 | else | 624 | else |
| 619 | throw new Error("Unknown entry type: " + obfEntry); | 625 | throw new Error("Unknown entry desc: " + obfEntry); |
| 620 | } | 626 | } |
| 621 | 627 | ||
| 622 | public Mappings.EntryModifier getModifier(Entry obEntry) { | 628 | public Mappings.EntryModifier getModifier(Entry obfEntry) { |
| 623 | Entry entry = obfuscateEntry(obEntry); | 629 | Entry entry = obfuscateEntry(obfEntry); |
| 624 | if (entry != null) | 630 | if (entry != null) |
| 625 | obEntry = entry; | 631 | obfEntry = entry; |
| 626 | return getTranslator(TranslationDirection.Deobfuscating).getModifier(obEntry); | 632 | if (obfEntry instanceof ClassEntry) |
| 633 | return this.renamer.getClassModifier((ClassEntry) obfEntry); | ||
| 634 | else if (obfEntry instanceof FieldEntry) | ||
| 635 | return this.renamer.getFieldModifier((FieldEntry) obfEntry); | ||
| 636 | else if (obfEntry instanceof MethodEntry) | ||
| 637 | return this.renamer.getMethodModfifier((MethodEntry) obfEntry); | ||
| 638 | else | ||
| 639 | throw new Error("Unknown entry desc: " + obfEntry); | ||
| 627 | } | 640 | } |
| 628 | 641 | ||
| 629 | public interface ProgressListener { | 642 | public interface ProgressListener { |
| @@ -633,6 +646,6 @@ public class Deobfuscator { | |||
| 633 | } | 646 | } |
| 634 | 647 | ||
| 635 | public interface ClassTransformer { | 648 | public interface ClassTransformer { |
| 636 | CtClass transform(CtClass c) throws Exception; | 649 | void write(ClassNode node, ClassWriter writer); |
| 637 | } | 650 | } |
| 638 | } | 651 | } |