From 2e97f24a658aa897313cb7cf92ed2e4b4a986bfc Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 25 Aug 2014 00:04:47 -0400 Subject: fixed issue with bridge methods so source export has fewer compile errors. =) --- src/cuchaz/enigma/Deobfuscator.java | 6 + src/cuchaz/enigma/Main.java | 3 +- src/cuchaz/enigma/TranslatingTypeLoader.java | 2 +- src/cuchaz/enigma/analysis/BridgeFixer.java | 92 -------------- src/cuchaz/enigma/analysis/JarIndex.java | 172 ++++++++++++++++++++++++--- 5 files changed, 163 insertions(+), 112 deletions(-) delete mode 100644 src/cuchaz/enigma/analysis/BridgeFixer.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 0bc4a04..8a516b1 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -219,6 +219,12 @@ public class Deobfuscator continue; } + // TEMP: skip the classes that won't decompile because of a procyon bug + if( obfClassEntry.getName().equals( "none/bgl" ) ) + { + continue; + } + ClassEntry deobfClassEntry = deobfuscateEntry( new ClassEntry( obfClassEntry ) ); if( progress != null ) { diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index fe4d6e3..c69b890 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -13,6 +13,7 @@ package cuchaz.enigma; import java.io.File; import cuchaz.enigma.gui.Gui; +import cuchaz.enigma.mapping.ClassEntry; public class Main { @@ -32,7 +33,7 @@ public class Main } // DEBUG - //gui.getController().openDeclaration( new ClassEntry( "none/bgl" ) ); + gui.getController().openDeclaration( new ClassEntry( "none/bsp" ) ); } private static File getFile( String path ) diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index 763d767..83f0baa 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -177,7 +177,7 @@ public class TranslatingTypeLoader implements ITypeLoader assertClassName( c, obfClassEntry ); // do all kinds of deobfuscating transformations on the class - new BridgeFixer().fixBridges( c ); + new BridgeFixer( m_jarIndex ).fixBridges( c ); new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c ); new ClassTranslator( m_deobfuscatingTranslator ).translate( c ); diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java deleted file mode 100644 index f13f68f..0000000 --- a/src/cuchaz/enigma/analysis/BridgeFixer.java +++ /dev/null @@ -1,92 +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.analysis; - -import java.util.List; - -import javassist.CannotCompileException; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.NotFoundException; -import javassist.bytecode.AccessFlag; -import javassist.expr.ExprEditor; -import javassist.expr.MethodCall; - -import com.beust.jcommander.internal.Lists; - -public class BridgeFixer -{ - public void fixBridges( CtClass c ) - { - // bridge methods are scrubbed and marked as synthetic methods by the obfuscator - // need to figure out which synthetics are bridge methods and restore them - for( CtMethod method : c.getDeclaredMethods() ) - { - // skip non-synthetic methods - if( ( method.getModifiers() & AccessFlag.SYNTHETIC ) == 0 ) - { - continue; - } - - CtMethod bridgedMethod = getBridgedMethod( method ); - if( bridgedMethod != null ) - { - bridgedMethod.setName( method.getName() ); - method.setModifiers( method.getModifiers() | AccessFlag.BRIDGE ); - - // TODO: rename all references to this method? - } - } - } - - private CtMethod getBridgedMethod( CtMethod method ) - { - // bridge methods just call another method, cast it to the return type, and return the result - // let's see if we can detect this scenario - - // get all the called methods - final List methodCalls = Lists.newArrayList(); - try - { - method.instrument( new ExprEditor( ) - { - @Override - public void edit( MethodCall call ) - { - methodCalls.add( call ); - } - } ); - } - catch( CannotCompileException ex ) - { - // this is stupid... we're not even compiling anything - throw new Error( ex ); - } - - // is there just one? - if( methodCalls.size() != 1 ) - { - return null; - } - MethodCall call = methodCalls.get( 0 ); - - try - { - // we have a bridge method! - return call.getMethod(); - } - catch( NotFoundException ex ) - { - // can't find the type? not a bridge method - return null; - } - } -} diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 2c4dec4..cb7508e 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -24,6 +24,7 @@ import javassist.CtBehavior; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtMethod; +import javassist.NotFoundException; import javassist.bytecode.AccessFlag; import javassist.bytecode.Descriptor; import javassist.bytecode.FieldInfo; @@ -60,6 +61,7 @@ public class JarIndex private Multimap m_innerClasses; private Map m_outerClasses; private Set m_anonymousClasses; + private Map m_bridgeMethods; public JarIndex( ) { @@ -71,11 +73,12 @@ public class JarIndex m_innerClasses = HashMultimap.create(); m_outerClasses = Maps.newHashMap(); m_anonymousClasses = Sets.newHashSet(); + m_bridgeMethods = Maps.newHashMap(); } public void indexJar( JarFile jar ) { - // pass 1: read the class names + // step 1: read the class names for( ClassEntry classEntry : JarClassIterator.getClassEntries( jar ) ) { if( classEntry.isInDefaultPackage() ) @@ -86,7 +89,7 @@ public class JarIndex m_obfClassEntries.add( classEntry ); } - // pass 2: index the types, methods + // step 2: index the types, methods for( CtClass c : JarClassIterator.classes( jar ) ) { fixClass( c ); @@ -97,7 +100,7 @@ public class JarIndex } } - // pass 2: index inner classes and anonymous classes + // step 3: index inner classes and anonymous classes for( CtClass c : JarClassIterator.classes( jar ) ) { fixClass( c ); @@ -124,13 +127,16 @@ public class JarIndex } } - // step 3: update other indicies with inner class info + // step 4: update other indices with inner class info Map renames = Maps.newHashMap(); for( Map.Entry entry : m_outerClasses.entrySet() ) { renames.put( entry.getKey(), entry.getValue() + "$" + entry.getKey() ); } renameClasses( renames ); + + // step 5: update other indices with bridge method info + renameMethods( m_bridgeMethods ); } private void fixClass( CtClass c ) @@ -160,6 +166,18 @@ public class JarIndex // index implementation m_methodImplementations.put( className, methodEntry ); + + // look for bridge methods + CtMethod bridgedMethod = getBridgedMethod( (CtMethod)behavior ); + if( bridgedMethod != null ) + { + MethodEntry bridgedMethodEntry = new MethodEntry( + new ClassEntry( className ), + bridgedMethod.getName(), + bridgedMethod.getSignature() + ); + m_bridgeMethods.put( bridgedMethodEntry, methodEntry ); + } } else if( behavior instanceof CtConstructor ) { @@ -254,6 +272,56 @@ public class JarIndex } } + + private CtMethod getBridgedMethod( CtMethod method ) + { + // bridge methods just call another method, cast it to the return type, and return the result + // let's see if we can detect this scenario + + // skip non-synthetic methods + if( ( method.getModifiers() & AccessFlag.SYNTHETIC ) == 0 ) + { + return null; + } + + // get all the called methods + final List methodCalls = Lists.newArrayList(); + try + { + method.instrument( new ExprEditor( ) + { + @Override + public void edit( MethodCall call ) + { + methodCalls.add( call ); + } + } ); + } + catch( CannotCompileException ex ) + { + // this is stupid... we're not even compiling anything + throw new Error( ex ); + } + + // is there just one? + if( methodCalls.size() != 1 ) + { + return null; + } + MethodCall call = methodCalls.get( 0 ); + + try + { + // we have a bridge method! + return call.getMethod(); + } + catch( NotFoundException ex ) + { + // can't find the type? not a bridge method + return null; + } + } + private String findOuterClass( CtClass c ) { // inner classes: @@ -534,15 +602,27 @@ public class JarIndex return m_anonymousClasses.contains( obfInnerClassName ); } + public MethodEntry getBridgeMethod( MethodEntry methodEntry ) + { + return m_bridgeMethods.get( methodEntry ); + } + private void renameClasses( Map renames ) { m_ancestries.renameClasses( renames ); - renameMultimap( renames, m_methodImplementations ); - renameMultimap( renames, m_behaviorReferences ); - renameMultimap( renames, m_fieldReferences ); + renameClassesInMultimap( renames, m_methodImplementations ); + renameClassesInMultimap( renames, m_behaviorReferences ); + renameClassesInMultimap( renames, m_fieldReferences ); + } + + private void renameMethods( Map renames ) + { + renameMethodsInMultimap( renames, m_methodImplementations ); + renameMethodsInMultimap( renames, m_behaviorReferences ); + renameMethodsInMultimap( renames, m_fieldReferences ); } - private void renameMultimap( Map renames, Multimap map ) + private void renameClassesInMultimap( Map renames, Multimap map ) { // for each key/value pair... Set> entriesToAdd = Sets.newHashSet(); @@ -552,8 +632,8 @@ public class JarIndex Map.Entry entry = iter.next(); iter.remove(); entriesToAdd.add( new AbstractMap.SimpleEntry( - renameThing( renames, entry.getKey() ), - renameThing( renames, entry.getValue() ) + renameClassesInThing( renames, entry.getKey() ), + renameClassesInThing( renames, entry.getValue() ) ) ); } for( Map.Entry entry : entriesToAdd ) @@ -563,7 +643,7 @@ public class JarIndex } @SuppressWarnings( "unchecked" ) - private T renameThing( Map renames, T thing ) + private T renameClassesInThing( Map renames, T thing ) { if( thing instanceof String ) { @@ -576,13 +656,13 @@ public class JarIndex else if( thing instanceof ClassEntry ) { ClassEntry classEntry = (ClassEntry)thing; - return (T)new ClassEntry( renameThing( renames, classEntry.getClassName() ) ); + return (T)new ClassEntry( renameClassesInThing( renames, classEntry.getClassName() ) ); } else if( thing instanceof FieldEntry ) { FieldEntry fieldEntry = (FieldEntry)thing; return (T)new FieldEntry( - renameThing( renames, fieldEntry.getClassEntry() ), + renameClassesInThing( renames, fieldEntry.getClassEntry() ), fieldEntry.getName() ); } @@ -590,7 +670,7 @@ public class JarIndex { ConstructorEntry constructorEntry = (ConstructorEntry)thing; return (T)new ConstructorEntry( - renameThing( renames, constructorEntry.getClassEntry() ), + renameClassesInThing( renames, constructorEntry.getClassEntry() ), constructorEntry.getSignature() ); } @@ -598,7 +678,7 @@ public class JarIndex { MethodEntry methodEntry = (MethodEntry)thing; return (T)new MethodEntry( - renameThing( renames, methodEntry.getClassEntry() ), + renameClassesInThing( renames, methodEntry.getClassEntry() ), methodEntry.getName(), methodEntry.getSignature() ); @@ -607,7 +687,7 @@ public class JarIndex { ArgumentEntry argumentEntry = (ArgumentEntry)thing; return (T)new ArgumentEntry( - renameThing( renames, argumentEntry.getMethodEntry() ), + renameClassesInThing( renames, argumentEntry.getMethodEntry() ), argumentEntry.getIndex(), argumentEntry.getName() ); @@ -615,8 +695,8 @@ public class JarIndex else if( thing instanceof EntryReference ) { EntryReference reference = (EntryReference)thing; - reference.entry = renameThing( renames, reference.entry ); - reference.context = renameThing( renames, reference.context ); + reference.entry = renameClassesInThing( renames, reference.entry ); + reference.context = renameClassesInThing( renames, reference.context ); return thing; } else @@ -626,4 +706,60 @@ public class JarIndex return thing; } + + private void renameMethodsInMultimap( Map renames, Multimap map ) + { + // for each key/value pair... + Set> entriesToAdd = Sets.newHashSet(); + Iterator> iter = map.entries().iterator(); + while( iter.hasNext() ) + { + Map.Entry entry = iter.next(); + iter.remove(); + entriesToAdd.add( new AbstractMap.SimpleEntry( + renameMethodsInThing( renames, entry.getKey() ), + renameMethodsInThing( renames, entry.getValue() ) + ) ); + } + for( Map.Entry entry : entriesToAdd ) + { + map.put( entry.getKey(), entry.getValue() ); + } + } + + @SuppressWarnings( "unchecked" ) + private T renameMethodsInThing( Map renames, T thing ) + { + if( thing instanceof MethodEntry ) + { + MethodEntry methodEntry = (MethodEntry)thing; + MethodEntry newMethodEntry = renames.get( methodEntry ); + if( newMethodEntry != null ) + { + return (T)new MethodEntry( + methodEntry.getClassEntry(), + newMethodEntry.getName(), + methodEntry.getSignature() + ); + } + return thing; + } + else if( thing instanceof ArgumentEntry ) + { + ArgumentEntry argumentEntry = (ArgumentEntry)thing; + return (T)new ArgumentEntry( + renameMethodsInThing( renames, argumentEntry.getMethodEntry() ), + argumentEntry.getIndex(), + argumentEntry.getName() + ); + } + else if( thing instanceof EntryReference ) + { + EntryReference reference = (EntryReference)thing; + reference.entry = renameMethodsInThing( renames, reference.entry ); + reference.context = renameMethodsInThing( renames, reference.context ); + return thing; + } + return thing; + } } -- cgit v1.2.3