From a83bbfd5c510367a194073b1db132022cacf65ed Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 30 Sep 2014 00:25:36 -0400 Subject: fixed nasty issue with renaming inner classes, but alas, more bugs remain --- src/cuchaz/enigma/Deobfuscator.java | 3 +- src/cuchaz/enigma/TranslatingTypeLoader.java | 10 +++--- src/cuchaz/enigma/analysis/EntryReference.java | 15 +++++++++ src/cuchaz/enigma/analysis/JarIndex.java | 7 ++-- src/cuchaz/enigma/analysis/SourceIndex.java | 2 -- src/cuchaz/enigma/bytecode/ClassRenamer.java | 31 ++++-------------- src/cuchaz/enigma/bytecode/ClassTranslator.java | 6 +++- src/cuchaz/enigma/bytecode/InnerClassWriter.java | 20 ++++++------ src/cuchaz/enigma/gui/Gui.java | 4 +-- src/cuchaz/enigma/mapping/ClassMapping.java | 18 +++++++++-- src/cuchaz/enigma/mapping/MappingsReader.java | 41 +++++++++++++----------- src/cuchaz/enigma/mapping/MappingsRenamer.java | 6 ++-- src/cuchaz/enigma/mapping/NameValidator.java | 6 ++-- src/cuchaz/enigma/mapping/Translator.java | 17 +++++++--- 14 files changed, 108 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index bd4345e7..d45ffb41 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -45,7 +45,6 @@ import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.SourceIndexVisitor; import cuchaz.enigma.analysis.Token; -import cuchaz.enigma.analysis.TreeDumpVisitor; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.BehaviorEntryFactory; @@ -221,7 +220,7 @@ public class Deobfuscator String outerClassName = m_jarIndex.getOuterClass( classMapping.getObfName() ); if( outerClassName != null ) { - classEntry = new ClassEntry( outerClassName + "$" + classEntry.getSimpleName() ); + classEntry = new ClassEntry( outerClassName + "$" + classMapping.getObfName() ); } if( !m_jarIndex.getObfClassEntries().contains( classEntry ) ) { diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index 6179879a..86e52a34 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -13,6 +13,7 @@ package cuchaz.enigma; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -119,7 +120,6 @@ public class TranslatingTypeLoader implements ITypeLoader private byte[] loadType( String deobfClassName ) { - // what class file should we actually load? ClassEntry deobfClassEntry = new ClassEntry( deobfClassName ); ClassEntry obfClassEntry = m_obfuscatingTranslator.translateEntry( deobfClassEntry ); @@ -143,7 +143,7 @@ public class TranslatingTypeLoader implements ITypeLoader String classFileName; if( obfClassEntry.isInnerClass() ) { - // use just the inner class simple name for inner classes + // use just the inner class name for inner classes classFileName = obfClassEntry.getInnerClassName(); } else if( obfClassEntry.getPackageName().equals( Constants.NonePackage ) ) @@ -193,6 +193,9 @@ public class TranslatingTypeLoader implements ITypeLoader // sanity checking assertClassName( c, deobfClassEntry ); + // DEBUG + //Util.writeClass( c ); + // we have a transformed class! return c.toBytecode(); } @@ -227,9 +230,6 @@ public class TranslatingTypeLoader implements ITypeLoader new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c ); new ClassTranslator( m_deobfuscatingTranslator ).translate( c ); - // DEBUG - //Util.writeClass( c ); - return c; } diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java index 4da2f589..0cde8759 100644 --- a/src/cuchaz/enigma/analysis/EntryReference.java +++ b/src/cuchaz/enigma/analysis/EntryReference.java @@ -79,6 +79,21 @@ public class EntryReference return entry; } + public String getNamableName( ) + { + if( getNameableEntry() instanceof ClassEntry ) + { + ClassEntry classEntry = (ClassEntry)getNameableEntry(); + if( classEntry.isInnerClass() ) + { + // make sure we only rename the inner class name + return classEntry.getInnerClassName(); + } + } + + return getNameableEntry().getName(); + } + @Override public int hashCode( ) { diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 604e4853..ba082064 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -164,9 +164,10 @@ public class JarIndex String outerClassName = findOuterClass( c ); if( outerClassName != null ) { - String innerClassName = Descriptor.toJvmName( c.getName() ); + String innerClassName = c.getSimpleName(); m_innerClasses.put( outerClassName, innerClassName ); - m_outerClasses.put( innerClassName, outerClassName ); + boolean innerWasAdded = m_outerClasses.put( innerClassName, outerClassName ) == null; + assert( innerWasAdded ); BehaviorEntry enclosingBehavior = isAnonymousClass( c, outerClassName ); if( enclosingBehavior != null ) @@ -188,7 +189,7 @@ public class JarIndex Map renames = Maps.newHashMap(); for( Map.Entry entry : m_outerClasses.entrySet() ) { - renames.put( entry.getKey(), entry.getValue() + "$" + new ClassEntry( entry.getKey() ).getSimpleName() ); + renames.put( Constants.NonePackage + "/" + entry.getKey(), entry.getValue() + "$" + entry.getKey() ); } EntryRenamer.renameClassesInSet( renames, m_obfClassEntries ); m_translationIndex.renameClasses( renames ); diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index faae1a14..21a499e8 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -89,14 +89,12 @@ public class SourceIndex // DEBUG //System.out.println( String.format( "%s \"%s\" region: %s", node.getNodeType(), name, region ) ); - /* TODO: double check that we still need this // for tokens representing inner classes, make sure we only get the simple name int pos = node.getText().lastIndexOf( '$' ); if( pos >= 0 ) { token.end -= pos + 1; } - */ return token; } diff --git a/src/cuchaz/enigma/bytecode/ClassRenamer.java b/src/cuchaz/enigma/bytecode/ClassRenamer.java index 9f0845da..849a3233 100644 --- a/src/cuchaz/enigma/bytecode/ClassRenamer.java +++ b/src/cuchaz/enigma/bytecode/ClassRenamer.java @@ -37,34 +37,25 @@ public class ClassRenamer { nameMap.put( entry.getKey().getName(), entry.getValue().getName() ); } + c.replaceClassName( nameMap ); - // translate the names in the InnerClasses attribute + // replace simple names in the InnerClasses attribute too ConstPool constants = c.getClassFile().getConstPool(); InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute( InnerClassesAttribute.tag ); if( attr != null ) { for( int i=0; i ATTR: %s,%s,%s", - obfClassEntry, deobfClassEntry, + System.out.println( String.format( "\tDEOBF: %s-> ATTR: %s,%s,%s", + classEntry, attr.outerClass( i ), attr.innerClass( i ), attr.innerName( i ) @@ -109,16 +100,6 @@ public class ClassRenamer }; c.replaceClassName( map ); - // also check InnerClassesAttribute - InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute( InnerClassesAttribute.tag ); - if( attr != null ) - { - for( int i=0; i map = Maps.newHashMap(); for( ClassEntry obfClassEntry : ClassRenamer.getAllClassEntries( c ) ) { - map.put( obfClassEntry, m_translator.translateEntry( obfClassEntry ) ); + ClassEntry deobfClassEntry = m_translator.translateEntry( obfClassEntry ); + if( !obfClassEntry.equals( deobfClassEntry ) ) + { + map.put( obfClassEntry, deobfClassEntry ); + } } ClassRenamer.renameClasses( c, map ); } diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java index a0617925..5e593078 100644 --- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java +++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java @@ -18,6 +18,7 @@ import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; import javassist.bytecode.EnclosingMethodAttribute; import javassist.bytecode.InnerClassesAttribute; +import cuchaz.enigma.Constants; import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; @@ -33,21 +34,21 @@ public class InnerClassWriter public void write( CtClass c ) { - // get the outer class name - String obfClassName = Descriptor.toJvmName( c.getName() ); - String obfOuterClassName = m_jarIndex.getOuterClass( obfClassName ); + // is this an inner or outer class? + String obfInnerClassName = new ClassEntry( Descriptor.toJvmName( c.getName() ) ).getSimpleName(); + String obfOuterClassName = m_jarIndex.getOuterClass( obfInnerClassName ); if( obfOuterClassName == null ) { // this is an outer class - obfOuterClassName = obfClassName; + obfOuterClassName = Descriptor.toJvmName( c.getName() ); } else { // this is an inner class, rename it to outer$inner - ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + new ClassEntry( obfClassName ).getSimpleName() ); + ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + obfInnerClassName ); c.setName( obfClassEntry.getName() ); - BehaviorEntry caller = m_jarIndex.getAnonymousClassCaller( obfClassName ); + BehaviorEntry caller = m_jarIndex.getAnonymousClassCaller( obfInnerClassName ); if( caller != null ) { // write the enclosing method attribute @@ -85,7 +86,7 @@ public class InnerClassWriter for( String obfInnerClassName : obfInnerClassNames ) { // get the new inner class name - ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + new ClassEntry( obfInnerClassName ).getSimpleName() ); + ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + obfInnerClassName ); // here's what the JVM spec says about the InnerClasses attribute // append( inner, outer of inner if inner is member of outer 0 ow, name after $ if inner not anonymous 0 ow, flags ); @@ -114,12 +115,13 @@ public class InnerClassWriter attr.outerClass( attr.tableLength() - 1 ), attr.innerClass( attr.tableLength() - 1 ), attr.innerName( attr.tableLength() - 1 ), - obfInnerClassName, obfClassEntry.getName() + Constants.NonePackage + "/" + obfInnerClassName, + obfClassEntry.getName() ) ); */ // make sure the outer class references only the new inner class names - c.replaceClassName( obfInnerClassName, obfClassEntry.getName() ); + c.replaceClassName( Constants.NonePackage + "/" + obfInnerClassName, obfClassEntry.getName() ); } } } diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index dbfcba83..faa9b7b1 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -1124,7 +1124,7 @@ public class Gui { // init the text box final JTextField text = new JTextField(); - text.setText( m_reference.getNameableEntry().getName() ); + text.setText( m_reference.getNamableName() ); text.setPreferredSize( new Dimension( 360, text.getPreferredSize().height ) ); text.addKeyListener( new KeyAdapter( ) { @@ -1175,7 +1175,7 @@ public class Gui // abort the rename JPanel panel = (JPanel)m_infoPanel.getComponent( 0 ); panel.remove( panel.getComponentCount() - 1 ); - panel.add( GuiTricks.unboldLabel( new JLabel( m_reference.getNameableEntry().getName(), JLabel.LEFT ) ) ); + panel.add( GuiTricks.unboldLabel( new JLabel( m_reference.getNamableName(), JLabel.LEFT ) ) ); m_editor.grabFocus(); diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index 88106dfa..ee02781e 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -37,7 +37,7 @@ public class ClassMapping implements Serializable, Comparable public ClassMapping( String obfName, String deobfName ) { m_obfName = obfName; - m_deobfName = NameValidator.validateClassName( deobfName ); + m_deobfName = NameValidator.validateClassName( deobfName, false ); m_innerClassesByObf = Maps.newHashMap(); m_innerClassesByDeobf = Maps.newHashMap(); m_fieldsByObf = Maps.newHashMap(); @@ -57,7 +57,7 @@ public class ClassMapping implements Serializable, Comparable } public void setDeobfName( String val ) { - m_deobfName = NameValidator.validateClassName( val ); + m_deobfName = NameValidator.validateClassName( val, false ); } //// INNER CLASSES //////// @@ -70,10 +70,12 @@ public class ClassMapping implements Serializable, Comparable public void addInnerClassMapping( ClassMapping classMapping ) { + assert( isSimpleClassName( classMapping.getObfName() ) ); boolean obfWasAdded = m_innerClassesByObf.put( classMapping.getObfName(), classMapping ) == null; assert( obfWasAdded ); if( classMapping.getDeobfName() != null ) { + assert( isSimpleClassName( classMapping.getDeobfName() ) ); boolean deobfWasAdded = m_innerClassesByDeobf.put( classMapping.getDeobfName(), classMapping ) == null; assert( deobfWasAdded ); } @@ -92,6 +94,7 @@ public class ClassMapping implements Serializable, Comparable public ClassMapping getOrCreateInnerClass( String obfName ) { + assert( isSimpleClassName( obfName ) ); ClassMapping classMapping = m_innerClassesByObf.get( obfName ); if( classMapping == null ) { @@ -104,16 +107,19 @@ public class ClassMapping implements Serializable, Comparable public ClassMapping getInnerClassByObf( String obfName ) { + assert( isSimpleClassName( obfName ) ); return m_innerClassesByObf.get( obfName ); } public ClassMapping getInnerClassByDeobf( String deobfName ) { + assert( isSimpleClassName( deobfName ) ); return m_innerClassesByDeobf.get( deobfName ); } public String getObfInnerClassName( String deobfName ) { + assert( isSimpleClassName( deobfName ) ); ClassMapping classMapping = m_innerClassesByDeobf.get( deobfName ); if( classMapping != null ) { @@ -124,6 +130,7 @@ public class ClassMapping implements Serializable, Comparable public String getDeobfInnerClassName( String obfName ) { + assert( isSimpleClassName( obfName ) ); ClassMapping classMapping = m_innerClassesByObf.get( obfName ); if( classMapping != null ) { @@ -134,6 +141,7 @@ public class ClassMapping implements Serializable, Comparable public void setInnerClassName( String obfName, String deobfName ) { + assert( isSimpleClassName( obfName ) ); ClassMapping classMapping = getOrCreateInnerClass( obfName ); if( classMapping.getDeobfName() != null ) { @@ -143,6 +151,7 @@ public class ClassMapping implements Serializable, Comparable classMapping.setDeobfName( deobfName ); if( deobfName != null ) { + assert( isSimpleClassName( deobfName ) ); boolean wasAdded = m_innerClassesByDeobf.put( deobfName, classMapping ) == null; assert( wasAdded ); } @@ -442,4 +451,9 @@ public class ClassMapping implements Serializable, Comparable } return false; } + + public static boolean isSimpleClassName( String name ) + { + return name.indexOf( '/' ) < 0 && name.indexOf( '$' ) < 0; + } } diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java index 5cbad59c..4bd9f121 100644 --- a/src/cuchaz/enigma/mapping/MappingsReader.java +++ b/src/cuchaz/enigma/mapping/MappingsReader.java @@ -78,10 +78,11 @@ public class MappingsReader if( token.equalsIgnoreCase( "CLASS" ) ) { - ClassMapping classMapping = readClass( parts ); + ClassMapping classMapping; if( indent == 0 ) { // outer class + classMapping = readClass( parts, false ); mappings.addClassMapping( classMapping ); } else if( indent == 1 ) @@ -91,11 +92,13 @@ public class MappingsReader { throw new MappingParseException( lineNumber, "Unexpected CLASS entry here!" ); } + + classMapping = readClass( parts, true ); ((ClassMapping)mappingStack.getFirst()).addInnerClassMapping( classMapping ); } else { - throw new MappingParseException( lineNumber, "Unexpected CLASS entry here!" ); + throw new MappingParseException( lineNumber, "Unexpected CLASS entry nesting!" ); } mappingStack.push( classMapping ); } @@ -140,28 +143,30 @@ public class MappingsReader return new ArgumentMapping( Integer.parseInt( parts[1] ), parts[2] ); } - private ClassMapping readClass( String[] parts ) + private ClassMapping readClass( String[] parts, boolean makeSimple ) { if( parts.length == 2 ) { - String obfName = parts[1]; - return new ClassMapping( moveClassOutOfDefaultPackage( obfName, Constants.NonePackage ) ); + String obfName = processName( parts[1], makeSimple ); + return new ClassMapping( obfName ); } else { - String obfName = parts[1]; - String deobfName = parts[2]; - if( obfName.equals( deobfName ) ) - { - return new ClassMapping( moveClassOutOfDefaultPackage( obfName, Constants.NonePackage ) ); - } - else - { - return new ClassMapping( - moveClassOutOfDefaultPackage( parts[1], Constants.NonePackage ), - moveClassOutOfDefaultPackage( parts[2], Constants.NonePackage ) - ); - } + String obfName = processName( parts[1], makeSimple ); + String deobfName = processName( parts[2], makeSimple ); + return new ClassMapping( obfName, deobfName ); + } + } + + private String processName( String name, boolean makeSimple ) + { + if( makeSimple ) + { + return new ClassEntry( name ).getSimpleName(); + } + else + { + return moveClassOutOfDefaultPackage( name, Constants.NonePackage ); } } diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index 957b6d68..24ec7318 100644 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -16,6 +16,7 @@ import java.io.OutputStream; import java.util.Set; import java.util.zip.GZIPOutputStream; +import cuchaz.enigma.Constants; import cuchaz.enigma.analysis.JarIndex; public class MappingsRenamer @@ -31,7 +32,7 @@ public class MappingsRenamer public void setClassName( ClassEntry obf, String deobfName ) { - deobfName = NameValidator.validateClassName( deobfName ); + deobfName = NameValidator.validateClassName( deobfName, !obf.isInnerClass() ); ClassEntry targetEntry = new ClassEntry( deobfName ); if( m_mappings.containsDeobfClass( deobfName ) || m_index.containsObfClass( targetEntry ) ) { @@ -77,7 +78,8 @@ public class MappingsRenamer ClassMapping classMapping = getOrCreateClassMapping( obf ); if( obf.isInnerClass() ) { - classMapping.setInnerClassName( obf.getName(), obf.getName() ); + String innerClassName = Constants.NonePackage + "/" + obf.getInnerClassName(); + classMapping.setInnerClassName( innerClassName, innerClassName ); } else { diff --git a/src/cuchaz/enigma/mapping/NameValidator.java b/src/cuchaz/enigma/mapping/NameValidator.java index 9adf1ac1..c6ae5969 100644 --- a/src/cuchaz/enigma/mapping/NameValidator.java +++ b/src/cuchaz/enigma/mapping/NameValidator.java @@ -55,7 +55,7 @@ public class NameValidator ClassPattern = Pattern.compile( String.format( "^(%s(\\.|/))*(%s)$", identifierRegex, identifierRegex ) ); } - public static String validateClassName( String name ) + public static String validateClassName( String name, boolean packageRequired ) { if( name == null ) { @@ -65,9 +65,9 @@ public class NameValidator { throw new IllegalNameException( name, "This doesn't look like a legal class name" ); } - if( new ClassEntry( name ).getPackageName() == null ) + if( packageRequired && new ClassEntry( name ).getPackageName() == null ) { - throw new IllegalNameException( name, "Classes must be in a package" ); + throw new IllegalNameException( name, "Class must be in a package" ); } return Descriptor.toJvmName( name ); } diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index 7904ef53..1c69b2f4 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -80,19 +80,26 @@ public class Translator { if( in.isInnerClass() ) { - // look for the inner class + // translate the inner class String translatedInnerClassName = m_direction.choose( classMapping.getDeobfInnerClassName( in.getInnerClassName() ), classMapping.getObfInnerClassName( in.getInnerClassName() ) ); if( translatedInnerClassName != null ) { - // return outer$inner + // try to translate the outer name String translatedOuterClassName = m_direction.choose( classMapping.getDeobfName(), classMapping.getObfName() ); - return translatedOuterClassName + "$" + translatedInnerClassName; + if( translatedOuterClassName != null ) + { + return translatedOuterClassName + "$" + translatedInnerClassName; + } + else + { + return in.getOuterClassName() + "$" + translatedInnerClassName; + } } } else @@ -109,6 +116,7 @@ public class Translator public ClassEntry translateEntry( ClassEntry in ) { + // can we translate the inner class? String name = translate( in ); if( name != null ) { @@ -117,13 +125,14 @@ public class Translator if( in.isInnerClass() ) { - // just translate the outer class name + // guess not. just translate the outer class name then String outerClassName = translate( in.getOuterClassEntry() ); if( outerClassName != null ) { return new ClassEntry( outerClassName + "$" + in.getInnerClassName() ); } } + return in; } -- cgit v1.2.3