From 8776a8ba38123c822530e5f659c626c8db616217 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 24 Sep 2014 01:00:54 -0400 Subject: HOW DO I WRITE SO MANY BUGS?!? --- src/cuchaz/enigma/Deobfuscator.java | 102 ++++++++++++++++----- src/cuchaz/enigma/analysis/EntryRenamer.java | 4 +- src/cuchaz/enigma/analysis/JarIndex.java | 102 +++++++++++++++------ .../analysis/MethodImplementationsTreeNode.java | 2 +- .../enigma/analysis/MethodInheritanceTreeNode.java | 2 +- src/cuchaz/enigma/analysis/SourceIndex.java | 9 ++ .../analysis/SourceIndexBehaviorVisitor.java | 18 +++- .../enigma/bytecode/MethodParameterWriter.java | 22 ++++- src/cuchaz/enigma/convert/ClassMatcher.java | 6 +- src/cuchaz/enigma/gui/Gui.java | 16 ++-- src/cuchaz/enigma/gui/GuiController.java | 3 +- src/cuchaz/enigma/mapping/ArgumentEntry.java | 43 ++++++--- src/cuchaz/enigma/mapping/ClassEntry.java | 18 ++-- src/cuchaz/enigma/mapping/ClassMapping.java | 34 ++++--- src/cuchaz/enigma/mapping/ConstructorEntry.java | 12 +++ src/cuchaz/enigma/mapping/Entry.java | 1 + src/cuchaz/enigma/mapping/FieldEntry.java | 6 ++ src/cuchaz/enigma/mapping/Mappings.java | 6 +- src/cuchaz/enigma/mapping/MappingsRenamer.java | 32 ++++++- src/cuchaz/enigma/mapping/MethodEntry.java | 6 ++ src/cuchaz/enigma/mapping/Translator.java | 2 +- 21 files changed, 335 insertions(+), 111 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 03c35113..f7f74480 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -39,6 +39,7 @@ import cuchaz.enigma.analysis.EntryReference; import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.SourceIndexVisitor; +import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ClassMapping; @@ -115,7 +116,7 @@ public class Deobfuscator val = new Mappings(); } - // look for any classes that got moved to inner classes + // pass 1: look for any classes that got moved to inner classes Map renames = Maps.newHashMap(); for( ClassMapping classMapping : val.classes() ) { @@ -136,6 +137,53 @@ public class Deobfuscator val.renameObfClass( entry.getKey(), entry.getValue() ); } + // pass 2: look for fields/methods that are actually declared in superclasses + MappingsRenamer renamer = new MappingsRenamer( m_jarIndex, val ); + for( ClassMapping classMapping : val.classes() ) + { + ClassEntry obfClassEntry = new ClassEntry( classMapping.getObfName() ); + + // fields + for( FieldMapping fieldMapping : Lists.newArrayList( classMapping.fields() ) ) + { + FieldEntry fieldEntry = new FieldEntry( obfClassEntry, fieldMapping.getObfName() ); + ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( fieldEntry ); + if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( fieldEntry.getClassEntry() ) ) + { + boolean wasMoved = renamer.moveFieldToObfClass( classMapping, fieldMapping, resolvedObfClassEntry ); + if( wasMoved ) + { + System.out.println( String.format( "Moved field %s to class %s", fieldEntry, resolvedObfClassEntry ) ); + } + else + { + System.err.println( String.format( "WARNING: Would move field %s to class %s but the field was already there. Dropping instead.", fieldEntry, resolvedObfClassEntry ) ); + } + } + } + + // methods + for( MethodMapping methodMapping : Lists.newArrayList( classMapping.methods() ) ) + { + MethodEntry methodEntry = new MethodEntry( obfClassEntry, methodMapping.getObfName(), methodMapping.getObfSignature() ); + ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( methodEntry ); + if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( methodEntry.getClassEntry() ) ) + { + boolean wasMoved = renamer.moveMethodToObfClass( classMapping, methodMapping, resolvedObfClassEntry ); + if( wasMoved ) + { + System.out.println( String.format( "Moved method %s to class %s", methodEntry, resolvedObfClassEntry ) ); + } + else + { + System.err.println( String.format( "WARNING: Would move method %s to class %s but the method was already there. Dropping instead.", methodEntry, resolvedObfClassEntry ) ); + } + } + } + + // TODO: recurse to inner classes? + } + // drop mappings that don't match the jar List unknownClasses = Lists.newArrayList(); for( ClassMapping classMapping : val.classes() ) @@ -148,7 +196,7 @@ public class Deobfuscator } m_mappings = val; - m_renamer = new MappingsRenamer( m_jarIndex, m_mappings ); + m_renamer = renamer; m_translatorCache.clear(); } @@ -170,7 +218,7 @@ public class Deobfuscator for( FieldMapping fieldMapping : Lists.newArrayList( classMapping.fields() ) ) { FieldEntry fieldEntry = new FieldEntry( classEntry, fieldMapping.getObfName() ); - if( m_jarIndex.getAccess( fieldEntry ) == null ) + if( !m_jarIndex.containsObfField( fieldEntry ) ) { System.err.println( "WARNING: unable to find field " + fieldEntry + ". dropping mapping." ); classMapping.removeFieldMapping( fieldMapping ); @@ -188,7 +236,7 @@ public class Deobfuscator else if( methodMapping.getObfName().equals( "" ) ) { ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, methodMapping.getObfSignature() ); - if( m_jarIndex.getAccess( constructorEntry ) == null ) + if( !m_jarIndex.containsObfBehavior( constructorEntry ) ) { System.err.println( "WARNING: unable to find constructor " + constructorEntry + ". dropping mapping." ); classMapping.removeMethodMapping( methodMapping ); @@ -201,7 +249,7 @@ public class Deobfuscator methodMapping.getObfName(), methodMapping.getObfSignature() ); - if( m_jarIndex.getAccess( methodEntry ) == null ) + if( !m_jarIndex.containsObfBehavior( methodEntry ) ) { System.err.println( "WARNING: unable to find method " + methodEntry + ". dropping mapping." ); classMapping.removeMethodMapping( methodMapping ); @@ -257,19 +305,20 @@ public class Deobfuscator } } - public CompilationUnit getSourceTree( String className ) + public CompilationUnit getSourceTree( String obfClassName ) { // is this class deobfuscated? // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out // the decompiler only sees the deobfuscated class, so we need to load it by the deobfuscated name - ClassMapping classMapping = m_mappings.getClassByObf( className ); + String lookupClassName = obfClassName; + ClassMapping classMapping = m_mappings.getClassByObf( obfClassName ); if( classMapping != null && classMapping.getDeobfName() != null ) { - className = classMapping.getDeobfName(); + lookupClassName = classMapping.getDeobfName(); } // is this class even in the jar? - if( !m_jarIndex.containsObfClass( new ClassEntry( className ) ) ) + if( !m_jarIndex.containsObfClass( new ClassEntry( obfClassName ) ) ) { return null; } @@ -283,7 +332,7 @@ public class Deobfuscator ) ); // decompile it! - TypeDefinition resolvedType = new MetadataSystem( m_settings.getTypeLoader() ).lookupType( className ).resolve(); + TypeDefinition resolvedType = new MetadataSystem( m_settings.getTypeLoader() ).lookupType( lookupClassName ).resolve(); DecompilerContext context = new DecompilerContext(); context.setCurrentType( resolvedType ); context.setSettings( m_settings ); @@ -302,13 +351,29 @@ public class Deobfuscator // DEBUG //sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); - /* DEBUG + // resolve all the classes in the source references for( Token token : index.referenceTokens() ) { - EntryReference reference = index.getDeobfReference( token ); - System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) ); + EntryReference deobfReference = index.getDeobfReference( token ); + + // get the obfuscated entry + Entry obfEntry = obfuscateEntry( deobfReference.entry ); + + // try to resolve the class + ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( obfEntry ); + if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( obfEntry.getClassEntry() ) ) + { + // change the class of the entry + obfEntry = obfEntry.cloneToNewClass( resolvedObfClassEntry ); + + // save the new deobfuscated reference + deobfReference.entry = deobfuscateEntry( obfEntry ); + index.replaceDeobfReference( token, deobfReference ); + } + + // DEBUG + //System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) ); } - */ return index; } @@ -486,13 +551,6 @@ public class Deobfuscator public boolean isObfuscatedIdentifier( Entry obfEntry ) { - if( obfEntry instanceof ClassEntry ) - { - return m_jarIndex.getObfClassEntries().contains( obfEntry ); - } - else - { - return isObfuscatedIdentifier( obfEntry.getClassEntry() ); - } + return m_jarIndex.containsObfEntry( obfEntry ); } } diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java index b82b2547..44e0220c 100644 --- a/src/cuchaz/enigma/analysis/EntryRenamer.java +++ b/src/cuchaz/enigma/analysis/EntryRenamer.java @@ -117,7 +117,7 @@ public class EntryRenamer { ArgumentEntry argumentEntry = (ArgumentEntry)thing; return (T)new ArgumentEntry( - renameMethodsInThing( renames, argumentEntry.getMethodEntry() ), + renameMethodsInThing( renames, argumentEntry.getBehaviorEntry() ), argumentEntry.getIndex(), argumentEntry.getName() ); @@ -177,7 +177,7 @@ public class EntryRenamer { ArgumentEntry argumentEntry = (ArgumentEntry)thing; return (T)new ArgumentEntry( - renameClassesInThing( renames, argumentEntry.getMethodEntry() ), + renameClassesInThing( renames, argumentEntry.getBehaviorEntry() ), argumentEntry.getIndex(), argumentEntry.getName() ); diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index b51428a2..9f309cec 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -42,6 +42,7 @@ import com.google.common.collect.Sets; import cuchaz.enigma.Constants; import cuchaz.enigma.bytecode.ClassRenamer; +import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; @@ -264,7 +265,15 @@ public class JarIndex call.getMethodName(), call.getSignature() ); - calledMethodEntry = resolveMethodClass( calledMethodEntry ); + ClassEntry resolvedClassEntry = resolveEntryClass( calledMethodEntry ); + if( resolvedClassEntry != null && !resolvedClassEntry.equals( calledMethodEntry.getClassEntry() ) ) + { + calledMethodEntry = new MethodEntry( + resolvedClassEntry, + call.getMethodName(), + call.getSignature() + ); + } EntryReference reference = new EntryReference( calledMethodEntry, behaviorEntry @@ -280,6 +289,14 @@ public class JarIndex new ClassEntry( className ), call.getFieldName() ); + ClassEntry resolvedClassEntry = resolveEntryClass( calledFieldEntry ); + if( resolvedClassEntry != null && !resolvedClassEntry.equals( calledFieldEntry.getClassEntry() ) ) + { + calledFieldEntry = new FieldEntry( + resolvedClassEntry, + call.getFieldName() + ); + } EntryReference reference = new EntryReference( calledFieldEntry, behaviorEntry @@ -355,30 +372,26 @@ public class JarIndex throw new IllegalArgumentException( "behavior must be a method or a constructor!" ); } } - - private MethodEntry resolveMethodClass( MethodEntry methodEntry ) + + public ClassEntry resolveEntryClass( Entry obfEntry ) { // this entry could refer to a method on a class where the method is not actually implemented // travel up the inheritance tree to find the closest implementation - while( !isMethodImplemented( methodEntry ) ) + while( !containsObfEntry( obfEntry ) ) { // is there a parent class? - String superclassName = m_translationIndex.getSuperclassName( methodEntry.getClassName() ); + String superclassName = m_translationIndex.getSuperclassName( obfEntry.getClassName() ); if( superclassName == null ) { // this is probably a method from a class in a library // we can't trace the implementation up any higher unless we index the library - return methodEntry; + return null; } // move up to the parent class - methodEntry = new MethodEntry( - new ClassEntry( superclassName ), - methodEntry.getName(), - methodEntry.getSignature() - ); + obfEntry = obfEntry.cloneToNewClass( new ClassEntry( superclassName ) ); } - return methodEntry; + return obfEntry.getClassEntry(); } private CtMethod getBridgedMethod( CtMethod method ) @@ -704,16 +717,6 @@ public class JarIndex return m_fieldClasses.get( fieldEntry ); } - public boolean isMethodImplemented( MethodEntry methodEntry ) - { - Collection implementations = m_methodImplementations.get( methodEntry.getClassName() ); - if( implementations == null ) - { - return false; - } - return implementations.contains( methodEntry ); - } - public ClassInheritanceTreeNode getClassInheritance( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) { // get the root node @@ -751,7 +754,7 @@ public class JarIndex obfMethodEntry.getName(), obfMethodEntry.getSignature() ); - if( isMethodImplemented( ancestorMethodEntry ) ) + if( containsObfBehavior( ancestorMethodEntry ) ) { baseImplementationClassName = ancestorClassName; } @@ -766,7 +769,7 @@ public class JarIndex MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode( deobfuscatingTranslator, methodEntry, - isMethodImplemented( methodEntry ) + containsObfBehavior( methodEntry ) ); // expand the full tree @@ -796,7 +799,7 @@ public class JarIndex obfMethodEntry.getName(), obfMethodEntry.getSignature() ); - if( isMethodImplemented( methodInterface ) ) + if( containsObfBehavior( methodInterface ) ) { methodInterfaces.add( methodInterface ); } @@ -827,7 +830,7 @@ public class JarIndex private void getRelatedMethodImplementations( Set methodEntries, MethodInheritanceTreeNode node ) { MethodEntry methodEntry = node.getMethodEntry(); - if( isMethodImplemented( methodEntry ) ) + if( containsObfBehavior( methodEntry ) ) { // collect the entry methodEntries.add( methodEntry ); @@ -850,7 +853,7 @@ public class JarIndex private void getRelatedMethodImplementations( Set methodEntries, MethodImplementationsTreeNode node ) { MethodEntry methodEntry = node.getMethodEntry(); - if( isMethodImplemented( methodEntry ) ) + if( containsObfBehavior( methodEntry ) ) { // collect the entry methodEntries.add( methodEntry ); @@ -969,8 +972,49 @@ public class JarIndex return m_access.containsKey( obfFieldEntry ); } - public boolean containsObfMethod( MethodEntry obfMethodEntry ) + public boolean containsObfBehavior( BehaviorEntry obfBehaviorEntry ) + { + return m_access.containsKey( obfBehaviorEntry ); + } + + public boolean containsObfArgument( ArgumentEntry obfArgumentEntry ) + { + // check the behavior + if( !containsObfBehavior( obfArgumentEntry.getBehaviorEntry() ) ) + { + return false; + } + + // check the argument + if( obfArgumentEntry.getIndex() >= Descriptor.numOfParameters( obfArgumentEntry.getBehaviorEntry().getSignature() ) ) + { + return false; + } + + return true; + } + + public boolean containsObfEntry( Entry obfEntry ) { - return m_access.containsKey( obfMethodEntry ); + if( obfEntry instanceof ClassEntry ) + { + return containsObfClass( (ClassEntry)obfEntry ); + } + else if( obfEntry instanceof FieldEntry ) + { + return containsObfField( (FieldEntry)obfEntry ); + } + else if( obfEntry instanceof BehaviorEntry ) + { + return containsObfBehavior( (BehaviorEntry)obfEntry ); + } + else if( obfEntry instanceof ArgumentEntry ) + { + return containsObfArgument( (ArgumentEntry)obfEntry ); + } + else + { + throw new Error( "Entry type not supported: " + obfEntry.getClass().getName() ); + } } } diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java index 8b9dd2d8..a050282b 100644 --- a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java @@ -81,7 +81,7 @@ public class MethodImplementationsTreeNode extends DefaultMutableTreeNode m_entry.getName(), m_entry.getSignature() ); - if( index.isMethodImplemented( methodEntry ) ) + if( index.containsObfBehavior( methodEntry ) ) { nodes.add( new MethodImplementationsTreeNode( m_deobfuscatingTranslator, methodEntry ) ); } diff --git a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java index d77fd858..bd919518 100644 --- a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java @@ -93,7 +93,7 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode nodes.add( new MethodInheritanceTreeNode( m_deobfuscatingTranslator, methodEntry, - index.isMethodImplemented( methodEntry ) + index.containsObfBehavior( methodEntry ) ) ); } diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 49451b90..a5d1460f 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -126,6 +126,15 @@ public class SourceIndex return m_tokenToReference.get( token ); } + public void replaceDeobfReference( Token token, EntryReference newDeobfReference ) + { + EntryReference oldDeobfReference = m_tokenToReference.get( token ); + m_tokenToReference.put( token, newDeobfReference ); + Collection tokens = m_referenceToTokens.get( oldDeobfReference ); + m_referenceToTokens.removeAll( oldDeobfReference ); + m_referenceToTokens.putAll( newDeobfReference, tokens ); + } + public Iterable referenceTokens( ) { return m_tokenToReference.keySet(); diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java index 6238b1e7..f307c11d 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java @@ -116,6 +116,12 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); if( ref != null ) { + // make sure this is actually a field + if( ref.getSignature().indexOf( '(' ) >= 0 ) + { + throw new Error( "Expected a field here! got " + ref ); + } + ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); index.addReference( @@ -149,8 +155,16 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor ParameterDefinition def = node.getUserData( Keys.PARAMETER_DEFINITION ); ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); MethodDefinition methodDef = (MethodDefinition)def.getMethod(); - MethodEntry methodEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() ); - ArgumentEntry argumentEntry = new ArgumentEntry( methodEntry, def.getPosition(), def.getName() ); + BehaviorEntry behaviorEntry; + if( methodDef.isConstructor() ) + { + behaviorEntry = new ConstructorEntry( classEntry, methodDef.getSignature() ); + } + else + { + behaviorEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() ); + } + ArgumentEntry argumentEntry = new ArgumentEntry( behaviorEntry, def.getPosition(), def.getName() ); index.addDeclaration( node.getNameToken(), argumentEntry ); return recurse( node, index ); diff --git a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java index a8d3983f..adea7eae 100644 --- a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java +++ b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java @@ -15,9 +15,13 @@ import java.util.List; import javassist.CtBehavior; import javassist.CtClass; +import javassist.CtConstructor; +import javassist.CtMethod; import javassist.bytecode.Descriptor; import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.Translator; @@ -42,12 +46,26 @@ public class MethodParameterWriter continue; } + // get the behavior entry + BehaviorEntry behaviorEntry; + if( behavior instanceof CtMethod ) + { + behaviorEntry = new MethodEntry( classEntry, behavior.getMethodInfo().getName(), behavior.getSignature() ); + } + else if( behavior instanceof CtConstructor ) + { + behaviorEntry = new ConstructorEntry( classEntry, behavior.getSignature() ); + } + else + { + throw new Error( "Unsupported behavior type: " + behavior.getClass().getName() ); + } + // get the list of parameter names - MethodEntry methodEntry = new MethodEntry( classEntry, behavior.getMethodInfo().getName(), behavior.getSignature() ); List names = new ArrayList( numParams ); for( int i=0; i fallbackMatching = Maps.newHashMap(); @@ -271,7 +271,7 @@ public class ClassMatcher methodMapping.getObfName(), methodMapping.getObfSignature() ); - if( !destIndex.isMethodImplemented( methodEntry ) ) + if( !destIndex.containsObfBehavior( methodEntry ) ) { System.err.println( "WARNING: method doesn't match: " + methodEntry ); diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 5eed728a..1f04aa35 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -229,27 +229,27 @@ public class Gui switch( event.getKeyCode() ) { case KeyEvent.VK_R: - startRename(); + m_renameMenu.doClick(); break; case KeyEvent.VK_I: - showInheritance(); + m_showInheritanceMenu.doClick(); break; case KeyEvent.VK_M: - showImplementations(); + m_showImplementationsMenu.doClick(); break; case KeyEvent.VK_N: - navigateTo( m_reference.entry ); + m_openEntryMenu.doClick(); break; case KeyEvent.VK_P: - m_controller.openPreviousReference(); + m_openPreviousMenu.doClick(); break; case KeyEvent.VK_C: - showCalls(); + m_showCallsMenu.doClick(); break; } } @@ -987,7 +987,7 @@ public class Gui { addNameValue( m_infoPanel, "Argument", entry.getName() ); addNameValue( m_infoPanel, "Class", entry.getClassEntry().getName() ); - addNameValue( m_infoPanel, "Method", entry.getMethodEntry().getName() ); + addNameValue( m_infoPanel, "Method", entry.getBehaviorEntry().getName() ); addNameValue( m_infoPanel, "Index", Integer.toString( entry.getIndex() ) ); } @@ -1014,7 +1014,7 @@ public class Gui boolean isFieldEntry = isToken && m_reference.entry instanceof FieldEntry; boolean isMethodEntry = isToken && m_reference.entry instanceof MethodEntry; boolean isConstructorEntry = isToken && m_reference.entry instanceof ConstructorEntry; - boolean isInJar = isToken && m_controller.entryIsInJar( m_reference.entry.getClassEntry() ); + boolean isInJar = isToken && m_controller.entryIsInJar( m_reference.entry ); if( isToken ) { diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index bbefe606..098e065d 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -270,7 +270,7 @@ public class GuiController ClassEntry obfClassEntry = obfReference.getClassEntry().getOuterClassEntry(); if( !m_deobfuscator.isObfuscatedIdentifier( obfClassEntry ) ) { - throw new IllegalArgumentException( "Entry must be in the jar!" ); + throw new IllegalArgumentException( "Obfuscated class " + obfClassEntry + " was not found in the jar!" ); } if( m_currentObfClass == null || !m_currentObfClass.equals( obfClassEntry ) ) { @@ -354,6 +354,7 @@ public class GuiController if( sourceTree == null ) { // decompilation of this class is not supported + m_gui.setSource("Unable to find class: " + classEntry); return; } String source = m_deobfuscator.getSource( sourceTree ); diff --git a/src/cuchaz/enigma/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java index 27dcc41d..7ed3d328 100644 --- a/src/cuchaz/enigma/mapping/ArgumentEntry.java +++ b/src/cuchaz/enigma/mapping/ArgumentEntry.java @@ -18,15 +18,15 @@ public class ArgumentEntry implements Entry, Serializable { private static final long serialVersionUID = 4472172468162696006L; - private MethodEntry m_methodEntry; + private BehaviorEntry m_behaviorEntry; private int m_index; private String m_name; - public ArgumentEntry( MethodEntry methodEntry, int index, String name ) + public ArgumentEntry( BehaviorEntry behaviorEntry, int index, String name ) { - if( methodEntry == null ) + if( behaviorEntry == null ) { - throw new IllegalArgumentException( "Method cannot be null!" ); + throw new IllegalArgumentException( "Behavior cannot be null!" ); } if( index < 0 ) { @@ -37,21 +37,28 @@ public class ArgumentEntry implements Entry, Serializable throw new IllegalArgumentException( "Argument name cannot be null!" ); } - m_methodEntry = methodEntry; + m_behaviorEntry = behaviorEntry; m_index = index; m_name = name; } public ArgumentEntry( ArgumentEntry other ) { - m_methodEntry = new MethodEntry( other.m_methodEntry ); + m_behaviorEntry = (BehaviorEntry)m_behaviorEntry.cloneToNewClass( getClassEntry() ); m_index = other.m_index; m_name = other.m_name; } - public MethodEntry getMethodEntry( ) + public ArgumentEntry( ArgumentEntry other, String newClassName ) { - return m_methodEntry; + m_behaviorEntry = (BehaviorEntry)other.m_behaviorEntry.cloneToNewClass( new ClassEntry( newClassName ) ); + m_index = other.m_index; + m_name = other.m_name; + } + + public BehaviorEntry getBehaviorEntry( ) + { + return m_behaviorEntry; } public int getIndex( ) @@ -68,29 +75,35 @@ public class ArgumentEntry implements Entry, Serializable @Override public ClassEntry getClassEntry( ) { - return m_methodEntry.getClassEntry(); + return m_behaviorEntry.getClassEntry(); } @Override public String getClassName( ) { - return m_methodEntry.getClassName(); + return m_behaviorEntry.getClassName(); + } + + @Override + public ArgumentEntry cloneToNewClass( ClassEntry classEntry ) + { + return new ArgumentEntry( this, classEntry.getName() ); } public String getMethodName( ) { - return m_methodEntry.getName(); + return m_behaviorEntry.getName(); } public String getMethodSignature( ) { - return m_methodEntry.getSignature(); + return m_behaviorEntry.getSignature(); } @Override public int hashCode( ) { - return Util.combineHashesOrdered( m_methodEntry, Integer.valueOf( m_index ).hashCode(), m_name.hashCode() ); + return Util.combineHashesOrdered( m_behaviorEntry, Integer.valueOf( m_index ).hashCode(), m_name.hashCode() ); } @Override @@ -105,7 +118,7 @@ public class ArgumentEntry implements Entry, Serializable public boolean equals( ArgumentEntry other ) { - return m_methodEntry.equals( other.m_methodEntry ) + return m_behaviorEntry.equals( other.m_behaviorEntry ) && m_index == other.m_index && m_name.equals( other.m_name ); } @@ -113,6 +126,6 @@ public class ArgumentEntry implements Entry, Serializable @Override public String toString( ) { - return m_methodEntry.toString() + "(" + m_index + ":" + m_name + ")"; + return m_behaviorEntry.toString() + "(" + m_index + ":" + m_name + ")"; } } diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index c6faa506..2c708f2a 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java @@ -43,12 +43,6 @@ public class ClassEntry implements Entry, Serializable m_name = other.m_name; } - @Override - public ClassEntry getClassEntry( ) - { - return this; - } - @Override public String getName( ) { @@ -61,6 +55,18 @@ public class ClassEntry implements Entry, Serializable return m_name; } + @Override + public ClassEntry getClassEntry( ) + { + return this; + } + + @Override + public ClassEntry cloneToNewClass( ClassEntry classEntry ) + { + return classEntry; + } + @Override public int hashCode( ) { diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index 88006cff..b551d71c 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -139,6 +139,16 @@ public class ClassMapping implements Serializable, Comparable return m_fieldsByObf.values(); } + public boolean containsObfField( String obfName ) + { + return m_fieldsByObf.containsKey( obfName ); + } + + public boolean containsDeobfField( String deobfName ) + { + return m_fieldsByDeobf.containsKey( deobfName ); + } + public void addFieldMapping( FieldMapping fieldMapping ) { if( m_fieldsByObf.containsKey( fieldMapping.getObfName() ) ) @@ -214,6 +224,16 @@ public class ClassMapping implements Serializable, Comparable return m_methodsByObf.values(); } + public boolean containsObfMethod( String obfName, String obfSignature ) + { + return m_methodsByObf.containsKey( getMethodKey( obfName, obfSignature ) ); + } + + public boolean containsDeobfMethod( String deobfName, String deobfSignature ) + { + return m_methodsByDeobf.containsKey( getMethodKey( deobfName, deobfSignature ) ); + } + public void addMethodMapping( MethodMapping methodMapping ) { String obfKey = getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ); @@ -375,19 +395,9 @@ public class ClassMapping implements Serializable, Comparable return false; } - public boolean containsDeobfField( String name ) - { - return m_fieldsByDeobf.containsKey( name ); - } - - public boolean containsDeobfMethod( String name, String signature ) - { - return m_methodsByDeobf.containsKey( getMethodKey( name, signature ) ); - } - - public boolean containsArgument( MethodEntry obfMethodEntry, String name ) + public boolean containsArgument( BehaviorEntry obfBehaviorEntry, String name ) { - MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfMethodEntry.getName(), obfMethodEntry.getSignature() ) ); + MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature() ) ); if( methodMapping != null ) { return methodMapping.containsArgument( name ); diff --git a/src/cuchaz/enigma/mapping/ConstructorEntry.java b/src/cuchaz/enigma/mapping/ConstructorEntry.java index ad029e1c..d99d1c35 100644 --- a/src/cuchaz/enigma/mapping/ConstructorEntry.java +++ b/src/cuchaz/enigma/mapping/ConstructorEntry.java @@ -43,6 +43,12 @@ public class ConstructorEntry implements BehaviorEntry, Serializable m_signature = other.m_signature; } + public ConstructorEntry( ConstructorEntry other, String newClassName ) + { + m_classEntry = new ClassEntry( newClassName ); + m_signature = other.m_signature; + } + @Override public ClassEntry getClassEntry( ) { @@ -76,6 +82,12 @@ public class ConstructorEntry implements BehaviorEntry, Serializable return m_classEntry.getName(); } + @Override + public ConstructorEntry cloneToNewClass( ClassEntry classEntry ) + { + return new ConstructorEntry( this, classEntry.getName() ); + } + @Override public int hashCode( ) { diff --git a/src/cuchaz/enigma/mapping/Entry.java b/src/cuchaz/enigma/mapping/Entry.java index e1591f02..8524834c 100644 --- a/src/cuchaz/enigma/mapping/Entry.java +++ b/src/cuchaz/enigma/mapping/Entry.java @@ -15,4 +15,5 @@ public interface Entry String getName( ); String getClassName( ); ClassEntry getClassEntry( ); + Entry cloneToNewClass( ClassEntry classEntry ); } diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java index 435490bd..626af576 100644 --- a/src/cuchaz/enigma/mapping/FieldEntry.java +++ b/src/cuchaz/enigma/mapping/FieldEntry.java @@ -67,6 +67,12 @@ public class FieldEntry implements Entry, Serializable return m_classEntry.getName(); } + @Override + public FieldEntry cloneToNewClass( ClassEntry classEntry ) + { + return new FieldEntry( this, classEntry.getName() ); + } + @Override public int hashCode( ) { diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index f855f580..0b4e7f3c 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -253,12 +253,12 @@ public class Mappings implements Serializable return false; } - public boolean containsArgument( MethodEntry obfMethodEntry, String name ) + public boolean containsArgument( BehaviorEntry obfBehaviorEntry, String name ) { - ClassMapping classMapping = m_classesByObf.get( obfMethodEntry.getClassName() ); + ClassMapping classMapping = m_classesByObf.get( obfBehaviorEntry.getClassName() ); if( classMapping != null ) { - return classMapping.containsArgument( obfMethodEntry, name ); + return classMapping.containsArgument( obfBehaviorEntry, name ); } return false; } diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index 49e7b5fd..dcceefbd 100644 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -79,7 +79,7 @@ public class MappingsRenamer { String deobfSignature = getTranslator( TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); MethodEntry targetEntry = new MethodEntry( entry.getClassEntry(), deobfName, deobfSignature ); - if( m_mappings.containsDeobfMethod( entry.getClassEntry(), deobfName, entry.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) + if( m_mappings.containsDeobfMethod( entry.getClassEntry(), deobfName, entry.getSignature() ) || m_index.containsObfBehavior( targetEntry ) ) { String deobfClassName = getTranslator( TranslationDirection.Deobfuscating ).translateClass( entry.getClassName() ); throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + deobfClassName ); @@ -96,7 +96,7 @@ public class MappingsRenamer { deobfName = NameValidator.validateMethodName( deobfName ); MethodEntry targetEntry = new MethodEntry( obf.getClassEntry(), deobfName, obf.getSignature() ); - if( m_mappings.containsDeobfMethod( obf.getClassEntry(), deobfName, obf.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) + if( m_mappings.containsDeobfMethod( obf.getClassEntry(), deobfName, obf.getSignature() ) || m_index.containsObfBehavior( targetEntry ) ) { String deobfClassName = getTranslator( TranslationDirection.Deobfuscating ).translateClass( obf.getClassName() ); throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + deobfClassName ); @@ -110,7 +110,7 @@ public class MappingsRenamer { deobfName = NameValidator.validateArgumentName( deobfName ); // NOTE: don't need to check arguments for name collisions with names determined by Procyon - if( m_mappings.containsArgument( obf.getMethodEntry(), deobfName ) ) + if( m_mappings.containsArgument( obf.getBehaviorEntry(), deobfName ) ) { throw new IllegalNameException( deobfName, "There is already an argument with that name" ); } @@ -119,6 +119,32 @@ public class MappingsRenamer classMapping.setArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName ); } + public boolean moveFieldToObfClass( ClassMapping classMapping, FieldMapping fieldMapping, ClassEntry obfClass ) + { + classMapping.removeFieldMapping( fieldMapping ); + ClassMapping targetClassMapping = getOrCreateClassMapping( obfClass ); + if( !targetClassMapping.containsObfField( fieldMapping.getObfName() ) + && !targetClassMapping.containsDeobfField( fieldMapping.getDeobfName() ) ) + { + targetClassMapping.addFieldMapping( fieldMapping ); + return true; + } + return false; + } + + public boolean moveMethodToObfClass( ClassMapping classMapping, MethodMapping methodMapping, ClassEntry obfClass ) + { + classMapping.removeMethodMapping( methodMapping ); + ClassMapping targetClassMapping = getOrCreateClassMapping( obfClass ); + if( !targetClassMapping.containsObfMethod( methodMapping.getObfName(), methodMapping.getObfSignature() ) + && !targetClassMapping.containsDeobfMethod( methodMapping.getDeobfName(), methodMapping.getObfSignature() ) ) + { + targetClassMapping.addMethodMapping( methodMapping ); + return true; + } + return false; + } + public void write( OutputStream out ) throws IOException { diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java index a311e636..8adbfe9c 100644 --- a/src/cuchaz/enigma/mapping/MethodEntry.java +++ b/src/cuchaz/enigma/mapping/MethodEntry.java @@ -80,6 +80,12 @@ public class MethodEntry implements BehaviorEntry, Serializable return m_classEntry.getName(); } + @Override + public MethodEntry cloneToNewClass( ClassEntry classEntry ) + { + return new MethodEntry( this, classEntry.getName() ); + } + @Override public int hashCode( ) { diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index b438e08d..7904ef53 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -271,7 +271,7 @@ public class Translator name = in.getName(); } return new ArgumentEntry( - translateEntry( in.getMethodEntry() ), + translateEntry( in.getBehaviorEntry() ), in.getIndex(), name ); -- cgit v1.2.3