summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/Deobfuscator.java
diff options
context:
space:
mode:
authorGravatar jeff2015-01-13 23:25:04 -0500
committerGravatar jeff2015-01-13 23:25:04 -0500
commit959cb5fd4f9586ec3bd265b452fe25fe1db82e3f (patch)
treebdd8a2c52c2fe053ba3460614bde8542e5378dbe /src/cuchaz/enigma/Deobfuscator.java
parentgot rid of gradle in favor of ivy+ssjb (diff)
downloadenigma-fork-959cb5fd4f9586ec3bd265b452fe25fe1db82e3f.tar.gz
enigma-fork-959cb5fd4f9586ec3bd265b452fe25fe1db82e3f.tar.xz
enigma-fork-959cb5fd4f9586ec3bd265b452fe25fe1db82e3f.zip
source format change
don't hate me too much if you were planning a big merge. =P
Diffstat (limited to 'src/cuchaz/enigma/Deobfuscator.java')
-rw-r--r--src/cuchaz/enigma/Deobfuscator.java595
1 files changed, 234 insertions, 361 deletions
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index 82c786c..679518a 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -61,12 +61,11 @@ import cuchaz.enigma.mapping.MethodMapping;
61import cuchaz.enigma.mapping.TranslationDirection; 61import cuchaz.enigma.mapping.TranslationDirection;
62import cuchaz.enigma.mapping.Translator; 62import cuchaz.enigma.mapping.Translator;
63 63
64public class Deobfuscator 64public class Deobfuscator {
65{ 65
66 public interface ProgressListener 66 public interface ProgressListener {
67 { 67 void init(int totalWork, String title);
68 void init( int totalWork, String title ); 68 void onProgress(int numDone, String message);
69 void onProgress( int numDone, String message );
70 } 69 }
71 70
72 private File m_file; 71 private File m_file;
@@ -77,121 +76,104 @@ public class Deobfuscator
77 private MappingsRenamer m_renamer; 76 private MappingsRenamer m_renamer;
78 private Map<TranslationDirection,Translator> m_translatorCache; 77 private Map<TranslationDirection,Translator> m_translatorCache;
79 78
80 public Deobfuscator( File file ) 79 public Deobfuscator(File file) throws IOException {
81 throws IOException
82 {
83 m_file = file; 80 m_file = file;
84 m_jar = new JarFile( m_file ); 81 m_jar = new JarFile(m_file);
85 82
86 // build the jar index 83 // build the jar index
87 m_jarIndex = new JarIndex(); 84 m_jarIndex = new JarIndex();
88 m_jarIndex.indexJar( m_jar, true ); 85 m_jarIndex.indexJar(m_jar, true);
89 86
90 // config the decompiler 87 // config the decompiler
91 m_settings = DecompilerSettings.javaDefaults(); 88 m_settings = DecompilerSettings.javaDefaults();
92 m_settings.setMergeVariables( true ); 89 m_settings.setMergeVariables(true);
93 m_settings.setForceExplicitImports( true ); 90 m_settings.setForceExplicitImports(true);
94 m_settings.setForceExplicitTypeArguments( true ); 91 m_settings.setForceExplicitTypeArguments(true);
95 // DEBUG 92 // DEBUG
96 //m_settings.setShowSyntheticMembers( true ); 93 // m_settings.setShowSyntheticMembers( true );
97 94
98 // init defaults 95 // init defaults
99 m_translatorCache = Maps.newTreeMap(); 96 m_translatorCache = Maps.newTreeMap();
100 97
101 // init mappings 98 // init mappings
102 setMappings( new Mappings() ); 99 setMappings(new Mappings());
103 } 100 }
104 101
105 public String getJarName( ) 102 public String getJarName() {
106 {
107 return m_file.getName(); 103 return m_file.getName();
108 } 104 }
109 105
110 public JarIndex getJarIndex( ) 106 public JarIndex getJarIndex() {
111 {
112 return m_jarIndex; 107 return m_jarIndex;
113 } 108 }
114 109
115 public Mappings getMappings( ) 110 public Mappings getMappings() {
116 {
117 return m_mappings; 111 return m_mappings;
118 } 112 }
119 public void setMappings( Mappings val ) 113
120 { 114 public void setMappings(Mappings val) {
121 if( val == null ) 115 if (val == null) {
122 {
123 val = new Mappings(); 116 val = new Mappings();
124 } 117 }
125 118
126 // pass 1: look for any classes that got moved to inner classes 119 // pass 1: look for any classes that got moved to inner classes
127 Map<String,String> renames = Maps.newHashMap(); 120 Map<String,String> renames = Maps.newHashMap();
128 for( ClassMapping classMapping : val.classes() ) 121 for (ClassMapping classMapping : val.classes()) {
129 {
130 // make sure we strip the packages off of obfuscated inner classes 122 // make sure we strip the packages off of obfuscated inner classes
131 String innerClassName = new ClassEntry( classMapping.getObfName() ).getSimpleName(); 123 String innerClassName = new ClassEntry(classMapping.getObfName()).getSimpleName();
132 String outerClassName = m_jarIndex.getOuterClass( innerClassName ); 124 String outerClassName = m_jarIndex.getOuterClass(innerClassName);
133 if( outerClassName != null ) 125 if (outerClassName != null) {
134 {
135 // build the composite class name 126 // build the composite class name
136 String newName = outerClassName + "$" + innerClassName; 127 String newName = outerClassName + "$" + innerClassName;
137 128
138 // add a rename 129 // add a rename
139 renames.put( classMapping.getObfName(), newName ); 130 renames.put(classMapping.getObfName(), newName);
140 131
141 System.out.println( String.format( "Converted class mapping %s to %s", classMapping.getObfName(), newName ) ); 132 System.out.println(String.format("Converted class mapping %s to %s", classMapping.getObfName(), newName));
142 } 133 }
143 } 134 }
144 for( Map.Entry<String,String> entry : renames.entrySet() ) 135 for (Map.Entry<String,String> entry : renames.entrySet()) {
145 { 136 val.renameObfClass(entry.getKey(), entry.getValue());
146 val.renameObfClass( entry.getKey(), entry.getValue() );
147 } 137 }
148 138
149 // pass 2: look for fields/methods that are actually declared in superclasses 139 // pass 2: look for fields/methods that are actually declared in superclasses
150 MappingsRenamer renamer = new MappingsRenamer( m_jarIndex, val ); 140 MappingsRenamer renamer = new MappingsRenamer(m_jarIndex, val);
151 for( ClassMapping classMapping : val.classes() ) 141 for (ClassMapping classMapping : val.classes()) {
152 { 142 ClassEntry obfClassEntry = new ClassEntry(classMapping.getObfName());
153 ClassEntry obfClassEntry = new ClassEntry( classMapping.getObfName() );
154 143
155 // fields 144 // fields
156 for( FieldMapping fieldMapping : Lists.newArrayList( classMapping.fields() ) ) 145 for (FieldMapping fieldMapping : Lists.newArrayList(classMapping.fields())) {
157 { 146 FieldEntry fieldEntry = new FieldEntry(obfClassEntry, fieldMapping.getObfName());
158 FieldEntry fieldEntry = new FieldEntry( obfClassEntry, fieldMapping.getObfName() ); 147 ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(fieldEntry);
159 ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( fieldEntry ); 148 if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(fieldEntry.getClassEntry())) {
160 if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( fieldEntry.getClassEntry() ) ) 149 boolean wasMoved = renamer.moveFieldToObfClass(classMapping, fieldMapping, resolvedObfClassEntry);
161 { 150 if (wasMoved) {
162 boolean wasMoved = renamer.moveFieldToObfClass( classMapping, fieldMapping, resolvedObfClassEntry ); 151 System.out.println(String.format("Moved field %s to class %s", fieldEntry, resolvedObfClassEntry));
163 if( wasMoved ) 152 } else {
164 { 153 System.err.println(String.format("WARNING: Would move field %s to class %s but the field was already there. Dropping instead.", fieldEntry, resolvedObfClassEntry));
165 System.out.println( String.format( "Moved field %s to class %s", fieldEntry, resolvedObfClassEntry ) );
166 }
167 else
168 {
169 System.err.println( String.format( "WARNING: Would move field %s to class %s but the field was already there. Dropping instead.", fieldEntry, resolvedObfClassEntry ) );
170 } 154 }
171 } 155 }
172 } 156 }
173 157
174 // methods 158 // methods
175 for( MethodMapping methodMapping : Lists.newArrayList( classMapping.methods() ) ) 159 for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) {
176 {
177 // skip constructors 160 // skip constructors
178 if( methodMapping.isConstructor() ) 161 if (methodMapping.isConstructor()) {
179 {
180 continue; 162 continue;
181 } 163 }
182 164
183 MethodEntry methodEntry = new MethodEntry( obfClassEntry, methodMapping.getObfName(), methodMapping.getObfSignature() ); 165 MethodEntry methodEntry = new MethodEntry(
184 ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( methodEntry ); 166 obfClassEntry,
185 if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( methodEntry.getClassEntry() ) ) 167 methodMapping.getObfName(),
186 { 168 methodMapping.getObfSignature()
187 boolean wasMoved = renamer.moveMethodToObfClass( classMapping, methodMapping, resolvedObfClassEntry ); 169 );
188 if( wasMoved ) 170 ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(methodEntry);
189 { 171 if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(methodEntry.getClassEntry())) {
190 System.out.println( String.format( "Moved method %s to class %s", methodEntry, resolvedObfClassEntry ) ); 172 boolean wasMoved = renamer.moveMethodToObfClass(classMapping, methodMapping, resolvedObfClassEntry);
191 } 173 if (wasMoved) {
192 else 174 System.out.println(String.format("Moved method %s to class %s", methodEntry, resolvedObfClassEntry));
193 { 175 } else {
194 System.err.println( String.format( "WARNING: Would move method %s to class %s but the method was already there. Dropping instead.", methodEntry, resolvedObfClassEntry ) ); 176 System.err.println(String.format("WARNING: Would move method %s to class %s but the method was already there. Dropping instead.", methodEntry, resolvedObfClassEntry));
195 } 177 }
196 } 178 }
197 } 179 }
@@ -201,13 +183,11 @@ public class Deobfuscator
201 183
202 // drop mappings that don't match the jar 184 // drop mappings that don't match the jar
203 List<ClassEntry> unknownClasses = Lists.newArrayList(); 185 List<ClassEntry> unknownClasses = Lists.newArrayList();
204 for( ClassMapping classMapping : val.classes() ) 186 for (ClassMapping classMapping : val.classes()) {
205 { 187 checkClassMapping(unknownClasses, classMapping);
206 checkClassMapping( unknownClasses, classMapping );
207 } 188 }
208 if( !unknownClasses.isEmpty() ) 189 if (!unknownClasses.isEmpty()) {
209 { 190 throw new Error("Unable to find classes in jar: " + unknownClasses);
210 throw new Error( "Unable to find classes in jar: " + unknownClasses );
211 } 191 }
212 192
213 m_mappings = val; 193 m_mappings = val;
@@ -215,453 +195,346 @@ public class Deobfuscator
215 m_translatorCache.clear(); 195 m_translatorCache.clear();
216 } 196 }
217 197
218 private void checkClassMapping( List<ClassEntry> unknownClasses, ClassMapping classMapping ) 198 private void checkClassMapping(List<ClassEntry> unknownClasses, ClassMapping classMapping) {
219 {
220 // check the class 199 // check the class
221 ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); 200 ClassEntry classEntry = new ClassEntry(classMapping.getObfName());
222 String outerClassName = m_jarIndex.getOuterClass( classEntry.getSimpleName() ); 201 String outerClassName = m_jarIndex.getOuterClass(classEntry.getSimpleName());
223 if( outerClassName != null ) 202 if (outerClassName != null) {
224 { 203 classEntry = new ClassEntry(outerClassName + "$" + classMapping.getObfName());
225 classEntry = new ClassEntry( outerClassName + "$" + classMapping.getObfName() );
226 } 204 }
227 if( !m_jarIndex.getObfClassEntries().contains( classEntry ) ) 205 if (!m_jarIndex.getObfClassEntries().contains(classEntry)) {
228 { 206 unknownClasses.add(classEntry);
229 unknownClasses.add( classEntry );
230 } 207 }
231 208
232 // check the fields 209 // check the fields
233 for( FieldMapping fieldMapping : Lists.newArrayList( classMapping.fields() ) ) 210 for (FieldMapping fieldMapping : Lists.newArrayList(classMapping.fields())) {
234 { 211 FieldEntry fieldEntry = new FieldEntry(classEntry, fieldMapping.getObfName());
235 FieldEntry fieldEntry = new FieldEntry( classEntry, fieldMapping.getObfName() ); 212 if (!m_jarIndex.containsObfField(fieldEntry)) {
236 if( !m_jarIndex.containsObfField( fieldEntry ) ) 213 System.err.println("WARNING: unable to find field " + fieldEntry + ". dropping mapping.");
237 { 214 classMapping.removeFieldMapping(fieldMapping);
238 System.err.println( "WARNING: unable to find field " + fieldEntry + ". dropping mapping." );
239 classMapping.removeFieldMapping( fieldMapping );
240 } 215 }
241 } 216 }
242 217
243 // check methods 218 // check methods
244 for( MethodMapping methodMapping : Lists.newArrayList( classMapping.methods() ) ) 219 for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) {
245 { 220 BehaviorEntry obfBehaviorEntry = BehaviorEntryFactory.createObf(classEntry, methodMapping);
246 BehaviorEntry obfBehaviorEntry = BehaviorEntryFactory.createObf( classEntry, methodMapping ); 221 if (!m_jarIndex.containsObfBehavior(obfBehaviorEntry)) {
247 if( !m_jarIndex.containsObfBehavior( obfBehaviorEntry ) ) 222 System.err.println("WARNING: unable to find behavior " + obfBehaviorEntry + ". dropping mapping.");
248 { 223 classMapping.removeMethodMapping(methodMapping);
249 System.err.println( "WARNING: unable to find behavior " + obfBehaviorEntry + ". dropping mapping." ); 224 }
250 classMapping.removeMethodMapping( methodMapping );
251 }
252 } 225 }
253 226
254 // check inner classes 227 // check inner classes
255 for( ClassMapping innerClassMapping : classMapping.innerClasses() ) 228 for (ClassMapping innerClassMapping : classMapping.innerClasses()) {
256 { 229 checkClassMapping(unknownClasses, innerClassMapping);
257 checkClassMapping( unknownClasses, innerClassMapping );
258 } 230 }
259 } 231 }
260 232
261 public Translator getTranslator( TranslationDirection direction ) 233 public Translator getTranslator(TranslationDirection direction) {
262 { 234 Translator translator = m_translatorCache.get(direction);
263 Translator translator = m_translatorCache.get( direction ); 235 if (translator == null) {
264 if( translator == null ) 236 translator = m_mappings.getTranslator(direction);
265 { 237 m_translatorCache.put(direction, translator);
266 translator = m_mappings.getTranslator( direction );
267 m_translatorCache.put( direction, translator );
268 } 238 }
269 return translator; 239 return translator;
270 } 240 }
271 241
272 public void getSeparatedClasses( List<ClassEntry> obfClasses, List<ClassEntry> deobfClasses ) 242 public void getSeparatedClasses(List<ClassEntry> obfClasses, List<ClassEntry> deobfClasses) {
273 { 243 for (ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries()) {
274 for( ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries() )
275 {
276 // skip inner classes 244 // skip inner classes
277 if( obfClassEntry.isInnerClass() ) 245 if (obfClassEntry.isInnerClass()) {
278 {
279 continue; 246 continue;
280 } 247 }
281 248
282 // separate the classes 249 // separate the classes
283 ClassEntry deobfClassEntry = deobfuscateEntry( obfClassEntry ); 250 ClassEntry deobfClassEntry = deobfuscateEntry(obfClassEntry);
284 if( !deobfClassEntry.equals( obfClassEntry ) ) 251 if (!deobfClassEntry.equals(obfClassEntry)) {
285 {
286 // if the class has a mapping, clearly it's deobfuscated 252 // if the class has a mapping, clearly it's deobfuscated
287 deobfClasses.add( deobfClassEntry ); 253 deobfClasses.add(deobfClassEntry);
288 } 254 } else if (!obfClassEntry.getPackageName().equals(Constants.NonePackage)) {
289 else if( !obfClassEntry.getPackageName().equals( Constants.NonePackage ) )
290 {
291 // also call it deobufscated if it's not in the none package 255 // also call it deobufscated if it's not in the none package
292 deobfClasses.add( obfClassEntry ); 256 deobfClasses.add(obfClassEntry);
293 } 257 } else {
294 else
295 {
296 // otherwise, assume it's still obfuscated 258 // otherwise, assume it's still obfuscated
297 obfClasses.add( obfClassEntry ); 259 obfClasses.add(obfClassEntry);
298 } 260 }
299 } 261 }
300 } 262 }
301 263
302 public CompilationUnit getSourceTree( String obfClassName ) 264 public CompilationUnit getSourceTree(String obfClassName) {
303 {
304 // is this class deobfuscated? 265 // is this class deobfuscated?
305 // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out 266 // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out
306 // the decompiler only sees the deobfuscated class, so we need to load it by the deobfuscated name 267 // the decompiler only sees the deobfuscated class, so we need to load it by the deobfuscated name
307 String lookupClassName = obfClassName; 268 String lookupClassName = obfClassName;
308 ClassMapping classMapping = m_mappings.getClassByObf( obfClassName ); 269 ClassMapping classMapping = m_mappings.getClassByObf(obfClassName);
309 if( classMapping != null && classMapping.getDeobfName() != null ) 270 if (classMapping != null && classMapping.getDeobfName() != null) {
310 {
311 lookupClassName = classMapping.getDeobfName(); 271 lookupClassName = classMapping.getDeobfName();
312 } 272 }
313 273
314 // is this class even in the jar? 274 // is this class even in the jar?
315 if( !m_jarIndex.containsObfClass( new ClassEntry( obfClassName ) ) ) 275 if (!m_jarIndex.containsObfClass(new ClassEntry(obfClassName))) {
316 {
317 return null; 276 return null;
318 } 277 }
319 278
320 // set the type loader 279 // set the type loader
321 m_settings.setTypeLoader( new TranslatingTypeLoader( 280 m_settings.setTypeLoader(new TranslatingTypeLoader(
322 m_jar, 281 m_jar,
323 m_jarIndex, 282 m_jarIndex,
324 getTranslator( TranslationDirection.Obfuscating ), 283 getTranslator(TranslationDirection.Obfuscating),
325 getTranslator( TranslationDirection.Deobfuscating ) 284 getTranslator(TranslationDirection.Deobfuscating)
326 ) ); 285 ));
327 286
328 // decompile it! 287 // decompile it!
329 TypeDefinition resolvedType = new MetadataSystem( m_settings.getTypeLoader() ).lookupType( lookupClassName ).resolve(); 288 TypeDefinition resolvedType = new MetadataSystem(m_settings.getTypeLoader()).lookupType(lookupClassName).resolve();
330 DecompilerContext context = new DecompilerContext(); 289 DecompilerContext context = new DecompilerContext();
331 context.setCurrentType( resolvedType ); 290 context.setCurrentType(resolvedType);
332 context.setSettings( m_settings ); 291 context.setSettings(m_settings);
333 AstBuilder builder = new AstBuilder( context ); 292 AstBuilder builder = new AstBuilder(context);
334 builder.addType( resolvedType ); 293 builder.addType(resolvedType);
335 builder.runTransformations( null ); 294 builder.runTransformations(null);
336 return builder.getCompilationUnit(); 295 return builder.getCompilationUnit();
337 } 296 }
338 297
339 public SourceIndex getSourceIndex( CompilationUnit sourceTree, String source ) 298 public SourceIndex getSourceIndex(CompilationUnit sourceTree, String source) {
340 {
341 // build the source index 299 // build the source index
342 SourceIndex index = new SourceIndex( source ); 300 SourceIndex index = new SourceIndex(source);
343 sourceTree.acceptVisitor( new SourceIndexVisitor(), index ); 301 sourceTree.acceptVisitor(new SourceIndexVisitor(), index);
344 302
345 // DEBUG 303 // DEBUG
346 //sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); 304 // sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null );
347 305
348 // resolve all the classes in the source references 306 // resolve all the classes in the source references
349 for( Token token : index.referenceTokens() ) 307 for (Token token : index.referenceTokens()) {
350 { 308 EntryReference<Entry,Entry> deobfReference = index.getDeobfReference(token);
351 EntryReference<Entry,Entry> deobfReference = index.getDeobfReference( token );
352 309
353 // get the obfuscated entry 310 // get the obfuscated entry
354 Entry obfEntry = obfuscateEntry( deobfReference.entry ); 311 Entry obfEntry = obfuscateEntry(deobfReference.entry);
355 312
356 // try to resolve the class 313 // try to resolve the class
357 ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( obfEntry ); 314 ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(obfEntry);
358 if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( obfEntry.getClassEntry() ) ) 315 if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(obfEntry.getClassEntry())) {
359 {
360 // change the class of the entry 316 // change the class of the entry
361 obfEntry = obfEntry.cloneToNewClass( resolvedObfClassEntry ); 317 obfEntry = obfEntry.cloneToNewClass(resolvedObfClassEntry);
362 318
363 // save the new deobfuscated reference 319 // save the new deobfuscated reference
364 deobfReference.entry = deobfuscateEntry( obfEntry ); 320 deobfReference.entry = deobfuscateEntry(obfEntry);
365 index.replaceDeobfReference( token, deobfReference ); 321 index.replaceDeobfReference(token, deobfReference);
366 } 322 }
367 323
368 // DEBUG 324 // DEBUG
369 //System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) ); 325 // System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) );
370 } 326 }
371 327
372 return index; 328 return index;
373 } 329 }
374 330
375 public String getSource( CompilationUnit sourceTree ) 331 public String getSource(CompilationUnit sourceTree) {
376 {
377 // render the AST into source 332 // render the AST into source
378 StringWriter buf = new StringWriter(); 333 StringWriter buf = new StringWriter();
379 sourceTree.acceptVisitor( new InsertParenthesesVisitor(), null ); 334 sourceTree.acceptVisitor(new InsertParenthesesVisitor(), null);
380 sourceTree.acceptVisitor( new JavaOutputVisitor( new PlainTextOutput( buf ), m_settings ), null ); 335 sourceTree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(buf), m_settings), null);
381 return buf.toString(); 336 return buf.toString();
382 } 337 }
383 338
384 public void writeSources( File dirOut, ProgressListener progress ) 339 public void writeSources(File dirOut, ProgressListener progress) throws IOException {
385 throws IOException
386 {
387 // get the classes to decompile 340 // get the classes to decompile
388 Set<ClassEntry> classEntries = Sets.newHashSet(); 341 Set<ClassEntry> classEntries = Sets.newHashSet();
389 for( ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries() ) 342 for (ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries()) {
390 {
391 // skip inner classes 343 // skip inner classes
392 if( obfClassEntry.isInnerClass() ) 344 if (obfClassEntry.isInnerClass()) {
393 {
394 continue; 345 continue;
395 } 346 }
396 347
397 classEntries.add( obfClassEntry ); 348 classEntries.add(obfClassEntry);
398 } 349 }
399 350
400 if( progress != null ) 351 if (progress != null) {
401 { 352 progress.init(classEntries.size(), "Decompiling classes...");
402 progress.init( classEntries.size(), "Decompiling classes..." );
403 } 353 }
404 354
405 // DEOBFUSCATE ALL THE THINGS!! @_@ 355 // DEOBFUSCATE ALL THE THINGS!! @_@
406 int i = 0; 356 int i = 0;
407 for( ClassEntry obfClassEntry : classEntries ) 357 for (ClassEntry obfClassEntry : classEntries) {
408 { 358 ClassEntry deobfClassEntry = deobfuscateEntry(new ClassEntry(obfClassEntry));
409 ClassEntry deobfClassEntry = deobfuscateEntry( new ClassEntry( obfClassEntry ) ); 359 if (progress != null) {
410 if( progress != null ) 360 progress.onProgress(i++, deobfClassEntry.toString());
411 {
412 progress.onProgress( i++, deobfClassEntry.toString() );
413 } 361 }
414 362
415 try 363 try {
416 {
417 // get the source 364 // get the source
418 String source = getSource( getSourceTree( obfClassEntry.getName() ) ); 365 String source = getSource(getSourceTree(obfClassEntry.getName()));
419 366
420 // write the file 367 // write the file
421 File file = new File( dirOut, deobfClassEntry.getName().replace( '.', '/' ) + ".java" ); 368 File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java");
422 file.getParentFile().mkdirs(); 369 file.getParentFile().mkdirs();
423 try( FileWriter out = new FileWriter( file ) ) 370 try (FileWriter out = new FileWriter(file)) {
424 { 371 out.write(source);
425 out.write( source );
426 } 372 }
427 } 373 } catch (Throwable t) {
428 catch( Throwable t ) 374 throw new Error("Unable to deobfuscate class " + deobfClassEntry.toString() + " (" + obfClassEntry.toString() + ")", t);
429 {
430 throw new Error( "Unable to deobfuscate class " + deobfClassEntry.toString() + " (" + obfClassEntry.toString() + ")", t );
431 } 375 }
432 } 376 }
433 if( progress != null ) 377 if (progress != null) {
434 { 378 progress.onProgress(i, "Done!");
435 progress.onProgress( i, "Done!" );
436 } 379 }
437 } 380 }
438 381
439 public void writeJar( File out, ProgressListener progress ) 382 public void writeJar(File out, ProgressListener progress) {
440 { 383 try (JarOutputStream outJar = new JarOutputStream(new FileOutputStream(out))) {
441 try( JarOutputStream outJar = new JarOutputStream( new FileOutputStream( out ) ) ) 384 if (progress != null) {
442 { 385 progress.init(JarClassIterator.getClassEntries(m_jar).size(), "Translating classes...");
443 if( progress != null )
444 {
445 progress.init( JarClassIterator.getClassEntries( m_jar ).size(), "Translating classes..." );
446 } 386 }
447 387
448 // prep the loader 388 // prep the loader
449 TranslatingTypeLoader loader = new TranslatingTypeLoader( 389 TranslatingTypeLoader loader = new TranslatingTypeLoader(
450 m_jar, 390 m_jar,
451 m_jarIndex, 391 m_jarIndex,
452 getTranslator( TranslationDirection.Obfuscating ), 392 getTranslator(TranslationDirection.Obfuscating),
453 getTranslator( TranslationDirection.Deobfuscating ) 393 getTranslator(TranslationDirection.Deobfuscating)
454 ); 394 );
455 395
456 int i = 0; 396 int i = 0;
457 for( CtClass c : JarClassIterator.classes( m_jar ) ) 397 for (CtClass c : JarClassIterator.classes(m_jar)) {
458 { 398 if (progress != null) {
459 if( progress != null ) 399 progress.onProgress(i++, c.getName());
460 {
461 progress.onProgress( i++, c.getName() );
462 } 400 }
463 401
464 try 402 try {
465 { 403 c = loader.transformClass(c);
466 c = loader.transformClass( c ); 404 outJar.putNextEntry(new JarEntry(c.getName().replace('.', '/') + ".class"));
467 outJar.putNextEntry( new JarEntry( c.getName().replace( '.', '/' ) + ".class" ) ); 405 outJar.write(c.toBytecode());
468 outJar.write( c.toBytecode() );
469 outJar.closeEntry(); 406 outJar.closeEntry();
470 } 407 } catch (Throwable t) {
471 catch( Throwable t ) 408 throw new Error("Unable to deobfuscate class " + c.getName(), t);
472 {
473 throw new Error( "Unable to deobfuscate class " + c.getName(), t );
474 } 409 }
475 } 410 }
476 if( progress != null ) 411 if (progress != null) {
477 { 412 progress.onProgress(i, "Done!");
478 progress.onProgress( i, "Done!" );
479 } 413 }
480 414
481 outJar.close(); 415 outJar.close();
482 } 416 } catch (IOException ex) {
483 catch( IOException ex ) 417 throw new Error("Unable to write to Jar file!");
484 {
485 throw new Error( "Unable to write to Jar file!" );
486 } 418 }
487 } 419 }
488 420
489 public <T extends Entry> T obfuscateEntry( T deobfEntry ) 421 public <T extends Entry> T obfuscateEntry(T deobfEntry) {
490 { 422 if (deobfEntry == null) {
491 if( deobfEntry == null )
492 {
493 return null; 423 return null;
494 } 424 }
495 return getTranslator( TranslationDirection.Obfuscating ).translateEntry( deobfEntry ); 425 return getTranslator(TranslationDirection.Obfuscating).translateEntry(deobfEntry);
496 } 426 }
497 427
498 public <T extends Entry> T deobfuscateEntry( T obfEntry ) 428 public <T extends Entry> T deobfuscateEntry(T obfEntry) {
499 { 429 if (obfEntry == null) {
500 if( obfEntry == null )
501 {
502 return null; 430 return null;
503 } 431 }
504 return getTranslator( TranslationDirection.Deobfuscating ).translateEntry( obfEntry ); 432 return getTranslator(TranslationDirection.Deobfuscating).translateEntry(obfEntry);
505 } 433 }
506 434
507 public <E extends Entry,C extends Entry> EntryReference<E,C> obfuscateReference( EntryReference<E,C> deobfReference ) 435 public <E extends Entry,C extends Entry> EntryReference<E,C> obfuscateReference(EntryReference<E,C> deobfReference) {
508 { 436 if (deobfReference == null) {
509 if( deobfReference == null )
510 {
511 return null; 437 return null;
512 } 438 }
513 return new EntryReference<E,C>( 439 return new EntryReference<E,C>(
514 obfuscateEntry( deobfReference.entry ), 440 obfuscateEntry(deobfReference.entry),
515 obfuscateEntry( deobfReference.context ), 441 obfuscateEntry(deobfReference.context),
516 deobfReference 442 deobfReference
517 ); 443 );
518 } 444 }
519 445
520 public <E extends Entry,C extends Entry> EntryReference<E,C> deobfuscateReference( EntryReference<E,C> obfReference ) 446 public <E extends Entry,C extends Entry> EntryReference<E,C> deobfuscateReference(EntryReference<E,C> obfReference) {
521 { 447 if (obfReference == null) {
522 if( obfReference == null )
523 {
524 return null; 448 return null;
525 } 449 }
526 return new EntryReference<E,C>( 450 return new EntryReference<E,C>(
527 deobfuscateEntry( obfReference.entry ), 451 deobfuscateEntry(obfReference.entry),
528 deobfuscateEntry( obfReference.context ), 452 deobfuscateEntry(obfReference.context),
529 obfReference 453 obfReference
530 ); 454 );
531 } 455 }
532 456
533 public boolean isObfuscatedIdentifier( Entry obfEntry ) 457 public boolean isObfuscatedIdentifier(Entry obfEntry) {
534 { 458 return m_jarIndex.containsObfEntry(obfEntry);
535 return m_jarIndex.containsObfEntry( obfEntry );
536 } 459 }
537 460
538 public boolean isRenameable( EntryReference<Entry,Entry> obfReference ) 461 public boolean isRenameable(EntryReference<Entry,Entry> obfReference) {
539 { 462 return obfReference.isNamed() && isObfuscatedIdentifier(obfReference.getNameableEntry());
540 return obfReference.isNamed() && isObfuscatedIdentifier( obfReference.getNameableEntry() );
541 } 463 }
542 464
543
544 // NOTE: these methods are a bit messy... oh well 465 // NOTE: these methods are a bit messy... oh well
545 466
546 public boolean hasDeobfuscatedName( Entry obfEntry ) 467 public boolean hasDeobfuscatedName(Entry obfEntry) {
547 { 468 Translator translator = getTranslator(TranslationDirection.Deobfuscating);
548 Translator translator = getTranslator( TranslationDirection.Deobfuscating ); 469 if (obfEntry instanceof ClassEntry) {
549 if( obfEntry instanceof ClassEntry ) 470 return translator.translate((ClassEntry)obfEntry) != null;
550 { 471 } else if (obfEntry instanceof FieldEntry) {
551 return translator.translate( (ClassEntry)obfEntry ) != null; 472 return translator.translate((FieldEntry)obfEntry) != null;
552 } 473 } else if (obfEntry instanceof MethodEntry) {
553 else if( obfEntry instanceof FieldEntry ) 474 return translator.translate((MethodEntry)obfEntry) != null;
554 { 475 } else if (obfEntry instanceof ConstructorEntry) {
555 return translator.translate( (FieldEntry)obfEntry ) != null;
556 }
557 else if( obfEntry instanceof MethodEntry )
558 {
559 return translator.translate( (MethodEntry)obfEntry ) != null;
560 }
561 else if( obfEntry instanceof ConstructorEntry )
562 {
563 // constructors have no names 476 // constructors have no names
564 return false; 477 return false;
565 } 478 } else if (obfEntry instanceof ArgumentEntry) {
566 else if( obfEntry instanceof ArgumentEntry ) 479 return translator.translate((ArgumentEntry)obfEntry) != null;
567 { 480 } else {
568 return translator.translate( (ArgumentEntry)obfEntry ) != null; 481 throw new Error("Unknown entry type: " + obfEntry.getClass().getName());
569 }
570 else
571 {
572 throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() );
573 } 482 }
574 } 483 }
575 484
576 public void rename( Entry obfEntry, String newName ) 485 public void rename(Entry obfEntry, String newName) {
577 { 486 if (obfEntry instanceof ClassEntry) {
578 if( obfEntry instanceof ClassEntry ) 487 m_renamer.setClassName((ClassEntry)obfEntry, Descriptor.toJvmName(newName));
579 { 488 } else if (obfEntry instanceof FieldEntry) {
580 m_renamer.setClassName( (ClassEntry)obfEntry, Descriptor.toJvmName( newName ) ); 489 m_renamer.setFieldName((FieldEntry)obfEntry, newName);
581 } 490 } else if (obfEntry instanceof MethodEntry) {
582 else if( obfEntry instanceof FieldEntry ) 491 m_renamer.setMethodTreeName((MethodEntry)obfEntry, newName);
583 { 492 } else if (obfEntry instanceof ConstructorEntry) {
584 m_renamer.setFieldName( (FieldEntry)obfEntry, newName ); 493 throw new IllegalArgumentException("Cannot rename constructors");
585 } 494 } else if (obfEntry instanceof ArgumentEntry) {
586 else if( obfEntry instanceof MethodEntry ) 495 m_renamer.setArgumentName((ArgumentEntry)obfEntry, newName);
587 { 496 } else {
588 m_renamer.setMethodTreeName( (MethodEntry)obfEntry, newName ); 497 throw new Error("Unknown entry type: " + obfEntry.getClass().getName());
589 }
590 else if( obfEntry instanceof ConstructorEntry )
591 {
592 throw new IllegalArgumentException( "Cannot rename constructors" );
593 }
594 else if( obfEntry instanceof ArgumentEntry )
595 {
596 m_renamer.setArgumentName( (ArgumentEntry)obfEntry, newName );
597 }
598 else
599 {
600 throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() );
601 } 498 }
602 499
603 // clear caches 500 // clear caches
604 m_translatorCache.clear(); 501 m_translatorCache.clear();
605 } 502 }
606 503
607 public void removeMapping( Entry obfEntry ) 504 public void removeMapping(Entry obfEntry) {
608 { 505 if (obfEntry instanceof ClassEntry) {
609 if( obfEntry instanceof ClassEntry ) 506 m_renamer.removeClassMapping((ClassEntry)obfEntry);
610 { 507 } else if (obfEntry instanceof FieldEntry) {
611 m_renamer.removeClassMapping( (ClassEntry)obfEntry ); 508 m_renamer.removeFieldMapping((FieldEntry)obfEntry);
612 } 509 } else if (obfEntry instanceof MethodEntry) {
613 else if( obfEntry instanceof FieldEntry ) 510 m_renamer.removeMethodTreeMapping((MethodEntry)obfEntry);
614 { 511 } else if (obfEntry instanceof ConstructorEntry) {
615 m_renamer.removeFieldMapping( (FieldEntry)obfEntry ); 512 throw new IllegalArgumentException("Cannot rename constructors");
616 } 513 } else if (obfEntry instanceof ArgumentEntry) {
617 else if( obfEntry instanceof MethodEntry ) 514 m_renamer.removeArgumentMapping((ArgumentEntry)obfEntry);
618 { 515 } else {
619 m_renamer.removeMethodTreeMapping( (MethodEntry)obfEntry ); 516 throw new Error("Unknown entry type: " + obfEntry);
620 }
621 else if( obfEntry instanceof ConstructorEntry )
622 {
623 throw new IllegalArgumentException( "Cannot rename constructors" );
624 }
625 else if( obfEntry instanceof ArgumentEntry )
626 {
627 m_renamer.removeArgumentMapping( (ArgumentEntry)obfEntry );
628 }
629 else
630 {
631 throw new Error( "Unknown entry type: " + obfEntry );
632 } 517 }
633 518
634 // clear caches 519 // clear caches
635 m_translatorCache.clear(); 520 m_translatorCache.clear();
636 } 521 }
637 522
638 public void markAsDeobfuscated( Entry obfEntry ) 523 public void markAsDeobfuscated(Entry obfEntry) {
639 { 524 if (obfEntry instanceof ClassEntry) {
640 if( obfEntry instanceof ClassEntry ) 525 m_renamer.markClassAsDeobfuscated((ClassEntry)obfEntry);
641 { 526 } else if (obfEntry instanceof FieldEntry) {
642 m_renamer.markClassAsDeobfuscated( (ClassEntry)obfEntry ); 527 m_renamer.markFieldAsDeobfuscated((FieldEntry)obfEntry);
643 } 528 } else if (obfEntry instanceof MethodEntry) {
644 else if( obfEntry instanceof FieldEntry ) 529 m_renamer.markMethodTreeAsDeobfuscated((MethodEntry)obfEntry);
645 { 530 } else if (obfEntry instanceof ConstructorEntry) {
646 m_renamer.markFieldAsDeobfuscated( (FieldEntry)obfEntry ); 531 throw new IllegalArgumentException("Cannot rename constructors");
647 } 532 } else if (obfEntry instanceof ArgumentEntry) {
648 else if( obfEntry instanceof MethodEntry ) 533 m_renamer.markArgumentAsDeobfuscated((ArgumentEntry)obfEntry);
649 { 534 } else {
650 m_renamer.markMethodTreeAsDeobfuscated( (MethodEntry)obfEntry ); 535 throw new Error("Unknown entry type: " + obfEntry);
651 }
652 else if( obfEntry instanceof ConstructorEntry )
653 {
654 throw new IllegalArgumentException( "Cannot rename constructors" );
655 } 536 }
656 else if( obfEntry instanceof ArgumentEntry ) 537
657 {
658 m_renamer.markArgumentAsDeobfuscated( (ArgumentEntry)obfEntry );
659 }
660 else
661 {
662 throw new Error( "Unknown entry type: " + obfEntry );
663 }
664
665 // clear caches 538 // clear caches
666 m_translatorCache.clear(); 539 m_translatorCache.clear();
667 } 540 }