From 064fe6a628f23f21eb2c8f584215f439e54cfaec Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 24 Sep 2014 20:32:19 -0400 Subject: fixed in-jar detection for bridge-related methods --- src/cuchaz/enigma/Deobfuscator.java | 39 ++++------- src/cuchaz/enigma/analysis/BridgeFixer.java | 22 +++++-- src/cuchaz/enigma/analysis/EntryRenamer.java | 25 +++++-- src/cuchaz/enigma/analysis/JarIndex.java | 40 ++---------- .../enigma/analysis/SourceIndexClassVisitor.java | 12 +--- src/cuchaz/enigma/bytecode/ClassTranslator.java | 41 +++++------- src/cuchaz/enigma/mapping/BehaviorEntry.java | 12 +++- .../enigma/mapping/BehaviorEntryFactory.java | 76 ++++++++++++++++++++++ src/cuchaz/enigma/mapping/MethodEntry.java | 4 ++ src/cuchaz/enigma/mapping/MethodMapping.java | 5 ++ 10 files changed, 170 insertions(+), 106 deletions(-) create mode 100644 src/cuchaz/enigma/mapping/BehaviorEntryFactory.java (limited to 'src/cuchaz') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index f7f74480..9a339176 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -41,6 +41,8 @@ import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.SourceIndexVisitor; import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.BehaviorEntryFactory; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ClassMapping; import cuchaz.enigma.mapping.ConstructorEntry; @@ -165,6 +167,12 @@ public class Deobfuscator // methods for( MethodMapping methodMapping : Lists.newArrayList( classMapping.methods() ) ) { + // skip constructors + if( methodMapping.isConstructor() ) + { + continue; + } + MethodEntry methodEntry = new MethodEntry( obfClassEntry, methodMapping.getObfName(), methodMapping.getObfSignature() ); ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( methodEntry ); if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( methodEntry.getClassEntry() ) ) @@ -228,33 +236,12 @@ public class Deobfuscator // check methods for( MethodMapping methodMapping : Lists.newArrayList( classMapping.methods() ) ) { - if( methodMapping.getObfName().equals( "" ) ) - { - // skip static initializers - continue; - } - else if( methodMapping.getObfName().equals( "" ) ) - { - ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, methodMapping.getObfSignature() ); - if( !m_jarIndex.containsObfBehavior( constructorEntry ) ) - { - System.err.println( "WARNING: unable to find constructor " + constructorEntry + ". dropping mapping." ); - classMapping.removeMethodMapping( methodMapping ); - } - } - else + BehaviorEntry obfBehaviorEntry = BehaviorEntryFactory.createObf( classEntry, methodMapping ); + if( !m_jarIndex.containsObfBehavior( obfBehaviorEntry ) ) { - MethodEntry methodEntry = new MethodEntry( - classEntry, - methodMapping.getObfName(), - methodMapping.getObfSignature() - ); - if( !m_jarIndex.containsObfBehavior( methodEntry ) ) - { - System.err.println( "WARNING: unable to find method " + methodEntry + ". dropping mapping." ); - classMapping.removeMethodMapping( methodMapping ); - } - } + System.err.println( "WARNING: unable to find behavior " + obfBehaviorEntry + ". dropping mapping." ); + classMapping.removeMethodMapping( methodMapping ); + } } // check inner classes diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java index aeaf871a..112b864a 100644 --- a/src/cuchaz/enigma/analysis/BridgeFixer.java +++ b/src/cuchaz/enigma/analysis/BridgeFixer.java @@ -15,6 +15,8 @@ import javassist.CtMethod; import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; import cuchaz.enigma.bytecode.ConstPoolEditor; +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.BehaviorEntryFactory; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.MethodEntry; @@ -57,17 +59,23 @@ public class BridgeFixer case ConstPool.CONST_Methodref: case ConstPool.CONST_InterfaceMethodref: { - // translate the name and type - MethodEntry methodEntry = new MethodEntry( - new ClassEntry( Descriptor.toJvmName( editor.getMemberrefClassname( i ) ) ), + BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( + Descriptor.toJvmName( editor.getMemberrefClassname( i ) ), editor.getMemberrefName( i ), editor.getMemberrefType( i ) ); - MethodEntry bridgeMethodEntry = m_index.getBridgeMethod( methodEntry ); - if( bridgeMethodEntry != null ) + + if( behaviorEntry instanceof MethodEntry ) { - // FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT - editor.changeMemberrefNameAndType( i, bridgeMethodEntry.getName(), bridgeMethodEntry.getSignature() ); + MethodEntry methodEntry = (MethodEntry)behaviorEntry; + + // translate the name and type + MethodEntry bridgeMethodEntry = m_index.getBridgeMethod( methodEntry ); + if( bridgeMethodEntry != null ) + { + // FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT + editor.changeMemberrefNameAndType( i, bridgeMethodEntry.getName(), bridgeMethodEntry.getSignature() ); + } } } break; diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java index 44e0220c..2d59fe9d 100644 --- a/src/cuchaz/enigma/analysis/EntryRenamer.java +++ b/src/cuchaz/enigma/analysis/EntryRenamer.java @@ -11,7 +11,6 @@ package cuchaz.enigma.analysis; import java.util.AbstractMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -80,16 +79,32 @@ public class EntryRenamer { // for each key/value pair... Set> entriesToAdd = Sets.newHashSet(); - Iterator> iter = map.entries().iterator(); - while( iter.hasNext() ) + for( Map.Entry entry : map.entries() ) { - Map.Entry entry = iter.next(); - iter.remove(); entriesToAdd.add( new AbstractMap.SimpleEntry( renameMethodsInThing( renames, entry.getKey() ), renameMethodsInThing( renames, entry.getValue() ) ) ); } + map.clear(); + for( Map.Entry entry : entriesToAdd ) + { + map.put( entry.getKey(), entry.getValue() ); + } + } + + public static void renameMethodsInMap( Map renames, Map map ) + { + // for each key/value pair... + Set> entriesToAdd = Sets.newHashSet(); + for( Map.Entry entry : map.entrySet() ) + { + entriesToAdd.add( new AbstractMap.SimpleEntry( + renameMethodsInThing( renames, entry.getKey() ), + renameMethodsInThing( renames, entry.getValue() ) + ) ); + } + map.clear(); for( Map.Entry entry : entriesToAdd ) { map.put( entry.getKey(), entry.getValue() ); diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 9f309cec..a2f6bf34 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -44,6 +44,7 @@ import cuchaz.enigma.Constants; import cuchaz.enigma.bytecode.ClassRenamer; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.BehaviorEntryFactory; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; @@ -203,6 +204,7 @@ public class JarIndex EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_methodImplementations ); EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_behaviorReferences ); EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_fieldReferences ); + EntryRenamer.renameMethodsInMap( m_bridgeMethods, m_access ); } private void indexField( CtField field ) @@ -224,21 +226,20 @@ public class JarIndex private void indexBehavior( CtBehavior behavior ) { // get the behavior entry - String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); - final BehaviorEntry behaviorEntry = getBehaviorEntry( behavior ); + final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( behavior ); if( behaviorEntry instanceof MethodEntry ) { MethodEntry methodEntry = (MethodEntry)behaviorEntry; // index implementation - m_methodImplementations.put( className, methodEntry ); + m_methodImplementations.put( behaviorEntry.getClassName(), methodEntry ); // look for bridge methods CtMethod bridgedMethod = getBridgedMethod( (CtMethod)behavior ); if( bridgedMethod != null ) { MethodEntry bridgedMethodEntry = new MethodEntry( - new ClassEntry( className ), + behaviorEntry.getClassEntry(), bridgedMethod.getName(), bridgedMethod.getSignature() ); @@ -251,7 +252,7 @@ public class JarIndex private void indexBehaviorReferences( CtBehavior behavior ) { // index method calls - final BehaviorEntry behaviorEntry = getBehaviorEntry( behavior ); + final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( behavior ); try { behavior.instrument( new ExprEditor( ) @@ -344,35 +345,6 @@ public class JarIndex } } - private BehaviorEntry getBehaviorEntry( CtBehavior behavior ) - { - String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); - if( behavior instanceof CtMethod ) - { - return new MethodEntry( - new ClassEntry( className ), - behavior.getName(), - behavior.getSignature() - ); - } - else if( behavior instanceof CtConstructor ) - { - boolean isStatic = behavior.getName().equals( "" ); - if( isStatic ) - { - return new ConstructorEntry( new ClassEntry( className ) ); - } - else - { - return new ConstructorEntry( new ClassEntry( className ), behavior.getSignature() ); - } - } - else - { - throw new IllegalArgumentException( "behavior must be a method or a constructor!" ); - } - } - public ClassEntry resolveEntryClass( Entry obfEntry ) { // this entry could refer to a method on a class where the method is not actually implemented diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java index b7897268..5d8a3833 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java @@ -25,11 +25,11 @@ import com.strobel.decompiler.languages.java.ast.TypeDeclaration; import com.strobel.decompiler.languages.java.ast.VariableInitializer; import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.BehaviorEntryFactory; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.MethodEntry; public class SourceIndexClassVisitor extends SourceIndexVisitor { @@ -77,15 +77,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor { MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - BehaviorEntry behaviorEntry; - if( def.getName().equals( "" ) ) - { - behaviorEntry = new ConstructorEntry( classEntry ); - } - else - { - behaviorEntry = new MethodEntry( classEntry, def.getName(), def.getSignature() ); - } + BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( classEntry, def.getName(), def.getSignature() ); index.addDeclaration( node.getNameToken(), behaviorEntry ); return node.acceptVisitor( new SourceIndexBehaviorVisitor( behaviorEntry ), index ); } diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java index 88926928..db28f21b 100644 --- a/src/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java @@ -21,6 +21,8 @@ import javassist.bytecode.Descriptor; import com.google.common.collect.Maps; +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.BehaviorEntryFactory; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MethodEntry; @@ -53,19 +55,15 @@ public class ClassTranslator new ClassEntry( Descriptor.toJvmName( constants.getFieldrefClassName( i ) ) ), constants.getFieldrefName( i ) ); - String translatedName = m_translator.translate( entry ); - if( translatedName == null ) - { - translatedName = entry.getName(); - } + FieldEntry translatedEntry = m_translator.translateEntry( entry ); // translate the type String type = constants.getFieldrefType( i ); String translatedType = m_translator.translateSignature( type ); - if( !entry.getName().equals( translatedName ) || !type.equals( translatedType ) ) + if( !entry.equals( translatedEntry ) || !type.equals( translatedType ) ) { - editor.changeMemberrefNameAndType( i, translatedName, translatedType ); + editor.changeMemberrefNameAndType( i, translatedEntry.getName(), translatedType ); } } break; @@ -74,21 +72,16 @@ public class ClassTranslator case ConstPool.CONST_InterfaceMethodref: { // translate the name and type - MethodEntry entry = new MethodEntry( - new ClassEntry( Descriptor.toJvmName( editor.getMemberrefClassname( i ) ) ), + BehaviorEntry entry = BehaviorEntryFactory.create( + Descriptor.toJvmName( editor.getMemberrefClassname( i ) ), editor.getMemberrefName( i ), editor.getMemberrefType( i ) ); - String translatedName = m_translator.translate( entry ); - if( translatedName == null ) - { - translatedName = entry.getName(); - } - String translatedSignature = m_translator.translateSignature( entry.getSignature() ); + BehaviorEntry translatedEntry = m_translator.translateEntry( entry ); - if( !entry.getName().equals( translatedName ) || !entry.getSignature().equals( translatedSignature ) ) + if( !entry.getName().equals( translatedEntry.getName() ) || !entry.getSignature().equals( translatedEntry.getSignature() ) ) { - editor.changeMemberrefNameAndType( i, translatedName, translatedSignature ); + editor.changeMemberrefNameAndType( i, translatedEntry.getName(), translatedEntry.getSignature() ); } } break; @@ -116,14 +109,16 @@ public class ClassTranslator // translate all the methods and constructors for( CtBehavior behavior : c.getDeclaredBehaviors() ) { - // translate the name - MethodEntry entry = new MethodEntry( classEntry, behavior.getName(), behavior.getSignature() ); - String translatedName = m_translator.translate( entry ); - if( translatedName != null ) + if( behavior instanceof CtMethod ) { - if( behavior instanceof CtMethod ) + CtMethod method = (CtMethod)behavior; + + // translate the name + MethodEntry entry = new MethodEntry( classEntry, method.getName(), method.getSignature() ); + String translatedName = m_translator.translate( entry ); + if( translatedName != null ) { - ((CtMethod)behavior).setName( translatedName ); + method.setName( translatedName ); } } diff --git a/src/cuchaz/enigma/mapping/BehaviorEntry.java b/src/cuchaz/enigma/mapping/BehaviorEntry.java index 99fdd28d..8fc4eaf0 100644 --- a/src/cuchaz/enigma/mapping/BehaviorEntry.java +++ b/src/cuchaz/enigma/mapping/BehaviorEntry.java @@ -1,6 +1,16 @@ +/******************************************************************************* + * 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.mapping; public interface BehaviorEntry extends Entry { - public String getSignature(); + String getSignature(); } diff --git a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java new file mode 100644 index 00000000..d3cfb938 --- /dev/null +++ b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * 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.mapping; + +import javassist.CtBehavior; +import javassist.CtConstructor; +import javassist.CtMethod; +import javassist.bytecode.Descriptor; + + +public class BehaviorEntryFactory +{ + public static BehaviorEntry create( String className, String name, String signature ) + { + return create( new ClassEntry( className ), name, signature ); + } + + public static BehaviorEntry create( ClassEntry classEntry, String name, String signature ) + { + if( name.equals( "" ) ) + { + return new ConstructorEntry( classEntry, signature ); + } + else if( name.equals( "" ) ) + { + return new ConstructorEntry( classEntry ); + } + else + { + return new MethodEntry( classEntry, name, signature ); + } + } + + public static BehaviorEntry create( CtBehavior behavior ) + { + String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); + if( behavior instanceof CtMethod ) + { + return create( className, behavior.getName(), behavior.getSignature() ); + } + else if( behavior instanceof CtConstructor ) + { + CtConstructor constructor = (CtConstructor)behavior; + if( constructor.isClassInitializer() ) + { + return create( className, "", null ); + } + else + { + return create( className, "", constructor.getSignature() ); + } + } + else + { + throw new IllegalArgumentException( "Unable to create BehaviorEntry from " + behavior ); + } + } + + public static BehaviorEntry createObf( ClassEntry classEntry, MethodMapping methodMapping ) + { + return create( classEntry, methodMapping.getObfName(), methodMapping.getObfSignature() ); + } + + public static BehaviorEntry createDeobf( ClassEntry classEntry, MethodMapping methodMapping ) + { + return create( classEntry, methodMapping.getDeobfName(), methodMapping.getObfSignature() ); + } +} diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java index 8adbfe9c..dbc18855 100644 --- a/src/cuchaz/enigma/mapping/MethodEntry.java +++ b/src/cuchaz/enigma/mapping/MethodEntry.java @@ -36,6 +36,10 @@ public class MethodEntry implements BehaviorEntry, Serializable { throw new IllegalArgumentException( "Method signature cannot be null!" ); } + if( name.startsWith( "<" ) ) + { + throw new IllegalArgumentException( "Don't use MethodEntry for a constructor!" ); + } m_classEntry = classEntry; m_name = name; diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java index 6210fd09..b076fa33 100644 --- a/src/cuchaz/enigma/mapping/MethodMapping.java +++ b/src/cuchaz/enigma/mapping/MethodMapping.java @@ -70,6 +70,11 @@ public class MethodMapping implements Serializable, Comparable return m_arguments.values(); } + public boolean isConstructor( ) + { + return m_obfName.startsWith( "<" ); + } + public void addArgumentMapping( ArgumentMapping argumentMapping ) { boolean wasAdded = m_arguments.put( argumentMapping.getIndex(), argumentMapping ) == null; -- cgit v1.2.3