From d71c0af8ed298bfb4b35b4e3e61b5678bc1c7d9f Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 6 Aug 2014 00:22:25 -0400 Subject: added simple class inheritance browsing --- src/cuchaz/enigma/Deobfuscator.java | 5 ++ src/cuchaz/enigma/TranslatingTypeLoader.java | 16 ++++-- .../enigma/gui/ClassInheritanceTreeNode.java | 56 ++++++++++++++++++++ src/cuchaz/enigma/gui/Gui.java | 61 ++++++++++++++++++---- src/cuchaz/enigma/gui/GuiController.java | 22 ++++++++ src/cuchaz/enigma/mapping/Ancestries.java | 22 +++++++- 6 files changed, 169 insertions(+), 13 deletions(-) create mode 100644 src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index a3937b4..65e618a 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -79,6 +79,11 @@ public class Deobfuscator return m_file.getName(); } + public Ancestries getAncestries( ) + { + return m_ancestries; + } + public Mappings getMappings( ) { return m_mappings; diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index e57a09d..44fe980 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -10,6 +10,7 @@ ******************************************************************************/ package cuchaz.enigma; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.jar.JarEntry; @@ -59,10 +60,19 @@ public class TranslatingTypeLoader implements ITypeLoader try { // read the class file into a buffer - byte[] buf = new byte[(int)entry.getSize()]; + ByteArrayOutputStream data = new ByteArrayOutputStream(); + byte[] buf = new byte[1024*1024]; // 1 KiB InputStream in = m_jar.getInputStream( entry ); - int bytesRead = in.read( buf ); - assert( bytesRead == buf.length ); + while( true ) + { + int bytesRead = in.read( buf ); + if( bytesRead <= 0 ) + { + break; + } + data.write( buf, 0, bytesRead ); + } + buf = data.toByteArray(); // translate the class ClassPool classPool = new ClassPool(); diff --git a/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java new file mode 100644 index 0000000..921a1e9 --- /dev/null +++ b/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java @@ -0,0 +1,56 @@ +package cuchaz.enigma.gui; + +import java.util.List; + +import javax.swing.tree.DefaultMutableTreeNode; + +import com.beust.jcommander.internal.Lists; + +import cuchaz.enigma.mapping.Ancestries; + +public class ClassInheritanceTreeNode extends DefaultMutableTreeNode +{ + private static final long serialVersionUID = 4432367405826178490L; + + String m_className; + + public ClassInheritanceTreeNode( String className ) + { + m_className = className; + } + + public String getClassName( ) + { + return m_className; + } + + @Override + public String toString( ) + { + return m_className; + } + + public void load( Ancestries ancestries, boolean recurse ) + { + // get all the child nodes + List nodes = Lists.newArrayList(); + for( String subclassName : ancestries.getSubclasses( m_className ) ) + { + nodes.add( new ClassInheritanceTreeNode( subclassName ) ); + } + + // add then to this node + for( ClassInheritanceTreeNode node : nodes ) + { + this.add( node ); + } + + if( recurse ) + { + for( ClassInheritanceTreeNode node : nodes ) + { + node.load( ancestries, true ); + } + } + } +} diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index f9afb64..2002a4d 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -49,12 +49,18 @@ import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.JTextField; +import javax.swing.JTree; import javax.swing.ListSelectionModel; import javax.swing.WindowConstants; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.text.BadLocationException; import javax.swing.text.Highlighter; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; + +import com.beust.jcommander.internal.Lists; import jsyntaxpane.DefaultSyntaxKit; import jsyntaxpane.SyntaxDocument; @@ -100,7 +106,7 @@ public class Gui private JPanel m_infoPanel; private BoxHighlightPainter m_obfuscatedHighlightPainter; private BoxHighlightPainter m_deobfuscatedHighlightPainter; - private JPanel m_inheritancePanel; + private JTree m_inheritanceTree; // dynamic menu items private JMenuItem m_closeJarMenu; @@ -136,6 +142,7 @@ public class Gui m_obfClasses.setCellRenderer( new ObfuscatedClassListCellRenderer() ); m_obfClasses.addMouseListener( new MouseAdapter() { + @Override public void mouseClicked( MouseEvent event ) { if( event.getClickCount() == 2 ) @@ -161,6 +168,7 @@ public class Gui m_deobfClasses.setCellRenderer( new DeobfuscatedClassListCellRenderer() ); m_deobfClasses.addMouseListener( new MouseAdapter() { + @Override public void mouseClicked( MouseEvent event ) { if( event.getClickCount() == 2 ) @@ -252,7 +260,26 @@ public class Gui } // init inheritance panel - m_inheritancePanel = new JPanel(); + m_inheritanceTree = new JTree(); + m_inheritanceTree.setModel( null ); + m_inheritanceTree.addMouseListener( new MouseAdapter( ) + { + @Override + public void mouseClicked( MouseEvent event ) + { + if( event.getClickCount() == 2 ) + { + ClassInheritanceTreeNode node = (ClassInheritanceTreeNode)m_inheritanceTree.getSelectionPath().getLastPathComponent(); + if( node != null ) + { + m_controller.deobfuscateClass( new ClassFile( node.getClassName() ) ); + } + } + } + } ); + JPanel inheritancePanel = new JPanel(); + inheritancePanel.setLayout( new BorderLayout() ); + inheritancePanel.add( new JScrollPane( m_inheritanceTree ) ); // layout controls JSplitPane splitLeft = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); @@ -263,7 +290,7 @@ public class Gui centerPanel.add( sourceScroller, BorderLayout.CENTER ); JTabbedPane tabbedPane = new JTabbedPane(); tabbedPane.setPreferredSize( new Dimension( 200, 0 ) ); - tabbedPane.addTab( "Inheritance", m_inheritancePanel ); + tabbedPane.addTab( "Inheritance", inheritancePanel ); JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, tabbedPane ); splitRight.setResizeWeight( 1 ); // let the left side take all the slack splitRight.resetToPreferredSizes(); @@ -748,12 +775,28 @@ public class Gui private void showInheritance( ) { - m_inheritancePanel.removeAll(); - - // TEMP - m_inheritancePanel.add( new JLabel( m_selectedEntryPair.obf.getName() ) ); - m_inheritancePanel.add( new JLabel( m_selectedEntryPair.deobf.getName() ) ); - + // get the current class + if( m_selectedEntryPair.obf instanceof ClassEntry ) + { + ClassInheritanceTreeNode classNode = m_controller.getClassInheritance( (ClassEntry)m_selectedEntryPair.obf ); + + // build the path from the root to the class node + List nodes = Lists.newArrayList(); + TreeNode node = classNode; + do + { + nodes.add( node ); + node = node.getParent(); + } + while( node != null ); + Collections.reverse( nodes ); + TreePath path = new TreePath( nodes.toArray() ); + + // show the tree at the root + m_inheritanceTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) ); + m_inheritanceTree.expandPath( path ); + m_inheritanceTree.setSelectionRow( m_inheritanceTree.getRowForPath( path ) ); + } redraw(); } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index e1ba49a..452632f 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -26,6 +26,7 @@ import cuchaz.enigma.ClassFile; import cuchaz.enigma.Deobfuscator; import cuchaz.enigma.analysis.Analyzer; import cuchaz.enigma.analysis.SourceIndex; +import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.EntryPair; import cuchaz.enigma.mapping.MappingsReader; @@ -129,6 +130,27 @@ public class GuiController return m_deobfuscator.hasMapping( pair.obf ); } + public ClassInheritanceTreeNode getClassInheritance( ClassEntry classEntry ) + { + // create a node for this class + ClassInheritanceTreeNode thisNode = new ClassInheritanceTreeNode( classEntry.getName() ); + + // expand all children recursively + thisNode.load( m_deobfuscator.getAncestries(), true ); + + // get the ancestors too + ClassInheritanceTreeNode node = thisNode; + for( String superclassName : m_deobfuscator.getAncestries().getAncestry( classEntry.getName() ) ) + { + // add the parent node + ClassInheritanceTreeNode parentNode = new ClassInheritanceTreeNode( superclassName ); + parentNode.add( node ); + node = parentNode; + } + + return thisNode; + } + public void rename( Entry obfsEntry, String newName, int lineNum ) { m_deobfuscator.rename( obfsEntry, newName ); diff --git a/src/cuchaz/enigma/mapping/Ancestries.java b/src/cuchaz/enigma/mapping/Ancestries.java index b7a5e24..f77a00e 100644 --- a/src/cuchaz/enigma/mapping/Ancestries.java +++ b/src/cuchaz/enigma/mapping/Ancestries.java @@ -26,6 +26,7 @@ import javassist.CtClass; import javassist.NotFoundException; import javassist.bytecode.Descriptor; +import com.beust.jcommander.internal.Lists; import com.google.common.collect.Maps; import cuchaz.enigma.Constants; @@ -121,11 +122,30 @@ public class Ancestries implements Serializable while( className != null ) { className = getSuperclassName( className ); - ancestors.add( className ); + if( className != null ) + { + ancestors.add( className ); + } } return ancestors; } + public List getSubclasses( String className ) + { + // linear search is fast enough for now + List subclasses = Lists.newArrayList(); + for( Map.Entry entry : m_superclasses.entrySet() ) + { + String subclass = entry.getKey(); + String superclass = entry.getValue(); + if( className.equals( superclass ) ) + { + subclasses.add( subclass ); + } + } + return subclasses; + } + private boolean isJre( String className ) { return className.startsWith( "java/" ) -- cgit v1.2.3