diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cuchaz/enigma/Deobfuscator.java | 102 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/EntryRenamer.java | 4 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/JarIndex.java | 14 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/ClassMapping.java | 22 |
4 files changed, 117 insertions, 25 deletions
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 9c845325..03c35113 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java | |||
| @@ -22,6 +22,7 @@ import java.util.jar.JarFile; | |||
| 22 | 22 | ||
| 23 | import javassist.bytecode.Descriptor; | 23 | import javassist.bytecode.Descriptor; |
| 24 | 24 | ||
| 25 | import com.google.common.collect.Lists; | ||
| 25 | import com.google.common.collect.Maps; | 26 | import com.google.common.collect.Maps; |
| 26 | import com.google.common.collect.Sets; | 27 | import com.google.common.collect.Sets; |
| 27 | import com.strobel.assembler.metadata.MetadataSystem; | 28 | import com.strobel.assembler.metadata.MetadataSystem; |
| @@ -44,6 +45,7 @@ import cuchaz.enigma.mapping.ClassMapping; | |||
| 44 | import cuchaz.enigma.mapping.ConstructorEntry; | 45 | import cuchaz.enigma.mapping.ConstructorEntry; |
| 45 | import cuchaz.enigma.mapping.Entry; | 46 | import cuchaz.enigma.mapping.Entry; |
| 46 | import cuchaz.enigma.mapping.FieldEntry; | 47 | import cuchaz.enigma.mapping.FieldEntry; |
| 48 | import cuchaz.enigma.mapping.FieldMapping; | ||
| 47 | import cuchaz.enigma.mapping.Mappings; | 49 | import cuchaz.enigma.mapping.Mappings; |
| 48 | import cuchaz.enigma.mapping.MappingsRenamer; | 50 | import cuchaz.enigma.mapping.MappingsRenamer; |
| 49 | import cuchaz.enigma.mapping.MethodEntry; | 51 | import cuchaz.enigma.mapping.MethodEntry; |
| @@ -113,41 +115,107 @@ public class Deobfuscator | |||
| 113 | val = new Mappings(); | 115 | val = new Mappings(); |
| 114 | } | 116 | } |
| 115 | 117 | ||
| 116 | // make sure all the mappings match the classes in the jar | 118 | // look for any classes that got moved to inner classes |
| 119 | Map<String,String> renames = Maps.newHashMap(); | ||
| 117 | for( ClassMapping classMapping : val.classes() ) | 120 | for( ClassMapping classMapping : val.classes() ) |
| 118 | { | 121 | { |
| 119 | ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); | 122 | String outerClassName = m_jarIndex.getOuterClass( classMapping.getObfName() ); |
| 120 | if( !m_jarIndex.getObfClassEntries().contains( classEntry ) ) | 123 | if( outerClassName != null ) |
| 121 | { | 124 | { |
| 122 | throw new Error( "Class " + classEntry + " not found in Jar!" ); | 125 | // build the composite class name |
| 126 | String newName = outerClassName + "$" + new ClassEntry( classMapping.getObfName() ).getSimpleName(); | ||
| 127 | |||
| 128 | // add a rename | ||
| 129 | renames.put( classMapping.getObfName(), newName ); | ||
| 130 | |||
| 131 | System.out.println( String.format( "Converted class mapping %s to %s", classMapping.getObfName(), newName ) ); | ||
| 123 | } | 132 | } |
| 124 | 133 | } | |
| 125 | // and method implementations | 134 | for( Map.Entry<String,String> entry : renames.entrySet() ) |
| 126 | for( MethodMapping methodMapping : classMapping.methods() ) | 135 | { |
| 136 | val.renameObfClass( entry.getKey(), entry.getValue() ); | ||
| 137 | } | ||
| 138 | |||
| 139 | // drop mappings that don't match the jar | ||
| 140 | List<ClassEntry> unknownClasses = Lists.newArrayList(); | ||
| 141 | for( ClassMapping classMapping : val.classes() ) | ||
| 142 | { | ||
| 143 | checkClassMapping( unknownClasses, classMapping ); | ||
| 144 | } | ||
| 145 | if( !unknownClasses.isEmpty() ) | ||
| 146 | { | ||
| 147 | throw new Error( "Unable to find classes in jar: " + unknownClasses ); | ||
| 148 | } | ||
| 149 | |||
| 150 | m_mappings = val; | ||
| 151 | m_renamer = new MappingsRenamer( m_jarIndex, m_mappings ); | ||
| 152 | m_translatorCache.clear(); | ||
| 153 | } | ||
| 154 | |||
| 155 | private void checkClassMapping( List<ClassEntry> unknownClasses, ClassMapping classMapping ) | ||
| 156 | { | ||
| 157 | // check the class | ||
| 158 | ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); | ||
| 159 | String outerClassName = m_jarIndex.getOuterClass( classMapping.getObfName() ); | ||
| 160 | if( outerClassName != null ) | ||
| 161 | { | ||
| 162 | classEntry = new ClassEntry( outerClassName + "$" + classEntry.getSimpleName() ); | ||
| 163 | } | ||
| 164 | if( !m_jarIndex.getObfClassEntries().contains( classEntry ) ) | ||
| 165 | { | ||
| 166 | unknownClasses.add( classEntry ); | ||
| 167 | } | ||
| 168 | |||
| 169 | // check the fields | ||
| 170 | for( FieldMapping fieldMapping : Lists.newArrayList( classMapping.fields() ) ) | ||
| 171 | { | ||
| 172 | FieldEntry fieldEntry = new FieldEntry( classEntry, fieldMapping.getObfName() ); | ||
| 173 | if( m_jarIndex.getAccess( fieldEntry ) == null ) | ||
| 174 | { | ||
| 175 | System.err.println( "WARNING: unable to find field " + fieldEntry + ". dropping mapping." ); | ||
| 176 | classMapping.removeFieldMapping( fieldMapping ); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | // check methods | ||
| 181 | for( MethodMapping methodMapping : Lists.newArrayList( classMapping.methods() ) ) | ||
| 182 | { | ||
| 183 | if( methodMapping.getObfName().equals( "<clinit>" ) ) | ||
| 184 | { | ||
| 185 | // skip static initializers | ||
| 186 | continue; | ||
| 187 | } | ||
| 188 | else if( methodMapping.getObfName().equals( "<init>" ) ) | ||
| 127 | { | 189 | { |
| 128 | if( methodMapping.getObfName().startsWith( "<" ) ) | 190 | ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, methodMapping.getObfSignature() ); |
| 191 | if( m_jarIndex.getAccess( constructorEntry ) == null ) | ||
| 129 | { | 192 | { |
| 130 | // skip constructors and static initializers | 193 | System.err.println( "WARNING: unable to find constructor " + constructorEntry + ". dropping mapping." ); |
| 131 | continue; | 194 | classMapping.removeMethodMapping( methodMapping ); |
| 132 | } | 195 | } |
| 133 | 196 | } | |
| 197 | else | ||
| 198 | { | ||
| 134 | MethodEntry methodEntry = new MethodEntry( | 199 | MethodEntry methodEntry = new MethodEntry( |
| 135 | classEntry, | 200 | classEntry, |
| 136 | methodMapping.getObfName(), | 201 | methodMapping.getObfName(), |
| 137 | methodMapping.getObfSignature() | 202 | methodMapping.getObfSignature() |
| 138 | ); | 203 | ); |
| 139 | if( !m_jarIndex.isMethodImplemented( methodEntry ) ) | 204 | if( m_jarIndex.getAccess( methodEntry ) == null ) |
| 140 | { | 205 | { |
| 141 | throw new Error( "Method " + methodEntry + " not found in Jar!" ); | 206 | System.err.println( "WARNING: unable to find method " + methodEntry + ". dropping mapping." ); |
| 207 | classMapping.removeMethodMapping( methodMapping ); | ||
| 142 | } | 208 | } |
| 143 | } | 209 | } |
| 144 | } | 210 | } |
| 145 | 211 | ||
| 146 | m_mappings = val; | 212 | // check inner classes |
| 147 | m_renamer = new MappingsRenamer( m_jarIndex, m_mappings ); | 213 | for( ClassMapping innerClassMapping : classMapping.innerClasses() ) |
| 148 | m_translatorCache.clear(); | 214 | { |
| 215 | checkClassMapping( unknownClasses, innerClassMapping ); | ||
| 216 | } | ||
| 149 | } | 217 | } |
| 150 | 218 | ||
| 151 | public Translator getTranslator( TranslationDirection direction ) | 219 | public Translator getTranslator( TranslationDirection direction ) |
| 152 | { | 220 | { |
| 153 | Translator translator = m_translatorCache.get( direction ); | 221 | Translator translator = m_translatorCache.get( direction ); |
diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java index e9483caa..b82b2547 100644 --- a/src/cuchaz/enigma/analysis/EntryRenamer.java +++ b/src/cuchaz/enigma/analysis/EntryRenamer.java | |||
| @@ -189,10 +189,6 @@ public class EntryRenamer | |||
| 189 | reference.context = renameClassesInThing( renames, reference.context ); | 189 | reference.context = renameClassesInThing( renames, reference.context ); |
| 190 | return thing; | 190 | return thing; |
| 191 | } | 191 | } |
| 192 | else | ||
| 193 | { | ||
| 194 | throw new Error( "Not an entry: " + thing ); | ||
| 195 | } | ||
| 196 | 192 | ||
| 197 | return thing; | 193 | return thing; |
| 198 | } | 194 | } |
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 8ebce35e..b51428a2 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java | |||
| @@ -95,7 +95,7 @@ public class JarIndex | |||
| 95 | m_obfClassEntries.add( classEntry ); | 95 | m_obfClassEntries.add( classEntry ); |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | // step 2: index method/field access | 98 | // step 2: index field/method/constructor access |
| 99 | for( CtClass c : JarClassIterator.classes( jar ) ) | 99 | for( CtClass c : JarClassIterator.classes( jar ) ) |
| 100 | { | 100 | { |
| 101 | ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); | 101 | ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); |
| @@ -105,10 +105,15 @@ public class JarIndex | |||
| 105 | FieldEntry fieldEntry = new FieldEntry( classEntry, field.getName() ); | 105 | FieldEntry fieldEntry = new FieldEntry( classEntry, field.getName() ); |
| 106 | m_access.put( fieldEntry, Access.get( field ) ); | 106 | m_access.put( fieldEntry, Access.get( field ) ); |
| 107 | } | 107 | } |
| 108 | for( CtBehavior behavior : c.getDeclaredBehaviors() ) | 108 | for( CtMethod method : c.getDeclaredMethods() ) |
| 109 | { | ||
| 110 | MethodEntry methodEntry = new MethodEntry( classEntry, method.getName(), method.getSignature() ); | ||
| 111 | m_access.put( methodEntry, Access.get( method ) ); | ||
| 112 | } | ||
| 113 | for( CtConstructor constructor : c.getDeclaredConstructors() ) | ||
| 109 | { | 114 | { |
| 110 | MethodEntry methodEntry = new MethodEntry( classEntry, behavior.getName(), behavior.getSignature() ); | 115 | ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getSignature() ); |
| 111 | m_access.put( methodEntry, Access.get( behavior ) ); | 116 | m_access.put( constructorEntry, Access.get( constructor ) ); |
| 112 | } | 117 | } |
| 113 | } | 118 | } |
| 114 | 119 | ||
| @@ -190,6 +195,7 @@ public class JarIndex | |||
| 190 | EntryRenamer.renameClassesInMultimap( renames, m_behaviorReferences ); | 195 | EntryRenamer.renameClassesInMultimap( renames, m_behaviorReferences ); |
| 191 | EntryRenamer.renameClassesInMultimap( renames, m_fieldReferences ); | 196 | EntryRenamer.renameClassesInMultimap( renames, m_fieldReferences ); |
| 192 | EntryRenamer.renameClassesInMap( renames, m_bridgeMethods ); | 197 | EntryRenamer.renameClassesInMap( renames, m_bridgeMethods ); |
| 198 | EntryRenamer.renameClassesInMap( renames, m_access ); | ||
| 193 | } | 199 | } |
| 194 | 200 | ||
| 195 | // step 6: update other indices with bridge method info | 201 | // step 6: update other indices with bridge method info |
diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index 200d9ca2..88006cff 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java | |||
| @@ -155,6 +155,17 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping> | |||
| 155 | assert( deobfWasAdded ); | 155 | assert( deobfWasAdded ); |
| 156 | assert( m_fieldsByObf.size() == m_fieldsByDeobf.size() ); | 156 | assert( m_fieldsByObf.size() == m_fieldsByDeobf.size() ); |
| 157 | } | 157 | } |
| 158 | |||
| 159 | public void removeFieldMapping( FieldMapping fieldMapping ) | ||
| 160 | { | ||
| 161 | boolean obfWasRemoved = m_fieldsByObf.remove( fieldMapping.getObfName() ) != null; | ||
| 162 | assert( obfWasRemoved ); | ||
| 163 | if( fieldMapping.getDeobfName() != null ) | ||
| 164 | { | ||
| 165 | boolean deobfWasRemoved = m_fieldsByDeobf.remove( fieldMapping.getDeobfName() ) != null; | ||
| 166 | assert( deobfWasRemoved ); | ||
| 167 | } | ||
| 168 | } | ||
| 158 | 169 | ||
| 159 | public String getObfFieldName( String deobfName ) | 170 | public String getObfFieldName( String deobfName ) |
| 160 | { | 171 | { |
| @@ -225,6 +236,17 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping> | |||
| 225 | assert( m_methodsByObf.size() >= m_methodsByDeobf.size() ); | 236 | assert( m_methodsByObf.size() >= m_methodsByDeobf.size() ); |
| 226 | } | 237 | } |
| 227 | 238 | ||
| 239 | public void removeMethodMapping( MethodMapping methodMapping ) | ||
| 240 | { | ||
| 241 | boolean obfWasRemoved = m_methodsByObf.remove( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ) ) != null; | ||
| 242 | assert( obfWasRemoved ); | ||
| 243 | if( methodMapping.getDeobfName() != null ) | ||
| 244 | { | ||
| 245 | boolean deobfWasRemoved = m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getObfSignature() ) ) != null; | ||
| 246 | assert( deobfWasRemoved ); | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 228 | public MethodMapping getMethodByObf( String obfName, String signature ) | 250 | public MethodMapping getMethodByObf( String obfName, String signature ) |
| 229 | { | 251 | { |
| 230 | return m_methodsByObf.get( getMethodKey( obfName, signature ) ); | 252 | return m_methodsByObf.get( getMethodKey( obfName, signature ) ); |