summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/cuchaz/enigma/ConvertMain.java14
-rw-r--r--src/main/java/cuchaz/enigma/Deobfuscator.java25
-rw-r--r--src/main/java/cuchaz/enigma/convert/MappingsConverter.java149
3 files changed, 165 insertions, 23 deletions
diff --git a/src/main/java/cuchaz/enigma/ConvertMain.java b/src/main/java/cuchaz/enigma/ConvertMain.java
index 67baeae9..1890aef1 100644
--- a/src/main/java/cuchaz/enigma/ConvertMain.java
+++ b/src/main/java/cuchaz/enigma/ConvertMain.java
@@ -63,7 +63,7 @@ public class ConvertMain {
63 editFieldMatches(sourceJar, destJar, outMappingsFile, mappings, classMatchesFile, fieldMatchesFile); 63 editFieldMatches(sourceJar, destJar, outMappingsFile, mappings, classMatchesFile, fieldMatchesFile);
64 convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchesFile, fieldMatchesFile); 64 convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchesFile, fieldMatchesFile);
65 } else if (command.equalsIgnoreCase("computeMethodMatches")) { 65 } else if (command.equalsIgnoreCase("computeMethodMatches")) {
66 computeMethodMatches(methodMatchesFile, destJar, outMappingsFile, classMatchesFile); 66 computeMethodMatches(outMappingsFile, sourceJar, destJar, mappings, classMatchesFile, fieldMatchesFile, methodMatchesFile);
67 convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchesFile, fieldMatchesFile, methodMatchesFile); 67 convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchesFile, fieldMatchesFile, methodMatchesFile);
68 } else if (command.equalsIgnoreCase("editMethodMatches")) { 68 } else if (command.equalsIgnoreCase("editMethodMatches")) {
69 editMethodMatches(sourceJar, destJar, outMappingsFile, mappings, classMatchesFile, methodMatchesFile); 69 editMethodMatches(sourceJar, destJar, outMappingsFile, mappings, classMatchesFile, methodMatchesFile);
@@ -224,22 +224,26 @@ public class ConvertMain {
224 } 224 }
225 225
226 226
227 private static void computeMethodMatches(File methodMatchesFile, JarFile destJar, File destMappingsFile, File classMatchesFile) 227 private static void computeMethodMatches(File outMappingsFile, JarFile sourceJar, JarFile destJar, Mappings sourceMappings, File classMatchesFile, File fieldMatchesFile, File methodMatchesFile)
228 throws IOException, MappingParseException { 228 throws IOException, MappingParseException {
229 229
230 System.out.println("Reading class matches..."); 230 System.out.println("Reading class matches...");
231 ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile); 231 ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile);
232 System.out.println("Reading mappings..."); 232 System.out.println("Reading dest mappings...");
233 Mappings destMappings = new MappingsEnigmaReader().read(destMappingsFile); 233 Mappings destMappings = new MappingsEnigmaReader().read(outMappingsFile);
234 System.out.println("Indexing dest jar..."); 234 System.out.println("Indexing dest jar...");
235 Deobfuscator destDeobfuscator = new Deobfuscator(destJar); 235 Deobfuscator destDeobfuscator = new Deobfuscator(destJar);
236 System.out.println("Indexing source jar...");
237 Deobfuscator sourceDeobfuscator = new Deobfuscator(sourceJar);
236 238
237 System.out.println("Writing method matches..."); 239 System.out.println("Writing method matches...");
238 240
239 // get the matched and unmatched mappings 241 // get the matched and unmatched mappings
240 MemberMatches<BehaviorEntry> methodMatches = MappingsConverter.computeMemberMatches( 242 MemberMatches<BehaviorEntry> methodMatches = MappingsConverter.computeMethodsMatches(
241 destDeobfuscator, 243 destDeobfuscator,
242 destMappings, 244 destMappings,
245 sourceDeobfuscator,
246 sourceMappings,
243 classMatches, 247 classMatches,
244 MappingsConverter.getMethodDoer() 248 MappingsConverter.getMethodDoer()
245 ); 249 );
diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java
index fe0e31dc..2766380b 100644
--- a/src/main/java/cuchaz/enigma/Deobfuscator.java
+++ b/src/main/java/cuchaz/enigma/Deobfuscator.java
@@ -156,6 +156,16 @@ public class Deobfuscator {
156 } 156 }
157 } 157 }
158 158
159 public TranslatingTypeLoader createTypeLoader()
160 {
161 return new TranslatingTypeLoader(
162 this.jar,
163 this.jarIndex,
164 getTranslator(TranslationDirection.Obfuscating),
165 getTranslator(TranslationDirection.Deobfuscating)
166 );
167 }
168
159 public CompilationUnit getSourceTree(String className) { 169 public CompilationUnit getSourceTree(String className) {
160 170
161 // we don't know if this class name is obfuscated or deobfuscated 171 // we don't know if this class name is obfuscated or deobfuscated
@@ -172,12 +182,7 @@ public class Deobfuscator {
172 } 182 }
173 183
174 // set the type loader 184 // set the type loader
175 TranslatingTypeLoader loader = new TranslatingTypeLoader( 185 TranslatingTypeLoader loader = createTypeLoader();
176 this.jar,
177 this.jarIndex,
178 getTranslator(TranslationDirection.Obfuscating),
179 getTranslator(TranslationDirection.Deobfuscating)
180 );
181 this.settings.setTypeLoader(loader); 186 this.settings.setTypeLoader(loader);
182 187
183 // see if procyon can find the type 188 // see if procyon can find the type
@@ -383,13 +388,7 @@ public class Deobfuscator {
383 } 388 }
384 389
385 public void writeJar(File out, ProgressListener progress) { 390 public void writeJar(File out, ProgressListener progress) {
386 final TranslatingTypeLoader loader = new TranslatingTypeLoader( 391 transformJar(out, progress, createTypeLoader()::transformClass);
387 this.jar,
388 this.jarIndex,
389 getTranslator(TranslationDirection.Obfuscating),
390 getTranslator(TranslationDirection.Deobfuscating)
391 );
392 transformJar(out, progress, loader::transformClass);
393 } 392 }
394 393
395 public void protectifyJar(File out, ProgressListener progress) { 394 public void protectifyJar(File out, ProgressListener progress) {
diff --git a/src/main/java/cuchaz/enigma/convert/MappingsConverter.java b/src/main/java/cuchaz/enigma/convert/MappingsConverter.java
index 9b06a511..929c89f2 100644
--- a/src/main/java/cuchaz/enigma/convert/MappingsConverter.java
+++ b/src/main/java/cuchaz/enigma/convert/MappingsConverter.java
@@ -13,10 +13,18 @@ package cuchaz.enigma.convert;
13import com.google.common.collect.*; 13import com.google.common.collect.*;
14import cuchaz.enigma.Constants; 14import cuchaz.enigma.Constants;
15import cuchaz.enigma.Deobfuscator; 15import cuchaz.enigma.Deobfuscator;
16import cuchaz.enigma.TranslatingTypeLoader;
16import cuchaz.enigma.analysis.JarIndex; 17import cuchaz.enigma.analysis.JarIndex;
17import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; 18import cuchaz.enigma.convert.ClassNamer.SidedClassNamer;
18import cuchaz.enigma.mapping.*; 19import cuchaz.enigma.mapping.*;
19import cuchaz.enigma.throwables.MappingConflict; 20import cuchaz.enigma.throwables.MappingConflict;
21import javassist.CtClass;
22import javassist.CtMethod;
23import javassist.NotFoundException;
24import javassist.bytecode.BadBytecode;
25import javassist.bytecode.CodeAttribute;
26import javassist.bytecode.CodeIterator;
27import javassist.bytecode.MethodInfo;
20 28
21import java.util.*; 29import java.util.*;
22import java.util.jar.JarFile; 30import java.util.jar.JarFile;
@@ -364,11 +372,9 @@ public class MappingsConverter {
364 public Set<BehaviorEntry> filterEntries(Collection<BehaviorEntry> obfDestFields, BehaviorEntry obfSourceField, ClassMatches classMatches) { 372 public Set<BehaviorEntry> filterEntries(Collection<BehaviorEntry> obfDestFields, BehaviorEntry obfSourceField, ClassMatches classMatches) {
365 Set<BehaviorEntry> out = Sets.newHashSet(); 373 Set<BehaviorEntry> out = Sets.newHashSet();
366 for (BehaviorEntry obfDestField : obfDestFields) { 374 for (BehaviorEntry obfDestField : obfDestFields) {
367 Signature translatedDestSignature = translate(obfDestField.getSignature(), 375 // Try to translate the signature
368 classMatches.getUniqueMatches().inverse()); 376 Signature translatedDestSignature = translate(obfDestField.getSignature(), classMatches.getUniqueMatches().inverse());
369 if ((translatedDestSignature == null && obfSourceField.getSignature() == null) 377 if (translatedDestSignature != null && obfSourceField.getSignature() != null && translatedDestSignature.equals(obfSourceField.getSignature()))
370 || translatedDestSignature != null && obfSourceField.getSignature() != null
371 && translatedDestSignature.equals(obfSourceField.getSignature()))
372 out.add(obfDestField); 378 out.add(obfDestField);
373 } 379 }
374 return out; 380 return out;
@@ -392,6 +398,139 @@ public class MappingsConverter {
392 }; 398 };
393 } 399 }
394 400
401 public static int compareMethodByteCode(CodeIterator sourceIt, CodeIterator destIt)
402 {
403 int sourcePos = 0;
404 int destPos = 0;
405 while (sourceIt.hasNext() && destIt.hasNext())
406 {
407 try
408 {
409 sourcePos = sourceIt.next();
410 destPos = destIt.next();
411 if (sourceIt.byteAt(sourcePos) != destIt.byteAt(destPos))
412 return sourcePos;
413 } catch (BadBytecode badBytecode)
414 {
415 // Ignore bad bytecode (it might be a little bit dangerous...)
416 }
417 }
418 if (sourcePos < destPos)
419 return sourcePos;
420 else if (destPos < sourcePos)
421 return destPos;
422 return sourcePos;
423 }
424
425 public static BehaviorEntry compareMethods(CtClass destCtClass, CtClass sourceCtClass, BehaviorEntry obfSourceEntry,
426 Set<BehaviorEntry> obfDestEntries)
427 {
428 try
429 {
430 // Get the source method with Javassist
431 CtMethod sourceCtClassMethod = sourceCtClass.getMethod(obfSourceEntry.getName(), obfSourceEntry.getSignature().toString());
432 CodeAttribute sourceAttribute = sourceCtClassMethod.getMethodInfo().getCodeAttribute();
433
434 // Empty method body, ignore!
435 if (sourceAttribute == null)
436 return null;
437 Iterator<BehaviorEntry> it = obfDestEntries.iterator();
438 while (it.hasNext())
439 {
440 BehaviorEntry desEntry = it.next();
441 try
442 {
443 CtMethod destCtClassMethod = destCtClass.getMethod(desEntry.getName(), desEntry.getSignature().toString());
444 CodeAttribute destAttribute = destCtClassMethod.getMethodInfo().getCodeAttribute();
445
446 // Ignore empty body methods
447 if (destAttribute == null)
448 continue;
449 CodeIterator destIterator = destAttribute.iterator();
450 int maxPos = compareMethodByteCode(sourceAttribute.iterator(), destIterator);
451
452 // The bytecode is identical to the original method, assuming that the method is correct!
453 if (sourceAttribute.getCodeLength() == (maxPos + 1) && maxPos > 1)
454 return desEntry;
455 } catch (NotFoundException e)
456 {
457 e.printStackTrace();
458 }
459 }
460 } catch (NotFoundException e)
461 {
462 e.printStackTrace();
463 return null;
464 }
465 return null;
466 }
467
468 public static MemberMatches<BehaviorEntry> computeMethodsMatches(Deobfuscator destDeobfuscator, Mappings destMappings, Deobfuscator sourceDeobfuscator, Mappings sourceMappings, ClassMatches classMatches, Doer<BehaviorEntry> doer) {
469
470 MemberMatches<BehaviorEntry> memberMatches = new MemberMatches<>();
471
472 // unmatched source fields are easy
473 MappingsChecker checker = new MappingsChecker(destDeobfuscator.getJarIndex());
474 checker.dropBrokenMappings(destMappings);
475 for (BehaviorEntry destObfEntry : doer.getDroppedEntries(checker)) {
476 BehaviorEntry srcObfEntry = translate(destObfEntry, classMatches.getUniqueMatches().inverse());
477 memberMatches.addUnmatchedSourceEntry(srcObfEntry);
478 }
479
480 // get matched fields (anything that's left after the checks/drops is matched(
481 for (ClassMapping classMapping : destMappings.classes())
482 collectMatchedFields(memberMatches, classMapping, classMatches, doer);
483
484 // get unmatched dest fields
485 doer.getObfEntries(destDeobfuscator.getJarIndex()).stream()
486 .filter(destEntry -> !memberMatches.isMatchedDestEntry(destEntry))
487 .forEach(memberMatches::addUnmatchedDestEntry);
488
489 // Apply mappings to deobfuscator
490
491 // Create type loader
492 TranslatingTypeLoader destTypeLoader = destDeobfuscator.createTypeLoader();
493 TranslatingTypeLoader sourceTypeLoader = sourceDeobfuscator.createTypeLoader();
494
495 System.out.println("Automatching " + memberMatches.getUnmatchedSourceEntries().size() + " unmatched source entries...");
496
497 // go through the unmatched source fields and try to pick out the easy matches
498 for (ClassEntry obfSourceClass : Lists.newArrayList(memberMatches.getSourceClassesWithUnmatchedEntries())) {
499 for (BehaviorEntry obfSourceEntry : Lists.newArrayList(memberMatches.getUnmatchedSourceEntries(obfSourceClass))) {
500
501 // get the possible dest matches
502 ClassEntry obfDestClass = classMatches.getUniqueMatches().get(obfSourceClass);
503
504 // filter by type/signature
505 Set<BehaviorEntry> obfDestEntries = doer.filterEntries(memberMatches.getUnmatchedDestEntries(obfDestClass), obfSourceEntry, classMatches);
506
507 if (obfDestEntries.size() == 1) {
508 // make the easy match
509 memberMatches.makeMatch(obfSourceEntry, obfDestEntries.iterator().next());
510 } else if (obfDestEntries.isEmpty()) {
511 // no match is possible =(
512 memberMatches.makeSourceUnmatchable(obfSourceEntry, null);
513 } else
514 {
515 // Multiple matches! Scan methods instructions
516 CtClass destCtClass = destTypeLoader.loadClass(obfDestClass.getClassName());
517 CtClass sourceCtClass = sourceTypeLoader.loadClass(obfSourceClass.getClassName());
518 BehaviorEntry match = compareMethods(destCtClass, sourceCtClass, obfSourceEntry, obfDestEntries);
519 // the method match correctly, match it on the member mapping!
520 if (match != null)
521 memberMatches.makeMatch(obfSourceEntry, match);
522 }
523 }
524 }
525
526 System.out.println(String.format("Ended up with %d ambiguous and %d unmatchable source entries",
527 memberMatches.getUnmatchedSourceEntries().size(),
528 memberMatches.getUnmatchableSourceEntries().size()
529 ));
530
531 return memberMatches;
532 }
533
395 public static <T extends Entry> MemberMatches<T> computeMemberMatches(Deobfuscator destDeobfuscator, Mappings destMappings, ClassMatches classMatches, Doer<T> doer) { 534 public static <T extends Entry> MemberMatches<T> computeMemberMatches(Deobfuscator destDeobfuscator, Mappings destMappings, ClassMatches classMatches, Doer<T> doer) {
396 535
397 MemberMatches<T> memberMatches = new MemberMatches<T>(); 536 MemberMatches<T> memberMatches = new MemberMatches<T>();