diff options
| author | 2014-08-18 00:55:30 -0400 | |
|---|---|---|
| committer | 2014-08-18 00:55:30 -0400 | |
| commit | 34c1e8e64ec4575527a19fb4cb0640c57da784db (patch) | |
| tree | 44e3f1d50f8d8b8a9ab7c26dd94b58cba750cc67 /src/cuchaz/enigma/bytecode | |
| parent | added support for automatic reconstruction of inner and anonymous classes (diff) | |
| download | enigma-fork-34c1e8e64ec4575527a19fb4cb0640c57da784db.tar.gz enigma-fork-34c1e8e64ec4575527a19fb4cb0640c57da784db.tar.xz enigma-fork-34c1e8e64ec4575527a19fb4cb0640c57da784db.zip | |
crap-ton of bug fixes for inner classes
Diffstat (limited to 'src/cuchaz/enigma/bytecode')
| -rw-r--r-- | src/cuchaz/enigma/bytecode/BytecodeTools.java | 57 | ||||
| -rw-r--r-- | src/cuchaz/enigma/bytecode/ClassTranslator.java | 53 | ||||
| -rw-r--r-- | src/cuchaz/enigma/bytecode/InnerClassWriter.java | 42 |
3 files changed, 116 insertions, 36 deletions
diff --git a/src/cuchaz/enigma/bytecode/BytecodeTools.java b/src/cuchaz/enigma/bytecode/BytecodeTools.java index 664350e..0de9bd6 100644 --- a/src/cuchaz/enigma/bytecode/BytecodeTools.java +++ b/src/cuchaz/enigma/bytecode/BytecodeTools.java | |||
| @@ -15,6 +15,7 @@ import java.io.ByteArrayOutputStream; | |||
| 15 | import java.io.DataInputStream; | 15 | import java.io.DataInputStream; |
| 16 | import java.io.DataOutputStream; | 16 | import java.io.DataOutputStream; |
| 17 | import java.io.IOException; | 17 | import java.io.IOException; |
| 18 | import java.util.List; | ||
| 18 | import java.util.Map; | 19 | import java.util.Map; |
| 19 | import java.util.Set; | 20 | import java.util.Set; |
| 20 | 21 | ||
| @@ -25,6 +26,7 @@ import javassist.bytecode.CodeAttribute; | |||
| 25 | import javassist.bytecode.ConstPool; | 26 | import javassist.bytecode.ConstPool; |
| 26 | import javassist.bytecode.ExceptionTable; | 27 | import javassist.bytecode.ExceptionTable; |
| 27 | 28 | ||
| 29 | import com.beust.jcommander.internal.Lists; | ||
| 28 | import com.google.common.collect.Maps; | 30 | import com.google.common.collect.Maps; |
| 29 | import com.google.common.collect.Sets; | 31 | import com.google.common.collect.Sets; |
| 30 | 32 | ||
| @@ -266,4 +268,59 @@ public class BytecodeTools | |||
| 266 | ); | 268 | ); |
| 267 | } | 269 | } |
| 268 | } | 270 | } |
| 271 | |||
| 272 | public static List<String> getParameterTypes( String signature ) | ||
| 273 | { | ||
| 274 | List<String> types = Lists.newArrayList(); | ||
| 275 | for( int i=0; i<signature.length(); ) | ||
| 276 | { | ||
| 277 | char c = signature.charAt( i ); | ||
| 278 | |||
| 279 | // handle parens | ||
| 280 | if( c == '(' ) | ||
| 281 | { | ||
| 282 | i++; | ||
| 283 | c = signature.charAt( i ); | ||
| 284 | } | ||
| 285 | if( c == ')' ) | ||
| 286 | { | ||
| 287 | break; | ||
| 288 | } | ||
| 289 | |||
| 290 | // find a type | ||
| 291 | String type = null; | ||
| 292 | |||
| 293 | int arrayDim = 0; | ||
| 294 | while( c == '[' ) | ||
| 295 | { | ||
| 296 | // advance to array type | ||
| 297 | arrayDim++; | ||
| 298 | i++; | ||
| 299 | c = signature.charAt( i ); | ||
| 300 | } | ||
| 301 | |||
| 302 | if( c == 'L' ) | ||
| 303 | { | ||
| 304 | // read class type | ||
| 305 | int pos = signature.indexOf( ';', i + 1 ); | ||
| 306 | String className = signature.substring( i + 1, pos ); | ||
| 307 | type = "L" + className + ";"; | ||
| 308 | i = pos + 1; | ||
| 309 | } | ||
| 310 | else | ||
| 311 | { | ||
| 312 | // read primitive type | ||
| 313 | type = signature.substring( i, i + 1 ); | ||
| 314 | i++; | ||
| 315 | } | ||
| 316 | |||
| 317 | // was it an array? | ||
| 318 | while( arrayDim-- > 0 ) | ||
| 319 | { | ||
| 320 | type = "[" + type; | ||
| 321 | } | ||
| 322 | types.add( type ); | ||
| 323 | } | ||
| 324 | return types; | ||
| 325 | } | ||
| 269 | } | 326 | } |
diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java index 3b5beeb..9ce06a5 100644 --- a/src/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | package cuchaz.enigma.bytecode; | 11 | package cuchaz.enigma.bytecode; |
| 12 | 12 | ||
| 13 | import java.util.HashSet; | ||
| 14 | import java.util.Set; | 13 | import java.util.Set; |
| 15 | 14 | ||
| 16 | import javassist.ClassMap; | 15 | import javassist.ClassMap; |
| @@ -20,6 +19,10 @@ import javassist.CtField; | |||
| 20 | import javassist.CtMethod; | 19 | import javassist.CtMethod; |
| 21 | import javassist.bytecode.ConstPool; | 20 | import javassist.bytecode.ConstPool; |
| 22 | import javassist.bytecode.Descriptor; | 21 | import javassist.bytecode.Descriptor; |
| 22 | import javassist.bytecode.InnerClassesAttribute; | ||
| 23 | |||
| 24 | import com.beust.jcommander.internal.Sets; | ||
| 25 | |||
| 23 | import cuchaz.enigma.mapping.ClassEntry; | 26 | import cuchaz.enigma.mapping.ClassEntry; |
| 24 | import cuchaz.enigma.mapping.FieldEntry; | 27 | import cuchaz.enigma.mapping.FieldEntry; |
| 25 | import cuchaz.enigma.mapping.MethodEntry; | 28 | import cuchaz.enigma.mapping.MethodEntry; |
| @@ -133,25 +136,47 @@ public class ClassTranslator | |||
| 133 | 136 | ||
| 134 | // translate all the class names referenced in the code | 137 | // translate all the class names referenced in the code |
| 135 | // the above code only changed method/field/reference names and types, but not the class names themselves | 138 | // the above code only changed method/field/reference names and types, but not the class names themselves |
| 136 | Set<String> classNames = getAllClassNames( c ); | 139 | Set<ClassEntry> classEntries = getAllClassEntries( c ); |
| 137 | ClassMap map = new ClassMap(); | 140 | ClassMap map = new ClassMap(); |
| 138 | for( String className : classNames ) | 141 | for( ClassEntry obfClassEntry : classEntries ) |
| 139 | { | 142 | { |
| 140 | String translatedName = m_translator.translateClass( className ); | 143 | map.put( obfClassEntry.getName(), m_translator.translateEntry( obfClassEntry ).getName() ); |
| 141 | if( translatedName != null ) | ||
| 142 | { | ||
| 143 | map.put( className, translatedName ); | ||
| 144 | } | ||
| 145 | } | 144 | } |
| 146 | if( !map.isEmpty() ) | 145 | c.replaceClassName( map ); |
| 146 | |||
| 147 | // translate the names in the InnerClasses attribute | ||
| 148 | InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute( InnerClassesAttribute.tag ); | ||
| 149 | if( attr != null ) | ||
| 147 | { | 150 | { |
| 148 | c.replaceClassName( map ); | 151 | for( int i=0; i<attr.tableLength(); i++ ) |
| 152 | { | ||
| 153 | ClassEntry obfClassEntry = new ClassEntry( Descriptor.toJvmName( attr.innerClass( i ) ) ); | ||
| 154 | ClassEntry deobfClassEntry = m_translator.translateEntry( obfClassEntry ); | ||
| 155 | attr.setInnerClassIndex( i, constants.addClassInfo( deobfClassEntry.getName() ) ); | ||
| 156 | if( attr.outerClassIndex( i ) != 0 ) | ||
| 157 | { | ||
| 158 | attr.setOuterClassIndex( i, constants.addClassInfo( deobfClassEntry.getOuterClassName() ) ); | ||
| 159 | } | ||
| 160 | if( attr.innerNameIndex( i ) != 0 ) | ||
| 161 | { | ||
| 162 | attr.setInnerNameIndex( i, constants.addUtf8Info( deobfClassEntry.getInnerClassName() ) ); | ||
| 163 | } | ||
| 164 | |||
| 165 | /* DEBUG | ||
| 166 | System.out.println( String.format( "\tOBF: %s DEOBF: %s-> ATTR: %s,%s,%s", | ||
| 167 | obfClassEntry, deobfClassEntry, | ||
| 168 | attr.outerClass( i ), | ||
| 169 | attr.innerClass( i ), | ||
| 170 | attr.innerName( i ) | ||
| 171 | ) ); | ||
| 172 | */ | ||
| 173 | } | ||
| 149 | } | 174 | } |
| 150 | } | 175 | } |
| 151 | 176 | ||
| 152 | private Set<String> getAllClassNames( CtClass c ) | 177 | private Set<ClassEntry> getAllClassEntries( CtClass c ) |
| 153 | { | 178 | { |
| 154 | final Set<String> names = new HashSet<String>(); | 179 | final Set<ClassEntry> entries = Sets.newHashSet(); |
| 155 | ClassMap map = new ClassMap( ) | 180 | ClassMap map = new ClassMap( ) |
| 156 | { | 181 | { |
| 157 | @Override | 182 | @Override |
| @@ -159,13 +184,13 @@ public class ClassTranslator | |||
| 159 | { | 184 | { |
| 160 | if( obj instanceof String ) | 185 | if( obj instanceof String ) |
| 161 | { | 186 | { |
| 162 | names.add( (String)obj ); | 187 | entries.add( new ClassEntry( (String)obj ) ); |
| 163 | } | 188 | } |
| 164 | return null; | 189 | return null; |
| 165 | } | 190 | } |
| 166 | private static final long serialVersionUID = -202160293602070641L; | 191 | private static final long serialVersionUID = -202160293602070641L; |
| 167 | }; | 192 | }; |
| 168 | c.replaceClassName( map ); | 193 | c.replaceClassName( map ); |
| 169 | return names; | 194 | return entries; |
| 170 | } | 195 | } |
| 171 | } | 196 | } |
diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java index b0e33ac..c412b1a 100644 --- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java +++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java | |||
| @@ -18,16 +18,14 @@ import javassist.bytecode.ConstPool; | |||
| 18 | import javassist.bytecode.Descriptor; | 18 | import javassist.bytecode.Descriptor; |
| 19 | import javassist.bytecode.InnerClassesAttribute; | 19 | import javassist.bytecode.InnerClassesAttribute; |
| 20 | import cuchaz.enigma.analysis.JarIndex; | 20 | import cuchaz.enigma.analysis.JarIndex; |
| 21 | import cuchaz.enigma.mapping.Translator; | 21 | import cuchaz.enigma.mapping.ClassEntry; |
| 22 | 22 | ||
| 23 | public class InnerClassWriter | 23 | public class InnerClassWriter |
| 24 | { | 24 | { |
| 25 | private Translator m_deobfuscatingTranslator; | ||
| 26 | private JarIndex m_jarIndex; | 25 | private JarIndex m_jarIndex; |
| 27 | 26 | ||
| 28 | public InnerClassWriter( Translator deobfuscatingTranslator, JarIndex jarIndex ) | 27 | public InnerClassWriter( JarIndex jarIndex ) |
| 29 | { | 28 | { |
| 30 | m_deobfuscatingTranslator = deobfuscatingTranslator; | ||
| 31 | m_jarIndex = jarIndex; | 29 | m_jarIndex = jarIndex; |
| 32 | } | 30 | } |
| 33 | 31 | ||
| @@ -44,7 +42,8 @@ public class InnerClassWriter | |||
| 44 | else | 42 | else |
| 45 | { | 43 | { |
| 46 | // this is an inner class, rename it to outer$inner | 44 | // this is an inner class, rename it to outer$inner |
| 47 | c.setName( obfOuterClassName + "$" + obfClassName ); | 45 | ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + obfClassName ); |
| 46 | c.setName( obfClassEntry.getName() ); | ||
| 48 | } | 47 | } |
| 49 | 48 | ||
| 50 | // write the inner classes if needed | 49 | // write the inner classes if needed |
| @@ -62,31 +61,20 @@ public class InnerClassWriter | |||
| 62 | for( String obfInnerClassName : obfInnerClassNames ) | 61 | for( String obfInnerClassName : obfInnerClassNames ) |
| 63 | { | 62 | { |
| 64 | // deobfuscate the class names | 63 | // deobfuscate the class names |
| 65 | String deobfOuterClassName = m_deobfuscatingTranslator.translateClass( obfOuterClassName ); | 64 | ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + obfInnerClassName ); |
| 66 | if( deobfOuterClassName == null ) | 65 | |
| 67 | { | ||
| 68 | deobfOuterClassName = obfOuterClassName; | ||
| 69 | } | ||
| 70 | String obfOuterInnerClassName = obfOuterClassName + "$" + obfInnerClassName; | ||
| 71 | String deobfOuterInnerClassName = m_deobfuscatingTranslator.translateClass( obfOuterInnerClassName ); | ||
| 72 | if( deobfOuterInnerClassName == null ) | ||
| 73 | { | ||
| 74 | deobfOuterInnerClassName = obfOuterInnerClassName; | ||
| 75 | } | ||
| 76 | String deobfInnerClassName = deobfOuterInnerClassName.substring( deobfOuterInnerClassName.lastIndexOf( '$' ) + 1 ); | ||
| 77 | |||
| 78 | // here's what the JVM spec says about the InnerClasses attribute | 66 | // here's what the JVM spec says about the InnerClasses attribute |
| 79 | // append( inner, outer of inner if inner is member of outer 0 ow, name after $ if inner not anonymous 0 ow, flags ); | 67 | // append( inner, outer of inner if inner is member of outer 0 ow, name after $ if inner not anonymous 0 ow, flags ); |
| 80 | 68 | ||
| 81 | // update the attribute with this inner class | 69 | // update the attribute with this inner class |
| 82 | ConstPool constPool = c.getClassFile().getConstPool(); | 70 | ConstPool constPool = c.getClassFile().getConstPool(); |
| 83 | int innerClassIndex = constPool.addClassInfo( deobfOuterInnerClassName ); | 71 | int innerClassIndex = constPool.addClassInfo( obfClassEntry.getName() ); |
| 84 | int outerClassIndex = 0; | 72 | int outerClassIndex = 0; |
| 85 | int innerClassSimpleNameIndex = 0; | 73 | int innerClassSimpleNameIndex = 0; |
| 86 | if( !m_jarIndex.isAnonymousClass( obfInnerClassName ) ) | 74 | if( !m_jarIndex.isAnonymousClass( obfInnerClassName ) ) |
| 87 | { | 75 | { |
| 88 | outerClassIndex = constPool.addClassInfo( deobfOuterClassName ); | 76 | outerClassIndex = constPool.addClassInfo( obfClassEntry.getOuterClassName() ); |
| 89 | innerClassSimpleNameIndex = constPool.addUtf8Info( deobfInnerClassName ); | 77 | innerClassSimpleNameIndex = constPool.addUtf8Info( obfClassEntry.getInnerClassName() ); |
| 90 | } | 78 | } |
| 91 | 79 | ||
| 92 | attr.append( | 80 | attr.append( |
| @@ -96,8 +84,18 @@ public class InnerClassWriter | |||
| 96 | c.getClassFile().getAccessFlags() & ~AccessFlag.SUPER | 84 | c.getClassFile().getAccessFlags() & ~AccessFlag.SUPER |
| 97 | ); | 85 | ); |
| 98 | 86 | ||
| 87 | /* DEBUG | ||
| 88 | System.out.println( String.format( "\tOBF: %s -> ATTR: %s,%s,%s (replace %s with %s)", | ||
| 89 | obfClassEntry, | ||
| 90 | attr.outerClass( attr.tableLength() - 1 ), | ||
| 91 | attr.innerClass( attr.tableLength() - 1 ), | ||
| 92 | attr.innerName( attr.tableLength() - 1 ), | ||
| 93 | obfInnerClassName, obfClassEntry.getName() | ||
| 94 | ) ); | ||
| 95 | */ | ||
| 96 | |||
| 99 | // make sure the outer class references only the new inner class names | 97 | // make sure the outer class references only the new inner class names |
| 100 | c.replaceClassName( obfInnerClassName, deobfOuterInnerClassName ); | 98 | c.replaceClassName( obfInnerClassName, obfClassEntry.getName() ); |
| 101 | } | 99 | } |
| 102 | } | 100 | } |
| 103 | } | 101 | } |