From faae0a6514c2565a10f9a62dd18c5d79fbbe4156 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 31 Jul 2014 22:27:26 -0400 Subject: fixed bug with save mappings menu gui shows deobfuscated classes list now working on name validation/sanitization --- src/cuchaz/enigma/ClassFile.java | 34 ++++++----- src/cuchaz/enigma/Deobfuscator.java | 60 +++++-------------- src/cuchaz/enigma/gui/ClassListCellRenderer.java | 40 +++++++++++++ src/cuchaz/enigma/gui/Gui.java | 64 +++++++++++++++++++-- src/cuchaz/enigma/gui/GuiController.java | 18 +++++- .../gui/ObfuscatedClassListCellRenderer.java | 40 ------------- src/cuchaz/enigma/mapping/NameValidator.java | 67 ++++++++++++++++++++++ 7 files changed, 216 insertions(+), 107 deletions(-) create mode 100644 src/cuchaz/enigma/gui/ClassListCellRenderer.java delete mode 100644 src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java create mode 100644 src/cuchaz/enigma/mapping/NameValidator.java (limited to 'src') diff --git a/src/cuchaz/enigma/ClassFile.java b/src/cuchaz/enigma/ClassFile.java index 221a119..c3c72a4 100644 --- a/src/cuchaz/enigma/ClassFile.java +++ b/src/cuchaz/enigma/ClassFile.java @@ -10,36 +10,42 @@ ******************************************************************************/ package cuchaz.enigma; -import java.util.regex.Pattern; public class ClassFile { - private static Pattern m_obfuscatedClassPattern; + private String m_obfName; + private String m_deobfName; - static + public ClassFile( String obfName ) { - m_obfuscatedClassPattern = Pattern.compile( "^[a-z]+$" ); + m_obfName = obfName; } - private String m_name; - - public ClassFile( String name ) + public String getName( ) { - m_name = name; + if( m_deobfName != null ) + { + return m_deobfName; + } + return m_obfName; } - public String getName( ) + public String getObfName( ) { - return m_name; + return m_obfName; } - public boolean isObfuscated( ) + public String getDeobfName( ) { - return m_obfuscatedClassPattern.matcher( m_name ).matches(); + return m_deobfName; } - + public void setDeobfName( String val ) + { + m_deobfName = val; + } + public String getPath( ) { - return m_name.replace( ".", "/" ) + ".class"; + return m_deobfName.replace( ".", "/" ) + ".class"; } } diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 7be5706..619eebf 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -15,9 +15,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; @@ -30,10 +27,12 @@ import com.strobel.decompiler.PlainTextOutput; import cuchaz.enigma.mapping.Ancestries; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ClassMapping; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.Mappings; import cuchaz.enigma.mapping.MethodEntry; +import cuchaz.enigma.mapping.NameValidator; import cuchaz.enigma.mapping.Renamer; import cuchaz.enigma.mapping.TranslationDirection; import cuchaz.enigma.mapping.Translator; @@ -47,25 +46,6 @@ public class Deobfuscator private Mappings m_mappings; private Renamer m_renamer; - private static Comparator m_obfuscatedClassSorter; - - static - { - m_obfuscatedClassSorter = new Comparator( ) - { - @Override - public int compare( ClassFile a, ClassFile b ) - { - if( a.getName().length() != b.getName().length() ) - { - return a.getName().length() - b.getName().length(); - } - - return a.getName().compareTo( b.getName() ); - } - }; - } - public Deobfuscator( File file ) throws IOException { @@ -120,48 +100,38 @@ public class Deobfuscator ) ); } - public List getObfuscatedClasses( ) + public void getSortedClasses( List obfClasses, List deobfClasses ) { - List classes = new ArrayList(); Enumeration entries = m_jar.entries(); while( entries.hasMoreElements() ) { JarEntry entry = entries.nextElement(); // get the class name - String className = toClassName( entry.getName() ); - if( className == null ) + String obfName = NameValidator.fileNameToClassName( entry.getName() ); + if( obfName == null ) { continue; } - ClassFile classFile = new ClassFile( className ); - if( classFile.isObfuscated() ) + ClassFile classFile = new ClassFile( obfName ); + ClassMapping classMapping = m_mappings.getClassByObf( classFile.getName() ); + if( classMapping != null ) { - classes.add( classFile ); + classFile.setDeobfName( classMapping.getDeobfName() ); + deobfClasses.add( classFile ); + } + else + { + obfClasses.add( classFile ); } } - Collections.sort( classes, m_obfuscatedClassSorter ); - return classes; - } - - // TODO: could go somewhere more generic - private static String toClassName( String fileName ) - { - final String suffix = ".class"; - - if( !fileName.endsWith( suffix ) ) - { - return null; - } - - return fileName.substring( 0, fileName.length() - suffix.length() ).replace( "/", "." ); } public String getSource( final ClassFile classFile ) { StringWriter buf = new StringWriter(); - Decompiler.decompile( classFile.getName(), new PlainTextOutput( buf ), m_settings ); + Decompiler.decompile( classFile.getObfName(), new PlainTextOutput( buf ), m_settings ); return buf.toString(); } diff --git a/src/cuchaz/enigma/gui/ClassListCellRenderer.java b/src/cuchaz/enigma/gui/ClassListCellRenderer.java new file mode 100644 index 0000000..302f140 --- /dev/null +++ b/src/cuchaz/enigma/gui/ClassListCellRenderer.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.gui; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; + +import cuchaz.enigma.ClassFile; + +public class ClassListCellRenderer implements ListCellRenderer +{ + private DefaultListCellRenderer m_defaultRenderer; + + public ClassListCellRenderer( ) + { + m_defaultRenderer = new DefaultListCellRenderer(); + } + + @Override + public Component getListCellRendererComponent( JList list, ClassFile classFile, int index, boolean isSelected, boolean hasFocus ) + { + JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, classFile, index, isSelected, hasFocus ); + + label.setText( classFile.getName() ); + + return label; + } +} diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index a86ff9b..d448dc2 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -21,6 +21,8 @@ import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.IOException; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Vector; @@ -58,6 +60,25 @@ import cuchaz.enigma.mapping.MethodEntry; public class Gui { + private static Comparator m_obfuscatedClassSorter; + + static + { + m_obfuscatedClassSorter = new Comparator( ) + { + @Override + public int compare( ClassFile a, ClassFile b ) + { + if( a.getName().length() != b.getName().length() ) + { + return a.getName().length() - b.getName().length(); + } + + return a.getName().compareTo( b.getName() ); + } + }; + } + private GuiController m_controller; // controls @@ -101,7 +122,7 @@ public class Gui m_obfClasses = new JList(); m_obfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); m_obfClasses.setLayoutOrientation( JList.VERTICAL ); - m_obfClasses.setCellRenderer( new ObfuscatedClassListCellRenderer() ); + m_obfClasses.setCellRenderer( new ClassListCellRenderer() ); m_obfClasses.addMouseListener( new MouseAdapter() { public void mouseClicked( MouseEvent event ) @@ -124,8 +145,23 @@ public class Gui // init deobfuscated classes list m_deobfClasses = new JList(); - m_obfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); - m_obfClasses.setLayoutOrientation( JList.VERTICAL ); + m_deobfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); + m_deobfClasses.setLayoutOrientation( JList.VERTICAL ); + m_deobfClasses.setCellRenderer( new ClassListCellRenderer() ); + m_deobfClasses.addMouseListener( new MouseAdapter() + { + public void mouseClicked( MouseEvent event ) + { + if( event.getClickCount() == 2 ) + { + ClassFile selected = m_deobfClasses.getSelectedValue(); + if( selected != null ) + { + m_controller.deobfuscateClass( selected ); + } + } + } + } ); JScrollPane deobfScroller = new JScrollPane( m_deobfClasses ); JPanel deobfPanel = new JPanel(); deobfPanel.setLayout( new BorderLayout() ); @@ -248,7 +284,6 @@ public class Gui try { m_controller.openMappings( m_mappingFileChooser.getSelectedFile() ); - m_saveMappingsMenu.setEnabled( true ); } catch( IOException ex ) { @@ -383,7 +418,9 @@ public class Gui { if( classes != null ) { - m_obfClasses.setListData( new Vector( classes ) ); + Vector sortedClasses = new Vector( classes ); + Collections.sort( sortedClasses, m_obfuscatedClassSorter ); + m_obfClasses.setListData( sortedClasses ); } else { @@ -391,6 +428,23 @@ public class Gui } } + public void setDeobfClasses( List classes ) + { + if( classes != null ) + { + m_deobfClasses.setListData( new Vector( classes ) ); + } + else + { + m_deobfClasses.setListData( new Vector() ); + } + } + + public void setMappingsLoaded( boolean isLoaded ) + { + m_saveMappingsMenu.setEnabled( isLoaded ); + } + public void setSource( String source ) { setSource( source, null ); diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index fb22b96..ce1c31b 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -14,6 +14,8 @@ import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import cuchaz.enigma.ClassFile; import cuchaz.enigma.Deobfuscator; @@ -45,7 +47,7 @@ public class GuiController { m_deobfuscator = new Deobfuscator( file ); m_gui.onOpenJar( m_deobfuscator.getJarName() ); - m_gui.setObfClasses( m_deobfuscator.getObfuscatedClasses() ); + refreshClasses(); } public void closeJar( ) @@ -60,8 +62,8 @@ public class GuiController FileReader in = new FileReader( file ); m_deobfuscator.setMappings( new MappingsReader().read( in ) ); in.close(); - // TEMP - System.out.println( m_deobfuscator.getMappings() ); + m_gui.setMappingsLoaded( true ); + refreshClasses(); refreshOpenFiles(); } @@ -76,6 +78,7 @@ public class GuiController public void closeMappings( ) { m_deobfuscator.setMappings( null ); + m_gui.setMappingsLoaded( false ); refreshOpenFiles(); } @@ -119,6 +122,15 @@ public class GuiController refreshOpenFiles(); } + private void refreshClasses( ) + { + List obfClasses = new ArrayList(); + List deobfClasses = new ArrayList(); + m_deobfuscator.getSortedClasses( obfClasses, deobfClasses ); + m_gui.setObfClasses( obfClasses ); + m_gui.setDeobfClasses( deobfClasses ); + } + private void refreshOpenFiles( ) { if( m_currentFile != null ) diff --git a/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java b/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java deleted file mode 100644 index 0badb3b..0000000 --- a/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.Component; - -import javax.swing.DefaultListCellRenderer; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.ListCellRenderer; - -import cuchaz.enigma.ClassFile; - -public class ObfuscatedClassListCellRenderer implements ListCellRenderer -{ - private DefaultListCellRenderer m_defaultRenderer; - - public ObfuscatedClassListCellRenderer( ) - { - m_defaultRenderer = new DefaultListCellRenderer(); - } - - @Override - public Component getListCellRendererComponent( JList list, ClassFile classFile, int index, boolean isSelected, boolean hasFocus ) - { - JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, classFile, index, isSelected, hasFocus ); - - label.setText( classFile.getName() ); - - return label; - } -} diff --git a/src/cuchaz/enigma/mapping/NameValidator.java b/src/cuchaz/enigma/mapping/NameValidator.java new file mode 100644 index 0000000..30982dc --- /dev/null +++ b/src/cuchaz/enigma/mapping/NameValidator.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.mapping; + +import java.util.regex.Pattern; + +public class NameValidator +{ + private static final String IdentifierPattern; + private static final Pattern ClassPattern; + + static + { + // java allows all kinds of weird characters... + StringBuilder startChars = new StringBuilder(); + StringBuilder partChars = new StringBuilder(); + for( int i = Character.MIN_CODE_POINT; i <= Character.MAX_CODE_POINT; i++ ) + { + if( Character.isJavaIdentifierStart( i ) ) + { + startChars.appendCodePoint( i ); + } + if( Character.isJavaIdentifierPart( i ) ) + { + partChars.appendCodePoint( i ); + } + } + + IdentifierPattern = String.format( "[\\Q%s\\E][\\Q%s\\E]*", startChars.toString(), partChars.toString() ); + ClassPattern = Pattern.compile( String.format( "^(%s(\\.|/))*(%s)$", IdentifierPattern, IdentifierPattern ) ); + } + + public String validateClassName( String name ) + { + if( !ClassPattern.matcher( name ).matches() ) + { + throw new IllegalArgumentException( "Illegal name: " + name ); + } + + return classNameToJavaName( name ); + } + + public static String fileNameToClassName( String fileName ) + { + final String suffix = ".class"; + + if( !fileName.endsWith( suffix ) ) + { + return null; + } + + return fileName.substring( 0, fileName.length() - suffix.length() ).replace( "/", "." ); + } + + public static String classNameToJavaName( String className ) + { + return className.replace( ".", "/" ); + } +} -- cgit v1.2.3