summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar jeff2014-09-28 16:48:54 -0400
committerGravatar jeff2014-09-28 16:48:54 -0400
commit3e9960f8a712e8590b3ab3126d823504027516da (patch)
tree3a437ef90fcfde1eaa8bf3e8ab3b4f946aa1bab2
parentargument names now default to the names chosen by Procyon (diff)
downloadenigma-3e9960f8a712e8590b3ab3126d823504027516da.tar.gz
enigma-3e9960f8a712e8590b3ab3126d823504027516da.tar.xz
enigma-3e9960f8a712e8590b3ab3126d823504027516da.zip
added jar export
-rw-r--r--src/cuchaz/enigma/Deobfuscator.java67
-rw-r--r--src/cuchaz/enigma/TranslatingTypeLoader.java59
-rw-r--r--src/cuchaz/enigma/gui/Gui.java37
-rw-r--r--src/cuchaz/enigma/gui/GuiController.java37
-rw-r--r--src/cuchaz/enigma/gui/ProgressDialog.java36
5 files changed, 177 insertions, 59 deletions
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index ff83d21a..9235cf74 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -12,14 +12,18 @@
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import java.io.File; 14import java.io.File;
15import java.io.FileOutputStream;
15import java.io.FileWriter; 16import java.io.FileWriter;
16import java.io.IOException; 17import java.io.IOException;
17import java.io.StringWriter; 18import java.io.StringWriter;
18import java.util.List; 19import java.util.List;
19import java.util.Map; 20import java.util.Map;
20import java.util.Set; 21import java.util.Set;
22import java.util.jar.JarEntry;
21import java.util.jar.JarFile; 23import java.util.jar.JarFile;
24import java.util.jar.JarOutputStream;
22 25
26import javassist.CtClass;
23import javassist.bytecode.Descriptor; 27import javassist.bytecode.Descriptor;
24 28
25import com.google.common.collect.Lists; 29import com.google.common.collect.Lists;
@@ -36,11 +40,11 @@ import com.strobel.decompiler.languages.java.ast.CompilationUnit;
36import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; 40import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor;
37 41
38import cuchaz.enigma.analysis.EntryReference; 42import cuchaz.enigma.analysis.EntryReference;
43import cuchaz.enigma.analysis.JarClassIterator;
39import cuchaz.enigma.analysis.JarIndex; 44import cuchaz.enigma.analysis.JarIndex;
40import cuchaz.enigma.analysis.SourceIndex; 45import cuchaz.enigma.analysis.SourceIndex;
41import cuchaz.enigma.analysis.SourceIndexVisitor; 46import cuchaz.enigma.analysis.SourceIndexVisitor;
42import cuchaz.enigma.analysis.Token; 47import cuchaz.enigma.analysis.Token;
43import cuchaz.enigma.analysis.TreeDumpVisitor;
44import cuchaz.enigma.mapping.ArgumentEntry; 48import cuchaz.enigma.mapping.ArgumentEntry;
45import cuchaz.enigma.mapping.BehaviorEntry; 49import cuchaz.enigma.mapping.BehaviorEntry;
46import cuchaz.enigma.mapping.BehaviorEntryFactory; 50import cuchaz.enigma.mapping.BehaviorEntryFactory;
@@ -61,7 +65,7 @@ public class Deobfuscator
61{ 65{
62 public interface ProgressListener 66 public interface ProgressListener
63 { 67 {
64 void init( int totalWork ); 68 void init( int totalWork, String title );
65 void onProgress( int numDone, String message ); 69 void onProgress( int numDone, String message );
66 } 70 }
67 71
@@ -393,7 +397,7 @@ public class Deobfuscator
393 397
394 if( progress != null ) 398 if( progress != null )
395 { 399 {
396 progress.init( classEntries.size() ); 400 progress.init( classEntries.size(), "Decompiling classes..." );
397 } 401 }
398 402
399 // DEOBFUSCATE ALL THE THINGS!! @_@ 403 // DEOBFUSCATE ALL THE THINGS!! @_@
@@ -424,9 +428,60 @@ public class Deobfuscator
424 throw new Error( "Unable to deobfuscate class " + deobfClassEntry.toString() + " (" + obfClassEntry.toString() + ")", t ); 428 throw new Error( "Unable to deobfuscate class " + deobfClassEntry.toString() + " (" + obfClassEntry.toString() + ")", t );
425 } 429 }
426 } 430 }
427 431 if( progress != null )
428 // done! 432 {
429 progress.onProgress( classEntries.size(), "Done!" ); 433 progress.onProgress( i, "Done!" );
434 }
435 }
436
437 public void writeJar( File out, ProgressListener progress )
438 {
439 try( JarOutputStream outJar = new JarOutputStream( new FileOutputStream( out ) ) )
440 {
441 if( progress != null )
442 {
443 progress.init( JarClassIterator.getClassEntries( m_jar ).size(), "Translating classes..." );
444 }
445
446 // prep the loader
447 TranslatingTypeLoader loader = new TranslatingTypeLoader(
448 m_jar,
449 m_jarIndex,
450 getTranslator( TranslationDirection.Obfuscating ),
451 getTranslator( TranslationDirection.Deobfuscating )
452 );
453
454 int i = 0;
455 for( CtClass c : JarClassIterator.classes( m_jar ) )
456 {
457 if( progress != null )
458 {
459 progress.onProgress( i++, c.getName() );
460 }
461
462 try
463 {
464 c = loader.transformClass( c );
465 outJar.putNextEntry( new JarEntry( c.getName().replace( '.', '/' ) + ".class" ) );
466 outJar.write( c.toBytecode() );
467 outJar.closeEntry();
468 }
469 catch( Throwable t )
470 {
471 throw new Error( "Unable to deobfuscate class " + c.getName(), t );
472 }
473 }
474 if( progress != null )
475 {
476 progress.onProgress( i, "Done!" );
477 }
478
479 outJar.close();
480 }
481 catch( IOException ex )
482 {
483 throw new Error( "Unable to write to Jar file!" );
484 }
430 } 485 }
431 486
432 public <T extends Entry> T obfuscateEntry( T deobfEntry ) 487 public <T extends Entry> T obfuscateEntry( T deobfEntry )
diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java
index 8b969857..6179879a 100644
--- a/src/cuchaz/enigma/TranslatingTypeLoader.java
+++ b/src/cuchaz/enigma/TranslatingTypeLoader.java
@@ -13,7 +13,6 @@ package cuchaz.enigma;
13import java.io.ByteArrayOutputStream; 13import java.io.ByteArrayOutputStream;
14import java.io.IOException; 14import java.io.IOException;
15import java.io.InputStream; 15import java.io.InputStream;
16import java.util.Arrays;
17import java.util.Map; 16import java.util.Map;
18import java.util.jar.JarEntry; 17import java.util.jar.JarEntry;
19import java.util.jar.JarFile; 18import java.util.jar.JarFile;
@@ -157,12 +156,13 @@ public class TranslatingTypeLoader implements ITypeLoader
157 // otherwise, just use the class name (ie for classes in packages) 156 // otherwise, just use the class name (ie for classes in packages)
158 classFileName = obfClassEntry.getName(); 157 classFileName = obfClassEntry.getName();
159 } 158 }
159
160 JarEntry entry = m_jar.getJarEntry( classFileName + ".class" ); 160 JarEntry entry = m_jar.getJarEntry( classFileName + ".class" );
161 if( entry == null ) 161 if( entry == null )
162 { 162 {
163 return null; 163 return null;
164 } 164 }
165 165
166 try 166 try
167 { 167 {
168 // read the class file into a buffer 168 // read the class file into a buffer
@@ -188,33 +188,11 @@ public class TranslatingTypeLoader implements ITypeLoader
188 classPool.insertClassPath( new ByteArrayClassPath( javaClassFileName, buf ) ); 188 classPool.insertClassPath( new ByteArrayClassPath( javaClassFileName, buf ) );
189 CtClass c = classPool.get( javaClassFileName ); 189 CtClass c = classPool.get( javaClassFileName );
190 190
191 // we moved a lot of classes out of the default package into the none package 191 c = transformClass( c );
192 // make sure all the class references are consistent
193 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage );
194
195 // reconstruct inner classes
196 new InnerClassWriter( m_jarIndex ).write( c );
197
198 // re-get the javassist handle since we changed class names
199 String javaClassReconstructedName = Descriptor.toJavaName( obfClassEntry.getName() );
200 classPool = new ClassPool();
201 classPool.insertClassPath( new ByteArrayClassPath( javaClassReconstructedName, c.toBytecode() ) );
202 c = classPool.get( javaClassReconstructedName );
203
204 // check that the file is correct after inner class reconstruction (ie cause Javassist to fail fast if something is wrong)
205 assertClassName( c, obfClassEntry );
206
207 // do all kinds of deobfuscating transformations on the class
208 new BridgeFixer( m_jarIndex ).fixBridges( c );
209 new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c );
210 new ClassTranslator( m_deobfuscatingTranslator ).translate( c );
211 192
212 // sanity checking 193 // sanity checking
213 assertClassName( c, deobfClassEntry ); 194 assertClassName( c, deobfClassEntry );
214 195
215 // DEBUG
216 //Util.writeClass( c );
217
218 // we have a transformed class! 196 // we have a transformed class!
219 return c.toBytecode(); 197 return c.toBytecode();
220 } 198 }
@@ -223,6 +201,37 @@ public class TranslatingTypeLoader implements ITypeLoader
223 throw new Error( ex ); 201 throw new Error( ex );
224 } 202 }
225 } 203 }
204
205 public CtClass transformClass( CtClass c )
206 throws IOException, NotFoundException, CannotCompileException
207 {
208 // we moved a lot of classes out of the default package into the none package
209 // make sure all the class references are consistent
210 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage );
211
212 // reconstruct inner classes
213 new InnerClassWriter( m_jarIndex ).write( c );
214
215 // re-get the javassist handle since we changed class names
216 ClassEntry obfClassEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) );
217 String javaClassReconstructedName = Descriptor.toJavaName( obfClassEntry.getName() );
218 ClassPool classPool = new ClassPool();
219 classPool.insertClassPath( new ByteArrayClassPath( javaClassReconstructedName, c.toBytecode() ) );
220 c = classPool.get( javaClassReconstructedName );
221
222 // check that the file is correct after inner class reconstruction (ie cause Javassist to fail fast if something is wrong)
223 assertClassName( c, obfClassEntry );
224
225 // do all kinds of deobfuscating transformations on the class
226 new BridgeFixer( m_jarIndex ).fixBridges( c );
227 new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c );
228 new ClassTranslator( m_deobfuscatingTranslator ).translate( c );
229
230 // DEBUG
231 //Util.writeClass( c );
232
233 return c;
234 }
226 235
227 private void assertClassName( CtClass c, ClassEntry obfClassEntry ) 236 private void assertClassName( CtClass c, ClassEntry obfClassEntry )
228 { 237 {
diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java
index 920bc0b9..dbfcba83 100644
--- a/src/cuchaz/enigma/gui/Gui.java
+++ b/src/cuchaz/enigma/gui/Gui.java
@@ -123,12 +123,15 @@ public class Gui
123 private JMenuItem m_showCallsMenu; 123 private JMenuItem m_showCallsMenu;
124 private JMenuItem m_showImplementationsMenu; 124 private JMenuItem m_showImplementationsMenu;
125 private JMenuItem m_toggleMappingMenu; 125 private JMenuItem m_toggleMappingMenu;
126 private JMenuItem m_exportSourceMenu;
127 private JMenuItem m_exportJarMenu;
126 128
127 // state 129 // state
128 private EntryReference<Entry,Entry> m_reference; 130 private EntryReference<Entry,Entry> m_reference;
129 private JFileChooser m_jarFileChooser; 131 private JFileChooser m_jarFileChooser;
130 private JFileChooser m_mappingsFileChooser; 132 private JFileChooser m_mappingsFileChooser;
131 private JFileChooser m_exportFileChooser; 133 private JFileChooser m_exportSourceFileChooser;
134 private JFileChooser m_exportJarFileChooser;
132 135
133 public Gui( ) 136 public Gui( )
134 { 137 {
@@ -157,8 +160,9 @@ public class Gui
157 // init file choosers 160 // init file choosers
158 m_jarFileChooser = new JFileChooser(); 161 m_jarFileChooser = new JFileChooser();
159 m_mappingsFileChooser = new JFileChooser(); 162 m_mappingsFileChooser = new JFileChooser();
160 m_exportFileChooser = new JFileChooser(); 163 m_exportSourceFileChooser = new JFileChooser();
161 m_exportFileChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); 164 m_exportSourceFileChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY );
165 m_exportJarFileChooser = new JFileChooser();
162 166
163 // init obfuscated classes list 167 // init obfuscated classes list
164 m_obfClasses = new ClassSelector( ClassSelector.ObfuscatedClassEntryComparator ); 168 m_obfClasses = new ClassSelector( ClassSelector.ObfuscatedClassEntryComparator );
@@ -663,19 +667,36 @@ public class Gui
663 } 667 }
664 menu.addSeparator(); 668 menu.addSeparator();
665 { 669 {
666 JMenuItem item = new JMenuItem( "Export..." ); 670 JMenuItem item = new JMenuItem( "Export Source..." );
667 menu.add( item ); 671 menu.add( item );
668 item.addActionListener( new ActionListener( ) 672 item.addActionListener( new ActionListener( )
669 { 673 {
670 @Override 674 @Override
671 public void actionPerformed( ActionEvent event ) 675 public void actionPerformed( ActionEvent event )
672 { 676 {
673 if( m_exportFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) 677 if( m_exportSourceFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION )
674 { 678 {
675 m_controller.export( m_exportFileChooser.getSelectedFile() ); 679 m_controller.exportSource( m_exportSourceFileChooser.getSelectedFile() );
676 } 680 }
677 } 681 }
678 } ); 682 } );
683 m_exportSourceMenu = item;
684 }
685 {
686 JMenuItem item = new JMenuItem( "Export Jar..." );
687 menu.add( item );
688 item.addActionListener( new ActionListener( )
689 {
690 @Override
691 public void actionPerformed( ActionEvent event )
692 {
693 if( m_exportJarFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION )
694 {
695 m_controller.exportJar( m_exportJarFileChooser.getSelectedFile() );
696 }
697 }
698 } );
699 m_exportJarMenu = item;
679 } 700 }
680 menu.addSeparator(); 701 menu.addSeparator();
681 { 702 {
@@ -762,6 +783,8 @@ public class Gui
762 m_saveMappingsMenu.setEnabled( false ); 783 m_saveMappingsMenu.setEnabled( false );
763 m_saveMappingsAsMenu.setEnabled( true ); 784 m_saveMappingsAsMenu.setEnabled( true );
764 m_closeMappingsMenu.setEnabled( true ); 785 m_closeMappingsMenu.setEnabled( true );
786 m_exportSourceMenu.setEnabled( true );
787 m_exportJarMenu.setEnabled( true );
765 788
766 redraw(); 789 redraw();
767 } 790 }
@@ -781,6 +804,8 @@ public class Gui
781 m_saveMappingsMenu.setEnabled( false ); 804 m_saveMappingsMenu.setEnabled( false );
782 m_saveMappingsAsMenu.setEnabled( false ); 805 m_saveMappingsAsMenu.setEnabled( false );
783 m_closeMappingsMenu.setEnabled( false ); 806 m_closeMappingsMenu.setEnabled( false );
807 m_exportSourceMenu.setEnabled( false );
808 m_exportJarMenu.setEnabled( false );
784 809
785 redraw(); 810 redraw();
786 } 811 }
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java
index c7efbce6..2862ebed 100644
--- a/src/cuchaz/enigma/gui/GuiController.java
+++ b/src/cuchaz/enigma/gui/GuiController.java
@@ -23,6 +23,7 @@ import com.google.common.collect.Queues;
23import com.strobel.decompiler.languages.java.ast.CompilationUnit; 23import com.strobel.decompiler.languages.java.ast.CompilationUnit;
24 24
25import cuchaz.enigma.Deobfuscator; 25import cuchaz.enigma.Deobfuscator;
26import cuchaz.enigma.Deobfuscator.ProgressListener;
26import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; 27import cuchaz.enigma.analysis.BehaviorReferenceTreeNode;
27import cuchaz.enigma.analysis.ClassImplementationsTreeNode; 28import cuchaz.enigma.analysis.ClassImplementationsTreeNode;
28import cuchaz.enigma.analysis.ClassInheritanceTreeNode; 29import cuchaz.enigma.analysis.ClassInheritanceTreeNode;
@@ -32,6 +33,7 @@ import cuchaz.enigma.analysis.MethodImplementationsTreeNode;
32import cuchaz.enigma.analysis.MethodInheritanceTreeNode; 33import cuchaz.enigma.analysis.MethodInheritanceTreeNode;
33import cuchaz.enigma.analysis.SourceIndex; 34import cuchaz.enigma.analysis.SourceIndex;
34import cuchaz.enigma.analysis.Token; 35import cuchaz.enigma.analysis.Token;
36import cuchaz.enigma.gui.ProgressDialog.ProgressRunnable;
35import cuchaz.enigma.mapping.BehaviorEntry; 37import cuchaz.enigma.mapping.BehaviorEntry;
36import cuchaz.enigma.mapping.ClassEntry; 38import cuchaz.enigma.mapping.ClassEntry;
37import cuchaz.enigma.mapping.Entry; 39import cuchaz.enigma.mapping.Entry;
@@ -110,28 +112,29 @@ public class GuiController
110 refreshCurrentClass(); 112 refreshCurrentClass();
111 } 113 }
112 114
113 public void export( final File dirOut ) 115 public void exportSource( final File dirOut )
114 { 116 {
115 new Thread( ) 117 ProgressDialog.runInThread( m_gui.getFrame(), new ProgressRunnable( )
116 { 118 {
117 @Override 119 @Override
118 public void run( ) 120 public void run( ProgressListener progress )
121 throws Exception
119 { 122 {
120 ProgressDialog progress = new ProgressDialog( m_gui.getFrame() ); 123 m_deobfuscator.writeSources( dirOut, progress );
121 try
122 {
123 m_deobfuscator.writeSources( dirOut, progress );
124 }
125 catch( Exception ex )
126 {
127 throw new Error( ex );
128 }
129 finally
130 {
131 progress.close();
132 }
133 } 124 }
134 }.start(); 125 } );
126 }
127
128 public void exportJar( final File fileOut )
129 {
130 ProgressDialog.runInThread( m_gui.getFrame(), new ProgressRunnable( )
131 {
132 @Override
133 public void run( ProgressListener progress )
134 {
135 m_deobfuscator.writeJar( fileOut, progress );
136 }
137 } );
135 } 138 }
136 139
137 public Token getToken( int pos ) 140 public Token getToken( int pos )
diff --git a/src/cuchaz/enigma/gui/ProgressDialog.java b/src/cuchaz/enigma/gui/ProgressDialog.java
index 40ac6a69..7f954314 100644
--- a/src/cuchaz/enigma/gui/ProgressDialog.java
+++ b/src/cuchaz/enigma/gui/ProgressDialog.java
@@ -25,22 +25,24 @@ import javax.swing.WindowConstants;
25import cuchaz.enigma.Constants; 25import cuchaz.enigma.Constants;
26import cuchaz.enigma.Deobfuscator.ProgressListener; 26import cuchaz.enigma.Deobfuscator.ProgressListener;
27 27
28public class ProgressDialog implements ProgressListener 28public class ProgressDialog implements ProgressListener, AutoCloseable
29{ 29{
30 private JFrame m_frame; 30 private JFrame m_frame;
31 private JLabel m_title;
31 private JLabel m_text; 32 private JLabel m_text;
32 private JProgressBar m_progress; 33 private JProgressBar m_progress;
33 34
34 public ProgressDialog( JFrame parent ) 35 public ProgressDialog( JFrame parent )
35 { 36 {
36 // init frame 37 // init frame
37 m_frame = new JFrame( Constants.Name + " - Export" ); 38 m_frame = new JFrame( Constants.Name + " - Operation in progress" );
38 final Container pane = m_frame.getContentPane(); 39 final Container pane = m_frame.getContentPane();
39 FlowLayout layout = new FlowLayout(); 40 FlowLayout layout = new FlowLayout();
40 layout.setAlignment( FlowLayout.LEFT ); 41 layout.setAlignment( FlowLayout.LEFT );
41 pane.setLayout( layout ); 42 pane.setLayout( layout );
42 43
43 pane.add( new JLabel( "Decompiling classes..." ) ); 44 m_title = new JLabel();
45 pane.add( m_title );
44 46
45 // set up the progress bar 47 // set up the progress bar
46 JPanel panel = new JPanel(); 48 JPanel panel = new JPanel();
@@ -68,9 +70,9 @@ public class ProgressDialog implements ProgressListener
68 } 70 }
69 71
70 @Override 72 @Override
71 public void init( int totalWork ) 73 public void init( int totalWork, String title )
72 { 74 {
73 m_text.setText( "Decompiling " + totalWork + " classes..." ); 75 m_title.setText( title );
74 m_progress.setMinimum( 0 ); 76 m_progress.setMinimum( 0 );
75 m_progress.setMaximum( totalWork ); 77 m_progress.setMaximum( totalWork );
76 m_progress.setValue( 0 ); 78 m_progress.setValue( 0 );
@@ -86,4 +88,28 @@ public class ProgressDialog implements ProgressListener
86 m_frame.validate(); 88 m_frame.validate();
87 m_frame.repaint(); 89 m_frame.repaint();
88 } 90 }
91
92 public static interface ProgressRunnable
93 {
94 void run( ProgressListener listener ) throws Exception;
95 }
96
97 public static void runInThread( final JFrame parent, final ProgressRunnable runnable )
98 {
99 new Thread( )
100 {
101 @Override
102 public void run( )
103 {
104 try( ProgressDialog progress = new ProgressDialog( parent ) )
105 {
106 runnable.run( progress );
107 }
108 catch( Exception ex )
109 {
110 throw new Error( ex );
111 }
112 }
113 }.start();
114 }
89} 115}