diff options
| author | 2014-08-12 00:24:11 -0400 | |
|---|---|---|
| committer | 2014-08-12 00:24:11 -0400 | |
| commit | 52bb7ba51ceaf65f40e5e3e2de9d1ac3f7fc9c2e (patch) | |
| tree | 52a89485240cb15318adb29a340ed5dc9056bc8c | |
| parent | fix keyboard shortcuts (diff) | |
| download | enigma-fork-52bb7ba51ceaf65f40e5e3e2de9d1ac3f7fc9c2e.tar.gz enigma-fork-52bb7ba51ceaf65f40e5e3e2de9d1ac3f7fc9c2e.tar.xz enigma-fork-52bb7ba51ceaf65f40e5e3e2de9d1ac3f7fc9c2e.zip | |
got simple method call graph working!
| -rw-r--r-- | src/cuchaz/enigma/Deobfuscator.java | 34 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/JarIndex.java | 101 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/MethodCallsTreeNode.java | 96 | ||||
| -rw-r--r-- | src/cuchaz/enigma/gui/Gui.java | 93 | ||||
| -rw-r--r-- | src/cuchaz/enigma/gui/GuiController.java | 11 |
5 files changed, 284 insertions, 51 deletions
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index c35a483..33eef08 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java | |||
| @@ -15,12 +15,9 @@ import java.io.FileInputStream; | |||
| 15 | import java.io.IOException; | 15 | import java.io.IOException; |
| 16 | import java.io.InputStream; | 16 | import java.io.InputStream; |
| 17 | import java.io.StringWriter; | 17 | import java.io.StringWriter; |
| 18 | import java.util.Enumeration; | ||
| 19 | import java.util.List; | 18 | import java.util.List; |
| 20 | import java.util.jar.JarEntry; | ||
| 21 | import java.util.jar.JarFile; | 19 | import java.util.jar.JarFile; |
| 22 | 20 | ||
| 23 | import com.google.common.collect.Lists; | ||
| 24 | import com.strobel.assembler.metadata.MetadataSystem; | 21 | import com.strobel.assembler.metadata.MetadataSystem; |
| 25 | import com.strobel.assembler.metadata.TypeDefinition; | 22 | import com.strobel.assembler.metadata.TypeDefinition; |
| 26 | import com.strobel.decompiler.DecompilerContext; | 23 | import com.strobel.decompiler.DecompilerContext; |
| @@ -53,7 +50,6 @@ public class Deobfuscator | |||
| 53 | private JarIndex m_jarIndex; | 50 | private JarIndex m_jarIndex; |
| 54 | private Mappings m_mappings; | 51 | private Mappings m_mappings; |
| 55 | private Renamer m_renamer; | 52 | private Renamer m_renamer; |
| 56 | private List<String> m_obfClassNames; | ||
| 57 | 53 | ||
| 58 | public Deobfuscator( File file ) | 54 | public Deobfuscator( File file ) |
| 59 | throws IOException | 55 | throws IOException |
| @@ -65,7 +61,7 @@ public class Deobfuscator | |||
| 65 | InputStream jarIn = null; | 61 | InputStream jarIn = null; |
| 66 | try | 62 | try |
| 67 | { | 63 | { |
| 68 | m_jarIndex = new JarIndex(); | 64 | m_jarIndex = new JarIndex( m_jar ); |
| 69 | jarIn = new FileInputStream( m_file ); | 65 | jarIn = new FileInputStream( m_file ); |
| 70 | m_jarIndex.indexJar( jarIn ); | 66 | m_jarIndex.indexJar( jarIn ); |
| 71 | } | 67 | } |
| @@ -74,26 +70,6 @@ public class Deobfuscator | |||
| 74 | Util.closeQuietly( jarIn ); | 70 | Util.closeQuietly( jarIn ); |
| 75 | } | 71 | } |
| 76 | 72 | ||
| 77 | // get the obf class names | ||
| 78 | m_obfClassNames = Lists.newArrayList(); | ||
| 79 | { | ||
| 80 | Enumeration<JarEntry> entries = m_jar.entries(); | ||
| 81 | while( entries.hasMoreElements() ) | ||
| 82 | { | ||
| 83 | JarEntry entry = entries.nextElement(); | ||
| 84 | |||
| 85 | // skip everything but class files | ||
| 86 | if( !entry.getName().endsWith( ".class" ) ) | ||
| 87 | { | ||
| 88 | continue; | ||
| 89 | } | ||
| 90 | |||
| 91 | // get the class name from the file | ||
| 92 | String className = entry.getName().substring( 0, entry.getName().length() - 6 ); | ||
| 93 | m_obfClassNames.add( className ); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | // config the decompiler | 73 | // config the decompiler |
| 98 | m_settings = DecompilerSettings.javaDefaults(); | 74 | m_settings = DecompilerSettings.javaDefaults(); |
| 99 | m_settings.setShowSyntheticMembers( true ); | 75 | m_settings.setShowSyntheticMembers( true ); |
| @@ -140,7 +116,7 @@ public class Deobfuscator | |||
| 140 | 116 | ||
| 141 | public void getSeparatedClasses( List<String> obfClasses, List<String> deobfClasses ) | 117 | public void getSeparatedClasses( List<String> obfClasses, List<String> deobfClasses ) |
| 142 | { | 118 | { |
| 143 | for( String obfClassName : m_obfClassNames ) | 119 | for( String obfClassName : m_jarIndex.getObfClassNames() ) |
| 144 | { | 120 | { |
| 145 | // separate the classes | 121 | // separate the classes |
| 146 | ClassMapping classMapping = m_mappings.getClassByObf( obfClassName ); | 122 | ClassMapping classMapping = m_mappings.getClassByObf( obfClassName ); |
| @@ -302,15 +278,15 @@ public class Deobfuscator | |||
| 302 | if( obfEntry instanceof ClassEntry ) | 278 | if( obfEntry instanceof ClassEntry ) |
| 303 | { | 279 | { |
| 304 | // obf classes must be in the list | 280 | // obf classes must be in the list |
| 305 | return m_obfClassNames.contains( obfEntry.getName() ); | 281 | return m_jarIndex.getObfClassNames().contains( obfEntry.getName() ); |
| 306 | } | 282 | } |
| 307 | else if( obfEntry instanceof FieldEntry ) | 283 | else if( obfEntry instanceof FieldEntry ) |
| 308 | { | 284 | { |
| 309 | return m_obfClassNames.contains( ((FieldEntry)obfEntry).getClassName() ); | 285 | return m_jarIndex.getObfClassNames().contains( ((FieldEntry)obfEntry).getClassName() ); |
| 310 | } | 286 | } |
| 311 | else if( obfEntry instanceof MethodEntry ) | 287 | else if( obfEntry instanceof MethodEntry ) |
| 312 | { | 288 | { |
| 313 | return m_obfClassNames.contains( ((MethodEntry)obfEntry).getClassName() ); | 289 | return m_jarIndex.getObfClassNames().contains( ((MethodEntry)obfEntry).getClassName() ); |
| 314 | } | 290 | } |
| 315 | else if( obfEntry instanceof ArgumentEntry ) | 291 | else if( obfEntry instanceof ArgumentEntry ) |
| 316 | { | 292 | { |
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 8a8384c..06b0173 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java | |||
| @@ -14,19 +14,28 @@ import java.io.ByteArrayOutputStream; | |||
| 14 | import java.io.IOException; | 14 | import java.io.IOException; |
| 15 | import java.io.InputStream; | 15 | import java.io.InputStream; |
| 16 | import java.util.Collection; | 16 | import java.util.Collection; |
| 17 | import java.util.Enumeration; | ||
| 17 | import java.util.List; | 18 | import java.util.List; |
| 19 | import java.util.Set; | ||
| 20 | import java.util.jar.JarEntry; | ||
| 21 | import java.util.jar.JarFile; | ||
| 18 | import java.util.zip.ZipEntry; | 22 | import java.util.zip.ZipEntry; |
| 19 | import java.util.zip.ZipInputStream; | 23 | import java.util.zip.ZipInputStream; |
| 20 | 24 | ||
| 21 | import com.google.common.collect.HashMultimap; | ||
| 22 | import com.google.common.collect.Multimap; | ||
| 23 | |||
| 24 | import javassist.ByteArrayClassPath; | 25 | import javassist.ByteArrayClassPath; |
| 26 | import javassist.CannotCompileException; | ||
| 25 | import javassist.ClassPool; | 27 | import javassist.ClassPool; |
| 28 | import javassist.CtBehavior; | ||
| 26 | import javassist.CtClass; | 29 | import javassist.CtClass; |
| 27 | import javassist.NotFoundException; | 30 | import javassist.NotFoundException; |
| 28 | import javassist.bytecode.Descriptor; | 31 | import javassist.bytecode.Descriptor; |
| 29 | import javassist.bytecode.MethodInfo; | 32 | import javassist.expr.ExprEditor; |
| 33 | import javassist.expr.MethodCall; | ||
| 34 | |||
| 35 | import com.google.common.collect.HashMultimap; | ||
| 36 | import com.google.common.collect.Multimap; | ||
| 37 | import com.google.common.collect.Sets; | ||
| 38 | |||
| 30 | import cuchaz.enigma.Constants; | 39 | import cuchaz.enigma.Constants; |
| 31 | import cuchaz.enigma.mapping.ClassEntry; | 40 | import cuchaz.enigma.mapping.ClassEntry; |
| 32 | import cuchaz.enigma.mapping.MethodEntry; | 41 | import cuchaz.enigma.mapping.MethodEntry; |
| @@ -34,16 +43,35 @@ import cuchaz.enigma.mapping.Translator; | |||
| 34 | 43 | ||
| 35 | public class JarIndex | 44 | public class JarIndex |
| 36 | { | 45 | { |
| 46 | private Set<String> m_obfClassNames; | ||
| 37 | private Ancestries m_ancestries; | 47 | private Ancestries m_ancestries; |
| 38 | private Multimap<String,String> m_methodImplementations; | 48 | private Multimap<String,MethodEntry> m_methodImplementations; |
| 49 | private Multimap<MethodEntry,MethodEntry> m_methodCalls; | ||
| 39 | 50 | ||
| 40 | public JarIndex( ) | 51 | public JarIndex( JarFile jar ) |
| 41 | { | 52 | { |
| 53 | m_obfClassNames = Sets.newHashSet(); | ||
| 42 | m_ancestries = new Ancestries(); | 54 | m_ancestries = new Ancestries(); |
| 43 | m_methodImplementations = HashMultimap.create(); | 55 | m_methodImplementations = HashMultimap.create(); |
| 56 | m_methodCalls = HashMultimap.create(); | ||
| 57 | |||
| 58 | // read the class names | ||
| 59 | Enumeration<JarEntry> enumeration = jar.entries(); | ||
| 60 | while( enumeration.hasMoreElements() ) | ||
| 61 | { | ||
| 62 | JarEntry entry = enumeration.nextElement(); | ||
| 63 | |||
| 64 | // filter out non-classes | ||
| 65 | if( entry.isDirectory() || !entry.getName().endsWith( ".class" ) ) | ||
| 66 | { | ||
| 67 | continue; | ||
| 68 | } | ||
| 69 | |||
| 70 | String className = entry.getName().substring( 0, entry.getName().length() - 6 ); | ||
| 71 | m_obfClassNames.add( Descriptor.toJvmName( className ) ); | ||
| 72 | } | ||
| 44 | } | 73 | } |
| 45 | 74 | ||
| 46 | @SuppressWarnings( "unchecked" ) | ||
| 47 | public void indexJar( InputStream in ) | 75 | public void indexJar( InputStream in ) |
| 48 | throws IOException | 76 | throws IOException |
| 49 | { | 77 | { |
| @@ -89,7 +117,10 @@ public class JarIndex | |||
| 89 | { | 117 | { |
| 90 | CtClass c = classPool.get( className ); | 118 | CtClass c = classPool.get( className ); |
| 91 | m_ancestries.addSuperclass( c.getName(), c.getClassFile().getSuperclass() ); | 119 | m_ancestries.addSuperclass( c.getName(), c.getClassFile().getSuperclass() ); |
| 92 | addMethodImplementations( c.getName(), (List<MethodInfo>)c.getClassFile().getMethods() ); | 120 | for( CtBehavior behavior : c.getDeclaredBehaviors() ) |
| 121 | { | ||
| 122 | indexBehavior( behavior ); | ||
| 123 | } | ||
| 93 | } | 124 | } |
| 94 | catch( NotFoundException ex ) | 125 | catch( NotFoundException ex ) |
| 95 | { | 126 | { |
| @@ -98,14 +129,55 @@ public class JarIndex | |||
| 98 | } | 129 | } |
| 99 | } | 130 | } |
| 100 | 131 | ||
| 101 | private void addMethodImplementations( String name, List<MethodInfo> methods ) | 132 | private void indexBehavior( CtBehavior behavior ) |
| 102 | { | 133 | { |
| 103 | for( MethodInfo method : methods ) | 134 | // get the method entry |
| 135 | String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); | ||
| 136 | final MethodEntry methodEntry = new MethodEntry( | ||
| 137 | new ClassEntry( className ), | ||
| 138 | behavior.getName(), | ||
| 139 | behavior.getSignature() | ||
| 140 | ); | ||
| 141 | |||
| 142 | // index implementation | ||
| 143 | m_methodImplementations.put( className, methodEntry ); | ||
| 144 | |||
| 145 | // index method calls | ||
| 146 | try | ||
| 147 | { | ||
| 148 | behavior.instrument( new ExprEditor( ) | ||
| 149 | { | ||
| 150 | @Override | ||
| 151 | public void edit( MethodCall call ) | ||
| 152 | { | ||
| 153 | // is this a jar class? | ||
| 154 | String className = Descriptor.toJvmName( call.getClassName() ); | ||
| 155 | if( !m_obfClassNames.contains( className ) ) | ||
| 156 | { | ||
| 157 | return; | ||
| 158 | } | ||
| 159 | |||
| 160 | // make entry for the called method | ||
| 161 | MethodEntry calledMethodEntry = new MethodEntry( | ||
| 162 | new ClassEntry( className ), | ||
| 163 | call.getMethodName(), | ||
| 164 | call.getSignature() | ||
| 165 | ); | ||
| 166 | m_methodCalls.put( calledMethodEntry, methodEntry ); | ||
| 167 | } | ||
| 168 | } ); | ||
| 169 | } | ||
| 170 | catch( CannotCompileException ex ) | ||
| 104 | { | 171 | { |
| 105 | m_methodImplementations.put( name, getMethodKey( method.getName(), method.getDescriptor() ) ); | 172 | throw new Error( ex ); |
| 106 | } | 173 | } |
| 107 | } | 174 | } |
| 108 | 175 | ||
| 176 | public Set<String> getObfClassNames( ) | ||
| 177 | { | ||
| 178 | return m_obfClassNames; | ||
| 179 | } | ||
| 180 | |||
| 109 | public Ancestries getAncestries( ) | 181 | public Ancestries getAncestries( ) |
| 110 | { | 182 | { |
| 111 | return m_ancestries; | 183 | return m_ancestries; |
| @@ -118,7 +190,7 @@ public class JarIndex | |||
| 118 | 190 | ||
| 119 | public boolean isMethodImplemented( String className, String methodName, String methodSignature ) | 191 | public boolean isMethodImplemented( String className, String methodName, String methodSignature ) |
| 120 | { | 192 | { |
| 121 | Collection<String> implementations = m_methodImplementations.get( className ); | 193 | Collection<MethodEntry> implementations = m_methodImplementations.get( className ); |
| 122 | if( implementations == null ) | 194 | if( implementations == null ) |
| 123 | { | 195 | { |
| 124 | return false; | 196 | return false; |
| @@ -169,6 +241,11 @@ public class JarIndex | |||
| 169 | return rootNode; | 241 | return rootNode; |
| 170 | } | 242 | } |
| 171 | 243 | ||
| 244 | public Collection<MethodEntry> getMethodCallers( MethodEntry methodEntry ) | ||
| 245 | { | ||
| 246 | return m_methodCalls.get( methodEntry ); | ||
| 247 | } | ||
| 248 | |||
| 172 | private String getMethodKey( String name, String signature ) | 249 | private String getMethodKey( String name, String signature ) |
| 173 | { | 250 | { |
| 174 | return name + signature; | 251 | return name + signature; |
diff --git a/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java b/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java new file mode 100644 index 0000000..dedfb2e --- /dev/null +++ b/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java | |||
| @@ -0,0 +1,96 @@ | |||
| 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 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.analysis; | ||
| 12 | |||
| 13 | import java.util.List; | ||
| 14 | |||
| 15 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 16 | |||
| 17 | import com.google.common.collect.Lists; | ||
| 18 | |||
| 19 | import cuchaz.enigma.mapping.MethodEntry; | ||
| 20 | import cuchaz.enigma.mapping.Translator; | ||
| 21 | |||
| 22 | public class MethodCallsTreeNode extends DefaultMutableTreeNode | ||
| 23 | { | ||
| 24 | private static final long serialVersionUID = -3658163700783307520L; | ||
| 25 | |||
| 26 | private Translator m_deobfuscatingTranslator; | ||
| 27 | private MethodEntry m_entry; | ||
| 28 | |||
| 29 | public MethodCallsTreeNode( Translator deobfuscatingTranslator, MethodEntry entry ) | ||
| 30 | { | ||
| 31 | m_deobfuscatingTranslator = deobfuscatingTranslator; | ||
| 32 | m_entry = entry; | ||
| 33 | } | ||
| 34 | |||
| 35 | public MethodEntry getMethodEntry( ) | ||
| 36 | { | ||
| 37 | return m_entry; | ||
| 38 | } | ||
| 39 | |||
| 40 | public String getDeobfClassName( ) | ||
| 41 | { | ||
| 42 | return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() ); | ||
| 43 | } | ||
| 44 | |||
| 45 | public String getDeobfMethodName( ) | ||
| 46 | { | ||
| 47 | return m_deobfuscatingTranslator.translate( m_entry ); | ||
| 48 | } | ||
| 49 | |||
| 50 | @Override | ||
| 51 | public String toString( ) | ||
| 52 | { | ||
| 53 | String className = getDeobfClassName(); | ||
| 54 | if( className == null ) | ||
| 55 | { | ||
| 56 | className = m_entry.getClassName(); | ||
| 57 | } | ||
| 58 | |||
| 59 | String methodName = getDeobfMethodName(); | ||
| 60 | if( methodName == null ) | ||
| 61 | { | ||
| 62 | methodName = m_entry.getName(); | ||
| 63 | } | ||
| 64 | return className + "." + methodName + "()"; | ||
| 65 | } | ||
| 66 | |||
| 67 | public void load( JarIndex index, boolean recurse ) | ||
| 68 | { | ||
| 69 | // get all the child nodes | ||
| 70 | List<MethodCallsTreeNode> nodes = Lists.newArrayList(); | ||
| 71 | for( MethodEntry entry : index.getMethodCallers( m_entry ) ) | ||
| 72 | { | ||
| 73 | nodes.add( new MethodCallsTreeNode( m_deobfuscatingTranslator, entry ) ); | ||
| 74 | } | ||
| 75 | |||
| 76 | // add them to this node | ||
| 77 | for( MethodCallsTreeNode node : nodes ) | ||
| 78 | { | ||
| 79 | this.add( node ); | ||
| 80 | } | ||
| 81 | |||
| 82 | if( recurse ) | ||
| 83 | { | ||
| 84 | for( MethodCallsTreeNode node : nodes ) | ||
| 85 | { | ||
| 86 | // don't recurse into self | ||
| 87 | if( node.getMethodEntry().equals( m_entry ) ) | ||
| 88 | { | ||
| 89 | continue; | ||
| 90 | } | ||
| 91 | |||
| 92 | node.load( index, true ); | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 3e8a18c..072fb3a 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java | |||
| @@ -67,6 +67,7 @@ import com.google.common.collect.Lists; | |||
| 67 | 67 | ||
| 68 | import cuchaz.enigma.Constants; | 68 | import cuchaz.enigma.Constants; |
| 69 | import cuchaz.enigma.analysis.ClassInheritanceTreeNode; | 69 | import cuchaz.enigma.analysis.ClassInheritanceTreeNode; |
| 70 | import cuchaz.enigma.analysis.MethodCallsTreeNode; | ||
| 70 | import cuchaz.enigma.analysis.MethodInheritanceTreeNode; | 71 | import cuchaz.enigma.analysis.MethodInheritanceTreeNode; |
| 71 | import cuchaz.enigma.analysis.Token; | 72 | import cuchaz.enigma.analysis.Token; |
| 72 | import cuchaz.enigma.mapping.ArgumentEntry; | 73 | import cuchaz.enigma.mapping.ArgumentEntry; |
| @@ -139,6 +140,8 @@ public class Gui | |||
| 139 | private BoxHighlightPainter m_obfuscatedHighlightPainter; | 140 | private BoxHighlightPainter m_obfuscatedHighlightPainter; |
| 140 | private BoxHighlightPainter m_deobfuscatedHighlightPainter; | 141 | private BoxHighlightPainter m_deobfuscatedHighlightPainter; |
| 141 | private JTree m_inheritanceTree; | 142 | private JTree m_inheritanceTree; |
| 143 | private JTree m_callsTree; | ||
| 144 | private JTabbedPane m_tabs; | ||
| 142 | 145 | ||
| 143 | // dynamic menu items | 146 | // dynamic menu items |
| 144 | private JMenuItem m_closeJarMenu; | 147 | private JMenuItem m_closeJarMenu; |
| @@ -147,9 +150,10 @@ public class Gui | |||
| 147 | private JMenuItem m_saveMappingsAsMenu; | 150 | private JMenuItem m_saveMappingsAsMenu; |
| 148 | private JMenuItem m_closeMappingsMenu; | 151 | private JMenuItem m_closeMappingsMenu; |
| 149 | private JMenuItem m_renameMenu; | 152 | private JMenuItem m_renameMenu; |
| 150 | private JMenuItem m_inheritanceMenu; | 153 | private JMenuItem m_showInheritanceMenu; |
| 151 | private JMenuItem m_openEntryMenu; | 154 | private JMenuItem m_openEntryMenu; |
| 152 | private JMenuItem m_openPreviousMenu; | 155 | private JMenuItem m_openPreviousMenu; |
| 156 | private JMenuItem m_showCallsMenu; | ||
| 153 | 157 | ||
| 154 | // state | 158 | // state |
| 155 | private EntryPair<Entry> m_selectedEntryPair; | 159 | private EntryPair<Entry> m_selectedEntryPair; |
| @@ -267,6 +271,10 @@ public class Gui | |||
| 267 | case KeyEvent.VK_P: | 271 | case KeyEvent.VK_P: |
| 268 | m_controller.openPreviousEntry(); | 272 | m_controller.openPreviousEntry(); |
| 269 | break; | 273 | break; |
| 274 | |||
| 275 | case KeyEvent.VK_C: | ||
| 276 | showCalls(); | ||
| 277 | break; | ||
| 270 | } | 278 | } |
| 271 | } | 279 | } |
| 272 | } ); | 280 | } ); |
| @@ -306,7 +314,22 @@ public class Gui | |||
| 306 | menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_I, 0 ) ); | 314 | menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_I, 0 ) ); |
| 307 | menu.setEnabled( false ); | 315 | menu.setEnabled( false ); |
| 308 | popupMenu.add( menu ); | 316 | popupMenu.add( menu ); |
| 309 | m_inheritanceMenu = menu; | 317 | m_showInheritanceMenu = menu; |
| 318 | } | ||
| 319 | { | ||
| 320 | JMenuItem menu = new JMenuItem( "Show Calls" ); | ||
| 321 | menu.addActionListener( new ActionListener( ) | ||
| 322 | { | ||
| 323 | @Override | ||
| 324 | public void actionPerformed( ActionEvent event ) | ||
| 325 | { | ||
| 326 | showCalls(); | ||
| 327 | } | ||
| 328 | } ); | ||
| 329 | menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_C, 0 ) ); | ||
| 330 | menu.setEnabled( false ); | ||
| 331 | popupMenu.add( menu ); | ||
| 332 | m_showCallsMenu = menu; | ||
| 310 | } | 333 | } |
| 311 | { | 334 | { |
| 312 | JMenuItem menu = new JMenuItem( "Go to Declaration" ); | 335 | JMenuItem menu = new JMenuItem( "Go to Declaration" ); |
| @@ -350,12 +373,13 @@ public class Gui | |||
| 350 | if( event.getClickCount() == 2 ) | 373 | if( event.getClickCount() == 2 ) |
| 351 | { | 374 | { |
| 352 | // get the selected node | 375 | // get the selected node |
| 353 | Object node = m_inheritanceTree.getSelectionPath().getLastPathComponent(); | 376 | TreePath path = m_inheritanceTree.getSelectionPath(); |
| 354 | if( node == null ) | 377 | if( path == null ) |
| 355 | { | 378 | { |
| 356 | return; | 379 | return; |
| 357 | } | 380 | } |
| 358 | 381 | ||
| 382 | Object node = path.getLastPathComponent(); | ||
| 359 | if( node instanceof ClassInheritanceTreeNode ) | 383 | if( node instanceof ClassInheritanceTreeNode ) |
| 360 | { | 384 | { |
| 361 | m_controller.openEntry( new ClassEntry( ((ClassInheritanceTreeNode)node).getObfClassName() ) ); | 385 | m_controller.openEntry( new ClassEntry( ((ClassInheritanceTreeNode)node).getObfClassName() ) ); |
| @@ -375,17 +399,47 @@ public class Gui | |||
| 375 | inheritancePanel.setLayout( new BorderLayout() ); | 399 | inheritancePanel.setLayout( new BorderLayout() ); |
| 376 | inheritancePanel.add( new JScrollPane( m_inheritanceTree ) ); | 400 | inheritancePanel.add( new JScrollPane( m_inheritanceTree ) ); |
| 377 | 401 | ||
| 402 | // init call panel | ||
| 403 | m_callsTree = new JTree(); | ||
| 404 | m_callsTree.setModel( null ); | ||
| 405 | m_callsTree.addMouseListener( new MouseAdapter( ) | ||
| 406 | { | ||
| 407 | @Override | ||
| 408 | public void mouseClicked( MouseEvent event ) | ||
| 409 | { | ||
| 410 | if( event.getClickCount() == 2 ) | ||
| 411 | { | ||
| 412 | // get the selected node | ||
| 413 | TreePath path = m_callsTree.getSelectionPath(); | ||
| 414 | if( path == null ) | ||
| 415 | { | ||
| 416 | return; | ||
| 417 | } | ||
| 418 | |||
| 419 | Object node = path.getLastPathComponent(); | ||
| 420 | if( node instanceof MethodCallsTreeNode ) | ||
| 421 | { | ||
| 422 | m_controller.openEntry( ((MethodCallsTreeNode)node).getMethodEntry() ); | ||
| 423 | } | ||
| 424 | } | ||
| 425 | } | ||
| 426 | } ); | ||
| 427 | JPanel callPanel = new JPanel(); | ||
| 428 | callPanel.setLayout( new BorderLayout() ); | ||
| 429 | callPanel.add( new JScrollPane( m_callsTree ) ); | ||
| 430 | |||
| 378 | // layout controls | 431 | // layout controls |
| 379 | JSplitPane splitLeft = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); | 432 | JSplitPane splitLeft = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); |
| 380 | splitLeft.setPreferredSize( new Dimension( 200, 0 ) ); | 433 | splitLeft.setPreferredSize( new Dimension( 250, 0 ) ); |
| 381 | JPanel centerPanel = new JPanel(); | 434 | JPanel centerPanel = new JPanel(); |
| 382 | centerPanel.setLayout( new BorderLayout() ); | 435 | centerPanel.setLayout( new BorderLayout() ); |
| 383 | centerPanel.add( m_infoPanel, BorderLayout.NORTH ); | 436 | centerPanel.add( m_infoPanel, BorderLayout.NORTH ); |
| 384 | centerPanel.add( sourceScroller, BorderLayout.CENTER ); | 437 | centerPanel.add( sourceScroller, BorderLayout.CENTER ); |
| 385 | JTabbedPane tabbedPane = new JTabbedPane(); | 438 | m_tabs = new JTabbedPane(); |
| 386 | tabbedPane.setPreferredSize( new Dimension( 200, 0 ) ); | 439 | m_tabs.setPreferredSize( new Dimension( 250, 0 ) ); |
| 387 | tabbedPane.addTab( "Inheritance", inheritancePanel ); | 440 | m_tabs.addTab( "Inheritance", inheritancePanel ); |
| 388 | JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, tabbedPane ); | 441 | m_tabs.addTab( "Method Calls", callPanel ); |
| 442 | JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs ); | ||
| 389 | splitRight.setResizeWeight( 1 ); // let the left side take all the slack | 443 | splitRight.setResizeWeight( 1 ); // let the left side take all the slack |
| 390 | splitRight.resetToPreferredSizes(); | 444 | splitRight.resetToPreferredSizes(); |
| 391 | JSplitPane splitCenter = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, splitRight ); | 445 | JSplitPane splitCenter = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, splitRight ); |
| @@ -784,7 +838,8 @@ public class Gui | |||
| 784 | 838 | ||
| 785 | showEntryPair( m_selectedEntryPair ); | 839 | showEntryPair( m_selectedEntryPair ); |
| 786 | 840 | ||
| 787 | m_inheritanceMenu.setEnabled( isClassEntry || isMethodEntry ); | 841 | m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry ); |
| 842 | m_showCallsMenu.setEnabled( isMethodEntry ); | ||
| 788 | m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry ); | 843 | m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry ); |
| 789 | m_openPreviousMenu.setEnabled( m_controller.hasPreviousEntry() ); | 844 | m_openPreviousMenu.setEnabled( m_controller.hasPreviousEntry() ); |
| 790 | } | 845 | } |
| @@ -879,6 +934,24 @@ public class Gui | |||
| 879 | m_inheritanceTree.setSelectionRow( m_inheritanceTree.getRowForPath( path ) ); | 934 | m_inheritanceTree.setSelectionRow( m_inheritanceTree.getRowForPath( path ) ); |
| 880 | } | 935 | } |
| 881 | 936 | ||
| 937 | m_tabs.setSelectedIndex( 0 ); | ||
| 938 | redraw(); | ||
| 939 | } | ||
| 940 | |||
| 941 | private void showCalls( ) | ||
| 942 | { | ||
| 943 | if( m_selectedEntryPair == null ) | ||
| 944 | { | ||
| 945 | return; | ||
| 946 | } | ||
| 947 | |||
| 948 | if( m_selectedEntryPair.obf instanceof MethodEntry ) | ||
| 949 | { | ||
| 950 | MethodCallsTreeNode node = m_controller.getMethodCalls( (MethodEntry)m_selectedEntryPair.obf ); | ||
| 951 | m_callsTree.setModel( new DefaultTreeModel( node ) ); | ||
| 952 | } | ||
| 953 | |||
| 954 | m_tabs.setSelectedIndex( 1 ); | ||
| 882 | redraw(); | 955 | redraw(); |
| 883 | } | 956 | } |
| 884 | 957 | ||
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 880f001..b54aeba 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java | |||
| @@ -21,6 +21,7 @@ import com.google.common.collect.Lists; | |||
| 21 | 21 | ||
| 22 | import cuchaz.enigma.Deobfuscator; | 22 | import cuchaz.enigma.Deobfuscator; |
| 23 | import cuchaz.enigma.analysis.ClassInheritanceTreeNode; | 23 | import cuchaz.enigma.analysis.ClassInheritanceTreeNode; |
| 24 | import cuchaz.enigma.analysis.MethodCallsTreeNode; | ||
| 24 | import cuchaz.enigma.analysis.MethodInheritanceTreeNode; | 25 | import cuchaz.enigma.analysis.MethodInheritanceTreeNode; |
| 25 | import cuchaz.enigma.analysis.SourceIndex; | 26 | import cuchaz.enigma.analysis.SourceIndex; |
| 26 | import cuchaz.enigma.analysis.Token; | 27 | import cuchaz.enigma.analysis.Token; |
| @@ -148,6 +149,16 @@ public class GuiController | |||
| 148 | return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry ); | 149 | return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry ); |
| 149 | } | 150 | } |
| 150 | 151 | ||
| 152 | public MethodCallsTreeNode getMethodCalls( MethodEntry obfMethodEntry ) | ||
| 153 | { | ||
| 154 | MethodCallsTreeNode rootNode = new MethodCallsTreeNode( | ||
| 155 | m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), | ||
| 156 | obfMethodEntry | ||
| 157 | ); | ||
| 158 | rootNode.load( m_deobfuscator.getJarIndex(), true ); | ||
| 159 | return rootNode; | ||
| 160 | } | ||
| 161 | |||
| 151 | public void rename( Entry obfEntry, String newName ) | 162 | public void rename( Entry obfEntry, String newName ) |
| 152 | { | 163 | { |
| 153 | m_deobfuscator.rename( obfEntry, newName ); | 164 | m_deobfuscator.rename( obfEntry, newName ); |