summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar jeff2014-08-25 00:04:47 -0400
committerGravatar jeff2014-08-25 00:04:47 -0400
commit2e97f24a658aa897313cb7cf92ed2e4b4a986bfc (patch)
treef5b97f28a913ecddf5c4902b331540b106a8b128 /src
parentminor bug fixes (diff)
downloadenigma-fork-2e97f24a658aa897313cb7cf92ed2e4b4a986bfc.tar.gz
enigma-fork-2e97f24a658aa897313cb7cf92ed2e4b4a986bfc.tar.xz
enigma-fork-2e97f24a658aa897313cb7cf92ed2e4b4a986bfc.zip
fixed issue with bridge methods so source export has fewer compile errors. =)
Diffstat (limited to 'src')
-rw-r--r--src/cuchaz/enigma/Deobfuscator.java6
-rw-r--r--src/cuchaz/enigma/Main.java3
-rw-r--r--src/cuchaz/enigma/TranslatingTypeLoader.java2
-rw-r--r--src/cuchaz/enigma/analysis/BridgeFixer.java92
-rw-r--r--src/cuchaz/enigma/analysis/JarIndex.java172
5 files changed, 163 insertions, 112 deletions
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index 0bc4a04..8a516b1 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -219,6 +219,12 @@ public class Deobfuscator
219 continue; 219 continue;
220 } 220 }
221 221
222 // TEMP: skip the classes that won't decompile because of a procyon bug
223 if( obfClassEntry.getName().equals( "none/bgl" ) )
224 {
225 continue;
226 }
227
222 ClassEntry deobfClassEntry = deobfuscateEntry( new ClassEntry( obfClassEntry ) ); 228 ClassEntry deobfClassEntry = deobfuscateEntry( new ClassEntry( obfClassEntry ) );
223 if( progress != null ) 229 if( progress != null )
224 { 230 {
diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java
index fe4d6e3..c69b890 100644
--- a/src/cuchaz/enigma/Main.java
+++ b/src/cuchaz/enigma/Main.java
@@ -13,6 +13,7 @@ package cuchaz.enigma;
13import java.io.File; 13import java.io.File;
14 14
15import cuchaz.enigma.gui.Gui; 15import cuchaz.enigma.gui.Gui;
16import cuchaz.enigma.mapping.ClassEntry;
16 17
17public class Main 18public class Main
18{ 19{
@@ -32,7 +33,7 @@ public class Main
32 } 33 }
33 34
34 // DEBUG 35 // DEBUG
35 //gui.getController().openDeclaration( new ClassEntry( "none/bgl" ) ); 36 gui.getController().openDeclaration( new ClassEntry( "none/bsp" ) );
36 } 37 }
37 38
38 private static File getFile( String path ) 39 private static File getFile( String path )
diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java
index 763d767..83f0baa 100644
--- a/src/cuchaz/enigma/TranslatingTypeLoader.java
+++ b/src/cuchaz/enigma/TranslatingTypeLoader.java
@@ -177,7 +177,7 @@ public class TranslatingTypeLoader implements ITypeLoader
177 assertClassName( c, obfClassEntry ); 177 assertClassName( c, obfClassEntry );
178 178
179 // do all kinds of deobfuscating transformations on the class 179 // do all kinds of deobfuscating transformations on the class
180 new BridgeFixer().fixBridges( c ); 180 new BridgeFixer( m_jarIndex ).fixBridges( c );
181 new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c ); 181 new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c );
182 new ClassTranslator( m_deobfuscatingTranslator ).translate( c ); 182 new ClassTranslator( m_deobfuscatingTranslator ).translate( c );
183 183
diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java
deleted file mode 100644
index f13f68f..0000000
--- a/src/cuchaz/enigma/analysis/BridgeFixer.java
+++ /dev/null
@@ -1,92 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.analysis;
12
13import java.util.List;
14
15import javassist.CannotCompileException;
16import javassist.CtClass;
17import javassist.CtMethod;
18import javassist.NotFoundException;
19import javassist.bytecode.AccessFlag;
20import javassist.expr.ExprEditor;
21import javassist.expr.MethodCall;
22
23import com.beust.jcommander.internal.Lists;
24
25public class BridgeFixer
26{
27 public void fixBridges( CtClass c )
28 {
29 // bridge methods are scrubbed and marked as synthetic methods by the obfuscator
30 // need to figure out which synthetics are bridge methods and restore them
31 for( CtMethod method : c.getDeclaredMethods() )
32 {
33 // skip non-synthetic methods
34 if( ( method.getModifiers() & AccessFlag.SYNTHETIC ) == 0 )
35 {
36 continue;
37 }
38
39 CtMethod bridgedMethod = getBridgedMethod( method );
40 if( bridgedMethod != null )
41 {
42 bridgedMethod.setName( method.getName() );
43 method.setModifiers( method.getModifiers() | AccessFlag.BRIDGE );
44
45 // TODO: rename all references to this method?
46 }
47 }
48 }
49
50 private CtMethod getBridgedMethod( CtMethod method )
51 {
52 // bridge methods just call another method, cast it to the return type, and return the result
53 // let's see if we can detect this scenario
54
55 // get all the called methods
56 final List<MethodCall> methodCalls = Lists.newArrayList();
57 try
58 {
59 method.instrument( new ExprEditor( )
60 {
61 @Override
62 public void edit( MethodCall call )
63 {
64 methodCalls.add( call );
65 }
66 } );
67 }
68 catch( CannotCompileException ex )
69 {
70 // this is stupid... we're not even compiling anything
71 throw new Error( ex );
72 }
73
74 // is there just one?
75 if( methodCalls.size() != 1 )
76 {
77 return null;
78 }
79 MethodCall call = methodCalls.get( 0 );
80
81 try
82 {
83 // we have a bridge method!
84 return call.getMethod();
85 }
86 catch( NotFoundException ex )
87 {
88 // can't find the type? not a bridge method
89 return null;
90 }
91 }
92}
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java
index 2c4dec4..cb7508e 100644
--- a/src/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/cuchaz/enigma/analysis/JarIndex.java
@@ -24,6 +24,7 @@ import javassist.CtBehavior;
24import javassist.CtClass; 24import javassist.CtClass;
25import javassist.CtConstructor; 25import javassist.CtConstructor;
26import javassist.CtMethod; 26import javassist.CtMethod;
27import javassist.NotFoundException;
27import javassist.bytecode.AccessFlag; 28import javassist.bytecode.AccessFlag;
28import javassist.bytecode.Descriptor; 29import javassist.bytecode.Descriptor;
29import javassist.bytecode.FieldInfo; 30import javassist.bytecode.FieldInfo;
@@ -60,6 +61,7 @@ public class JarIndex
60 private Multimap<String,String> m_innerClasses; 61 private Multimap<String,String> m_innerClasses;
61 private Map<String,String> m_outerClasses; 62 private Map<String,String> m_outerClasses;
62 private Set<String> m_anonymousClasses; 63 private Set<String> m_anonymousClasses;
64 private Map<MethodEntry,MethodEntry> m_bridgeMethods;
63 65
64 public JarIndex( ) 66 public JarIndex( )
65 { 67 {
@@ -71,11 +73,12 @@ public class JarIndex
71 m_innerClasses = HashMultimap.create(); 73 m_innerClasses = HashMultimap.create();
72 m_outerClasses = Maps.newHashMap(); 74 m_outerClasses = Maps.newHashMap();
73 m_anonymousClasses = Sets.newHashSet(); 75 m_anonymousClasses = Sets.newHashSet();
76 m_bridgeMethods = Maps.newHashMap();
74 } 77 }
75 78
76 public void indexJar( JarFile jar ) 79 public void indexJar( JarFile jar )
77 { 80 {
78 // pass 1: read the class names 81 // step 1: read the class names
79 for( ClassEntry classEntry : JarClassIterator.getClassEntries( jar ) ) 82 for( ClassEntry classEntry : JarClassIterator.getClassEntries( jar ) )
80 { 83 {
81 if( classEntry.isInDefaultPackage() ) 84 if( classEntry.isInDefaultPackage() )
@@ -86,7 +89,7 @@ public class JarIndex
86 m_obfClassEntries.add( classEntry ); 89 m_obfClassEntries.add( classEntry );
87 } 90 }
88 91
89 // pass 2: index the types, methods 92 // step 2: index the types, methods
90 for( CtClass c : JarClassIterator.classes( jar ) ) 93 for( CtClass c : JarClassIterator.classes( jar ) )
91 { 94 {
92 fixClass( c ); 95 fixClass( c );
@@ -97,7 +100,7 @@ public class JarIndex
97 } 100 }
98 } 101 }
99 102
100 // pass 2: index inner classes and anonymous classes 103 // step 3: index inner classes and anonymous classes
101 for( CtClass c : JarClassIterator.classes( jar ) ) 104 for( CtClass c : JarClassIterator.classes( jar ) )
102 { 105 {
103 fixClass( c ); 106 fixClass( c );
@@ -124,13 +127,16 @@ public class JarIndex
124 } 127 }
125 } 128 }
126 129
127 // step 3: update other indicies with inner class info 130 // step 4: update other indices with inner class info
128 Map<String,String> renames = Maps.newHashMap(); 131 Map<String,String> renames = Maps.newHashMap();
129 for( Map.Entry<String,String> entry : m_outerClasses.entrySet() ) 132 for( Map.Entry<String,String> entry : m_outerClasses.entrySet() )
130 { 133 {
131 renames.put( entry.getKey(), entry.getValue() + "$" + entry.getKey() ); 134 renames.put( entry.getKey(), entry.getValue() + "$" + entry.getKey() );
132 } 135 }
133 renameClasses( renames ); 136 renameClasses( renames );
137
138 // step 5: update other indices with bridge method info
139 renameMethods( m_bridgeMethods );
134 } 140 }
135 141
136 private void fixClass( CtClass c ) 142 private void fixClass( CtClass c )
@@ -160,6 +166,18 @@ public class JarIndex
160 166
161 // index implementation 167 // index implementation
162 m_methodImplementations.put( className, methodEntry ); 168 m_methodImplementations.put( className, methodEntry );
169
170 // look for bridge methods
171 CtMethod bridgedMethod = getBridgedMethod( (CtMethod)behavior );
172 if( bridgedMethod != null )
173 {
174 MethodEntry bridgedMethodEntry = new MethodEntry(
175 new ClassEntry( className ),
176 bridgedMethod.getName(),
177 bridgedMethod.getSignature()
178 );
179 m_bridgeMethods.put( bridgedMethodEntry, methodEntry );
180 }
163 } 181 }
164 else if( behavior instanceof CtConstructor ) 182 else if( behavior instanceof CtConstructor )
165 { 183 {
@@ -254,6 +272,56 @@ public class JarIndex
254 } 272 }
255 } 273 }
256 274
275
276 private CtMethod getBridgedMethod( CtMethod method )
277 {
278 // bridge methods just call another method, cast it to the return type, and return the result
279 // let's see if we can detect this scenario
280
281 // skip non-synthetic methods
282 if( ( method.getModifiers() & AccessFlag.SYNTHETIC ) == 0 )
283 {
284 return null;
285 }
286
287 // get all the called methods
288 final List<MethodCall> methodCalls = Lists.newArrayList();
289 try
290 {
291 method.instrument( new ExprEditor( )
292 {
293 @Override
294 public void edit( MethodCall call )
295 {
296 methodCalls.add( call );
297 }
298 } );
299 }
300 catch( CannotCompileException ex )
301 {
302 // this is stupid... we're not even compiling anything
303 throw new Error( ex );
304 }
305
306 // is there just one?
307 if( methodCalls.size() != 1 )
308 {
309 return null;
310 }
311 MethodCall call = methodCalls.get( 0 );
312
313 try
314 {
315 // we have a bridge method!
316 return call.getMethod();
317 }
318 catch( NotFoundException ex )
319 {
320 // can't find the type? not a bridge method
321 return null;
322 }
323 }
324
257 private String findOuterClass( CtClass c ) 325 private String findOuterClass( CtClass c )
258 { 326 {
259 // inner classes: 327 // inner classes:
@@ -534,15 +602,27 @@ public class JarIndex
534 return m_anonymousClasses.contains( obfInnerClassName ); 602 return m_anonymousClasses.contains( obfInnerClassName );
535 } 603 }
536 604
605 public MethodEntry getBridgeMethod( MethodEntry methodEntry )
606 {
607 return m_bridgeMethods.get( methodEntry );
608 }
609
537 private void renameClasses( Map<String,String> renames ) 610 private void renameClasses( Map<String,String> renames )
538 { 611 {
539 m_ancestries.renameClasses( renames ); 612 m_ancestries.renameClasses( renames );
540 renameMultimap( renames, m_methodImplementations ); 613 renameClassesInMultimap( renames, m_methodImplementations );
541 renameMultimap( renames, m_behaviorReferences ); 614 renameClassesInMultimap( renames, m_behaviorReferences );
542 renameMultimap( renames, m_fieldReferences ); 615 renameClassesInMultimap( renames, m_fieldReferences );
616 }
617
618 private void renameMethods( Map<MethodEntry,MethodEntry> renames )
619 {
620 renameMethodsInMultimap( renames, m_methodImplementations );
621 renameMethodsInMultimap( renames, m_behaviorReferences );
622 renameMethodsInMultimap( renames, m_fieldReferences );
543 } 623 }
544 624
545 private <Key,Val> void renameMultimap( Map<String,String> renames, Multimap<Key,Val> map ) 625 private <Key,Val> void renameClassesInMultimap( Map<String,String> renames, Multimap<Key,Val> map )
546 { 626 {
547 // for each key/value pair... 627 // for each key/value pair...
548 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); 628 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet();
@@ -552,8 +632,8 @@ public class JarIndex
552 Map.Entry<Key,Val> entry = iter.next(); 632 Map.Entry<Key,Val> entry = iter.next();
553 iter.remove(); 633 iter.remove();
554 entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( 634 entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>(
555 renameThing( renames, entry.getKey() ), 635 renameClassesInThing( renames, entry.getKey() ),
556 renameThing( renames, entry.getValue() ) 636 renameClassesInThing( renames, entry.getValue() )
557 ) ); 637 ) );
558 } 638 }
559 for( Map.Entry<Key,Val> entry : entriesToAdd ) 639 for( Map.Entry<Key,Val> entry : entriesToAdd )
@@ -563,7 +643,7 @@ public class JarIndex
563 } 643 }
564 644
565 @SuppressWarnings( "unchecked" ) 645 @SuppressWarnings( "unchecked" )
566 private <T> T renameThing( Map<String,String> renames, T thing ) 646 private <T> T renameClassesInThing( Map<String,String> renames, T thing )
567 { 647 {
568 if( thing instanceof String ) 648 if( thing instanceof String )
569 { 649 {
@@ -576,13 +656,13 @@ public class JarIndex
576 else if( thing instanceof ClassEntry ) 656 else if( thing instanceof ClassEntry )
577 { 657 {
578 ClassEntry classEntry = (ClassEntry)thing; 658 ClassEntry classEntry = (ClassEntry)thing;
579 return (T)new ClassEntry( renameThing( renames, classEntry.getClassName() ) ); 659 return (T)new ClassEntry( renameClassesInThing( renames, classEntry.getClassName() ) );
580 } 660 }
581 else if( thing instanceof FieldEntry ) 661 else if( thing instanceof FieldEntry )
582 { 662 {
583 FieldEntry fieldEntry = (FieldEntry)thing; 663 FieldEntry fieldEntry = (FieldEntry)thing;
584 return (T)new FieldEntry( 664 return (T)new FieldEntry(
585 renameThing( renames, fieldEntry.getClassEntry() ), 665 renameClassesInThing( renames, fieldEntry.getClassEntry() ),
586 fieldEntry.getName() 666 fieldEntry.getName()
587 ); 667 );
588 } 668 }
@@ -590,7 +670,7 @@ public class JarIndex
590 { 670 {
591 ConstructorEntry constructorEntry = (ConstructorEntry)thing; 671 ConstructorEntry constructorEntry = (ConstructorEntry)thing;
592 return (T)new ConstructorEntry( 672 return (T)new ConstructorEntry(
593 renameThing( renames, constructorEntry.getClassEntry() ), 673 renameClassesInThing( renames, constructorEntry.getClassEntry() ),
594 constructorEntry.getSignature() 674 constructorEntry.getSignature()
595 ); 675 );
596 } 676 }
@@ -598,7 +678,7 @@ public class JarIndex
598 { 678 {
599 MethodEntry methodEntry = (MethodEntry)thing; 679 MethodEntry methodEntry = (MethodEntry)thing;
600 return (T)new MethodEntry( 680 return (T)new MethodEntry(
601 renameThing( renames, methodEntry.getClassEntry() ), 681 renameClassesInThing( renames, methodEntry.getClassEntry() ),
602 methodEntry.getName(), 682 methodEntry.getName(),
603 methodEntry.getSignature() 683 methodEntry.getSignature()
604 ); 684 );
@@ -607,7 +687,7 @@ public class JarIndex
607 { 687 {
608 ArgumentEntry argumentEntry = (ArgumentEntry)thing; 688 ArgumentEntry argumentEntry = (ArgumentEntry)thing;
609 return (T)new ArgumentEntry( 689 return (T)new ArgumentEntry(
610 renameThing( renames, argumentEntry.getMethodEntry() ), 690 renameClassesInThing( renames, argumentEntry.getMethodEntry() ),
611 argumentEntry.getIndex(), 691 argumentEntry.getIndex(),
612 argumentEntry.getName() 692 argumentEntry.getName()
613 ); 693 );
@@ -615,8 +695,8 @@ public class JarIndex
615 else if( thing instanceof EntryReference ) 695 else if( thing instanceof EntryReference )
616 { 696 {
617 EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing; 697 EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing;
618 reference.entry = renameThing( renames, reference.entry ); 698 reference.entry = renameClassesInThing( renames, reference.entry );
619 reference.context = renameThing( renames, reference.context ); 699 reference.context = renameClassesInThing( renames, reference.context );
620 return thing; 700 return thing;
621 } 701 }
622 else 702 else
@@ -626,4 +706,60 @@ public class JarIndex
626 706
627 return thing; 707 return thing;
628 } 708 }
709
710 private <Key,Val> void renameMethodsInMultimap( Map<MethodEntry,MethodEntry> renames, Multimap<Key,Val> map )
711 {
712 // for each key/value pair...
713 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet();
714 Iterator<Map.Entry<Key,Val>> iter = map.entries().iterator();
715 while( iter.hasNext() )
716 {
717 Map.Entry<Key,Val> entry = iter.next();
718 iter.remove();
719 entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>(
720 renameMethodsInThing( renames, entry.getKey() ),
721 renameMethodsInThing( renames, entry.getValue() )
722 ) );
723 }
724 for( Map.Entry<Key,Val> entry : entriesToAdd )
725 {
726 map.put( entry.getKey(), entry.getValue() );
727 }
728 }
729
730 @SuppressWarnings( "unchecked" )
731 private <T> T renameMethodsInThing( Map<MethodEntry,MethodEntry> renames, T thing )
732 {
733 if( thing instanceof MethodEntry )
734 {
735 MethodEntry methodEntry = (MethodEntry)thing;
736 MethodEntry newMethodEntry = renames.get( methodEntry );
737 if( newMethodEntry != null )
738 {
739 return (T)new MethodEntry(
740 methodEntry.getClassEntry(),
741 newMethodEntry.getName(),
742 methodEntry.getSignature()
743 );
744 }
745 return thing;
746 }
747 else if( thing instanceof ArgumentEntry )
748 {
749 ArgumentEntry argumentEntry = (ArgumentEntry)thing;
750 return (T)new ArgumentEntry(
751 renameMethodsInThing( renames, argumentEntry.getMethodEntry() ),
752 argumentEntry.getIndex(),
753 argumentEntry.getName()
754 );
755 }
756 else if( thing instanceof EntryReference )
757 {
758 EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing;
759 reference.entry = renameMethodsInThing( renames, reference.entry );
760 reference.context = renameMethodsInThing( renames, reference.context );
761 return thing;
762 }
763 return thing;
764 }
629} 765}