From 959cb5fd4f9586ec3bd265b452fe25fe1db82e3f Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 13 Jan 2015 23:25:04 -0500 Subject: source format change don't hate me too much if you were planning a big merge. =P --- src/cuchaz/enigma/analysis/JarIndex.java | 820 +++++++++++++------------------ 1 file changed, 336 insertions(+), 484 deletions(-) (limited to 'src/cuchaz/enigma/analysis/JarIndex.java') diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 0954564..4b03a33 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -53,8 +53,8 @@ import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.SignatureUpdater; import cuchaz.enigma.mapping.Translator; -public class JarIndex -{ +public class JarIndex { + private Set m_obfClassEntries; private TranslationIndex m_translationIndex; private Multimap m_interfaces; @@ -68,8 +68,7 @@ public class JarIndex private Map m_anonymousClasses; private Map m_bridgeMethods; - public JarIndex( ) - { + public JarIndex() { m_obfClassEntries = Sets.newHashSet(); m_translationIndex = new TranslationIndex(); m_interfaces = HashMultimap.create(); @@ -84,192 +83,161 @@ public class JarIndex m_bridgeMethods = Maps.newHashMap(); } - public void indexJar( JarFile jar, boolean buildInnerClasses ) - { + public void indexJar(JarFile jar, boolean buildInnerClasses) { // step 1: read the class names - for( ClassEntry classEntry : JarClassIterator.getClassEntries( jar ) ) - { - if( classEntry.isInDefaultPackage() ) - { + for (ClassEntry classEntry : JarClassIterator.getClassEntries(jar)) { + if (classEntry.isInDefaultPackage()) { // move out of default package - classEntry = new ClassEntry( Constants.NonePackage + "/" + classEntry.getName() ); + classEntry = new ClassEntry(Constants.NonePackage + "/" + classEntry.getName()); } - m_obfClassEntries.add( classEntry ); + m_obfClassEntries.add(classEntry); } // step 2: index field/method/constructor access - for( CtClass c : JarClassIterator.classes( jar ) ) - { - ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); - ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); - for( CtField field : c.getDeclaredFields() ) - { - FieldEntry fieldEntry = new FieldEntry( classEntry, field.getName() ); - m_access.put( fieldEntry, Access.get( field ) ); + for (CtClass c : JarClassIterator.classes(jar)) { + ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); + ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); + for (CtField field : c.getDeclaredFields()) { + FieldEntry fieldEntry = new FieldEntry(classEntry, field.getName()); + m_access.put(fieldEntry, Access.get(field)); } - for( CtMethod method : c.getDeclaredMethods() ) - { - MethodEntry methodEntry = new MethodEntry( classEntry, method.getName(), method.getSignature() ); - m_access.put( methodEntry, Access.get( method ) ); + for (CtMethod method : c.getDeclaredMethods()) { + MethodEntry methodEntry = new MethodEntry(classEntry, method.getName(), method.getSignature()); + m_access.put(methodEntry, Access.get(method)); } - for( CtConstructor constructor : c.getDeclaredConstructors() ) - { - ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getSignature() ); - m_access.put( constructorEntry, Access.get( constructor ) ); + for (CtConstructor constructor : c.getDeclaredConstructors()) { + ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, constructor.getSignature()); + m_access.put(constructorEntry, Access.get(constructor)); } } // step 3: index extends, implements, fields, and methods - for( CtClass c : JarClassIterator.classes( jar ) ) - { - ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); - String className = Descriptor.toJvmName( c.getName() ); - m_translationIndex.addSuperclass( className, Descriptor.toJvmName( c.getClassFile().getSuperclass() ) ); - for( String interfaceName : c.getClassFile().getInterfaces() ) - { - className = Descriptor.toJvmName( className ); - interfaceName = Descriptor.toJvmName( interfaceName ); - if( className.equals( interfaceName ) ) - { - throw new IllegalArgumentException( "Class cannot be its own interface! " + className ); + for (CtClass c : JarClassIterator.classes(jar)) { + ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); + String className = Descriptor.toJvmName(c.getName()); + m_translationIndex.addSuperclass(className, Descriptor.toJvmName(c.getClassFile().getSuperclass())); + for (String interfaceName : c.getClassFile().getInterfaces()) { + className = Descriptor.toJvmName(className); + interfaceName = Descriptor.toJvmName(interfaceName); + if (className.equals(interfaceName)) { + throw new IllegalArgumentException("Class cannot be its own interface! " + className); } - m_interfaces.put( className, interfaceName ); + m_interfaces.put(className, interfaceName); } - for( CtField field : c.getDeclaredFields() ) - { - indexField( field ); + for (CtField field : c.getDeclaredFields()) { + indexField(field); } - for( CtBehavior behavior : c.getDeclaredBehaviors() ) - { - indexBehavior( behavior ); + for (CtBehavior behavior : c.getDeclaredBehaviors()) { + indexBehavior(behavior); } } // step 4: index field, method, constructor references - for( CtClass c : JarClassIterator.classes( jar ) ) - { - ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); - for( CtBehavior behavior : c.getDeclaredBehaviors() ) - { - indexBehaviorReferences( behavior ); + for (CtClass c : JarClassIterator.classes(jar)) { + ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); + for (CtBehavior behavior : c.getDeclaredBehaviors()) { + indexBehaviorReferences(behavior); } } - if( buildInnerClasses ) - { + if (buildInnerClasses) { // step 5: index inner classes and anonymous classes - for( CtClass c : JarClassIterator.classes( jar ) ) - { - ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); - String outerClassName = findOuterClass( c ); - if( outerClassName != null ) - { + for (CtClass c : JarClassIterator.classes(jar)) { + ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); + String outerClassName = findOuterClass(c); + if (outerClassName != null) { String innerClassName = c.getSimpleName(); - m_innerClasses.put( outerClassName, innerClassName ); - boolean innerWasAdded = m_outerClasses.put( innerClassName, outerClassName ) == null; - assert( innerWasAdded ); + m_innerClasses.put(outerClassName, innerClassName); + boolean innerWasAdded = m_outerClasses.put(innerClassName, outerClassName) == null; + assert (innerWasAdded); - BehaviorEntry enclosingBehavior = isAnonymousClass( c, outerClassName ); - if( enclosingBehavior != null ) - { - m_anonymousClasses.put( innerClassName, enclosingBehavior ); + BehaviorEntry enclosingBehavior = isAnonymousClass(c, outerClassName); + if (enclosingBehavior != null) { + m_anonymousClasses.put(innerClassName, enclosingBehavior); // DEBUG - //System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); - } - else - { + // System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); + } else { // DEBUG - //System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); + // System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); } } } // step 6: update other indices with inner class info Map renames = Maps.newHashMap(); - for( Map.Entry entry : m_outerClasses.entrySet() ) - { - renames.put( Constants.NonePackage + "/" + entry.getKey(), entry.getValue() + "$" + entry.getKey() ); + for (Map.Entry entry : m_outerClasses.entrySet()) { + renames.put(Constants.NonePackage + "/" + entry.getKey(), entry.getValue() + "$" + entry.getKey()); } - EntryRenamer.renameClassesInSet( renames, m_obfClassEntries ); - m_translationIndex.renameClasses( renames ); - EntryRenamer.renameClassesInMultimap( renames, m_interfaces ); - EntryRenamer.renameClassesInMultimap( renames, m_methodImplementations ); - EntryRenamer.renameClassesInMultimap( renames, m_behaviorReferences ); - EntryRenamer.renameClassesInMultimap( renames, m_fieldReferences ); - EntryRenamer.renameClassesInMap( renames, m_bridgeMethods ); - EntryRenamer.renameClassesInMap( renames, m_access ); + EntryRenamer.renameClassesInSet(renames, m_obfClassEntries); + m_translationIndex.renameClasses(renames); + EntryRenamer.renameClassesInMultimap(renames, m_interfaces); + EntryRenamer.renameClassesInMultimap(renames, m_methodImplementations); + EntryRenamer.renameClassesInMultimap(renames, m_behaviorReferences); + EntryRenamer.renameClassesInMultimap(renames, m_fieldReferences); + EntryRenamer.renameClassesInMap(renames, m_bridgeMethods); + EntryRenamer.renameClassesInMap(renames, m_access); } // step 6: update other indices with bridge method info - EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_methodImplementations ); - EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_behaviorReferences ); - EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_fieldReferences ); - EntryRenamer.renameMethodsInMap( m_bridgeMethods, m_access ); + 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 ) - { + private void indexField(CtField field) { // get the field entry - String className = Descriptor.toJvmName( field.getDeclaringClass().getName() ); - FieldEntry fieldEntry = new FieldEntry( new ClassEntry( className ), field.getName() ); + String className = Descriptor.toJvmName(field.getDeclaringClass().getName()); + FieldEntry fieldEntry = new FieldEntry(new ClassEntry(className), field.getName()); - m_translationIndex.addField( className, field.getName() ); + m_translationIndex.addField(className, field.getName()); // is the field a class type? - if( field.getSignature().startsWith( "L" ) ) - { - ClassEntry fieldTypeEntry = new ClassEntry( field.getSignature().substring( 1, field.getSignature().length() - 1 ) ); - m_fieldClasses.put( fieldEntry, fieldTypeEntry ); + if (field.getSignature().startsWith("L")) { + ClassEntry fieldTypeEntry = new ClassEntry(field.getSignature().substring(1, field.getSignature().length() - 1)); + m_fieldClasses.put(fieldEntry, fieldTypeEntry); } } - - private void indexBehavior( CtBehavior behavior ) - { + + private void indexBehavior(CtBehavior behavior) { // get the behavior entry - final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( behavior ); - if( behaviorEntry instanceof MethodEntry ) - { + final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior); + if (behaviorEntry instanceof MethodEntry) { MethodEntry methodEntry = (MethodEntry)behaviorEntry; // index implementation - m_methodImplementations.put( behaviorEntry.getClassName(), methodEntry ); + m_methodImplementations.put(behaviorEntry.getClassName(), methodEntry); // look for bridge methods - CtMethod bridgedMethod = getBridgedMethod( (CtMethod)behavior ); - if( bridgedMethod != null ) - { + CtMethod bridgedMethod = getBridgedMethod((CtMethod)behavior); + if (bridgedMethod != null) { MethodEntry bridgedMethodEntry = new MethodEntry( behaviorEntry.getClassEntry(), bridgedMethod.getName(), bridgedMethod.getSignature() ); - m_bridgeMethods.put( bridgedMethodEntry, methodEntry ); + m_bridgeMethods.put(bridgedMethodEntry, methodEntry); } } // looks like we don't care about constructors here } - private void indexBehaviorReferences( CtBehavior behavior ) - { + private void indexBehaviorReferences(CtBehavior behavior) { // index method calls - final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( behavior ); - try - { - behavior.instrument( new ExprEditor( ) - { + final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior); + try { + behavior.instrument(new ExprEditor() { @Override - public void edit( MethodCall call ) - { - String className = Descriptor.toJvmName( call.getClassName() ); + public void edit(MethodCall call) { + String className = Descriptor.toJvmName(call.getClassName()); MethodEntry calledMethodEntry = new MethodEntry( - new ClassEntry( className ), + new ClassEntry(className), call.getMethodName(), call.getSignature() ); - ClassEntry resolvedClassEntry = resolveEntryClass( calledMethodEntry ); - if( resolvedClassEntry != null && !resolvedClassEntry.equals( calledMethodEntry.getClassEntry() ) ) - { + ClassEntry resolvedClassEntry = resolveEntryClass(calledMethodEntry); + if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledMethodEntry.getClassEntry())) { calledMethodEntry = new MethodEntry( resolvedClassEntry, call.getMethodName(), @@ -281,39 +249,33 @@ public class JarIndex call.getMethodName(), behaviorEntry ); - m_behaviorReferences.put( calledMethodEntry, reference ); + m_behaviorReferences.put(calledMethodEntry, reference); } @Override - public void edit( FieldAccess call ) - { - String className = Descriptor.toJvmName( call.getClassName() ); + public void edit(FieldAccess call) { + String className = Descriptor.toJvmName(call.getClassName()); FieldEntry calledFieldEntry = new FieldEntry( - new ClassEntry( className ), + new ClassEntry(className), call.getFieldName() ); - ClassEntry resolvedClassEntry = resolveEntryClass( calledFieldEntry ); - if( resolvedClassEntry != null && !resolvedClassEntry.equals( calledFieldEntry.getClassEntry() ) ) - { - calledFieldEntry = new FieldEntry( - resolvedClassEntry, - call.getFieldName() - ); + ClassEntry resolvedClassEntry = resolveEntryClass(calledFieldEntry); + if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledFieldEntry.getClassEntry())) { + calledFieldEntry = new FieldEntry(resolvedClassEntry, call.getFieldName()); } EntryReference reference = new EntryReference( calledFieldEntry, call.getFieldName(), behaviorEntry ); - m_fieldReferences.put( calledFieldEntry, reference ); + m_fieldReferences.put(calledFieldEntry, reference); } @Override - public void edit( ConstructorCall call ) - { - String className = Descriptor.toJvmName( call.getClassName() ); + public void edit(ConstructorCall call) { + String className = Descriptor.toJvmName(call.getClassName()); ConstructorEntry calledConstructorEntry = new ConstructorEntry( - new ClassEntry( className ), + new ClassEntry(className), call.getSignature() ); EntryReference reference = new EntryReference( @@ -321,15 +283,14 @@ public class JarIndex call.getMethodName(), behaviorEntry ); - m_behaviorReferences.put( calledConstructorEntry, reference ); + m_behaviorReferences.put(calledConstructorEntry, reference); } @Override - public void edit( NewExpr call ) - { - String className = Descriptor.toJvmName( call.getClassName() ); + public void edit(NewExpr call) { + String className = Descriptor.toJvmName(call.getClassName()); ConstructorEntry calledConstructorEntry = new ConstructorEntry( - new ClassEntry( className ), + new ClassEntry(className), call.getSignature() ); EntryReference reference = new EntryReference( @@ -337,173 +298,141 @@ public class JarIndex call.getClassName(), behaviorEntry ); - m_behaviorReferences.put( calledConstructorEntry, reference ); + m_behaviorReferences.put(calledConstructorEntry, reference); } - } ); - } - catch( CannotCompileException ex ) - { - throw new Error( ex ); + }); + } catch (CannotCompileException ex) { + throw new Error(ex); } } - public ClassEntry resolveEntryClass( Entry obfEntry ) - { + 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( !containsObfEntry( obfEntry ) ) - { + while (!containsObfEntry(obfEntry)) { // is there a parent class? - String superclassName = m_translationIndex.getSuperclassName( obfEntry.getClassName() ); - if( superclassName == null ) - { + 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 null; } // move up to the parent class - obfEntry = obfEntry.cloneToNewClass( new ClassEntry( superclassName ) ); + obfEntry = obfEntry.cloneToNewClass(new ClassEntry(superclassName)); } return obfEntry.getClassEntry(); } - - private CtMethod getBridgedMethod( CtMethod 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 // skip non-synthetic methods - if( ( method.getModifiers() & AccessFlag.SYNTHETIC ) == 0 ) - { + if ( (method.getModifiers() & AccessFlag.SYNTHETIC) == 0) { return null; } - + // get all the called methods final List methodCalls = Lists.newArrayList(); - try - { - method.instrument( new ExprEditor( ) - { + try { + method.instrument(new ExprEditor() { @Override - public void edit( MethodCall call ) - { - methodCalls.add( call ); + public void edit(MethodCall call) { + methodCalls.add(call); } - } ); - } - catch( CannotCompileException ex ) - { + }); + } catch (CannotCompileException ex) { // this is stupid... we're not even compiling anything - throw new Error( ex ); + throw new Error(ex); } // is there just one? - if( methodCalls.size() != 1 ) - { + if (methodCalls.size() != 1) { return null; } - MethodCall call = methodCalls.get( 0 ); + MethodCall call = methodCalls.get(0); - try - { + try { // we have a bridge method! return call.getMethod(); - } - catch( NotFoundException ex ) - { + } catch (NotFoundException ex) { // can't find the type? not a bridge method return null; } } - private String findOuterClass( CtClass c ) - { + private String findOuterClass(CtClass c) { + // inner classes: - // have constructors that can (illegally) set synthetic fields - // the outer class is the only class that calls constructors + // have constructors that can (illegally) set synthetic fields + // the outer class is the only class that calls constructors // use the synthetic fields to find the synthetic constructors - for( CtConstructor constructor : c.getDeclaredConstructors() ) - { + for (CtConstructor constructor : c.getDeclaredConstructors()) { Set syntheticFieldTypes = Sets.newHashSet(); - if( !isIllegalConstructor( syntheticFieldTypes, constructor ) ) - { + if (!isIllegalConstructor(syntheticFieldTypes, constructor)) { continue; } - ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); - ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getMethodInfo().getDescriptor() ); + ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); + ConstructorEntry constructorEntry = new ConstructorEntry( + classEntry, + constructor.getMethodInfo().getDescriptor() + ); // gather the classes from the illegally-set synthetic fields Set illegallySetClasses = Sets.newHashSet(); - for( String type : syntheticFieldTypes ) - { - if( type.startsWith( "L" ) ) - { - ClassEntry outerClassEntry = new ClassEntry( type.substring( 1, type.length() - 1 ) ); - if( isSaneOuterClass( outerClassEntry, classEntry ) ) - { - illegallySetClasses.add( outerClassEntry ); + for (String type : syntheticFieldTypes) { + if (type.startsWith("L")) { + ClassEntry outerClassEntry = new ClassEntry(type.substring(1, type.length() - 1)); + if (isSaneOuterClass(outerClassEntry, classEntry)) { + illegallySetClasses.add(outerClassEntry); } } } // who calls this constructor? Set callerClasses = Sets.newHashSet(); - for( EntryReference reference : getBehaviorReferences( constructorEntry ) ) - { + for (EntryReference reference : getBehaviorReferences(constructorEntry)) { + // make sure it's not a call to super - if( reference.entry instanceof ConstructorEntry && reference.context instanceof ConstructorEntry ) - { + if (reference.entry instanceof ConstructorEntry && reference.context instanceof ConstructorEntry) { + // is the entry a superclass of the context? String calledClassName = reference.entry.getClassName(); - String callerSuperclassName = m_translationIndex.getSuperclassName( reference.context.getClassName() ); - if( callerSuperclassName != null && callerSuperclassName.equals( calledClassName ) ) - { + String callerSuperclassName = m_translationIndex.getSuperclassName(reference.context.getClassName()); + if (callerSuperclassName != null && callerSuperclassName.equals(calledClassName)) { // it's a super call, skip continue; } } - if( isSaneOuterClass( reference.context.getClassEntry(), classEntry ) ) - { - callerClasses.add( reference.context.getClassEntry() ); + if (isSaneOuterClass(reference.context.getClassEntry(), classEntry)) { + callerClasses.add(reference.context.getClassEntry()); } } // do we have an answer yet? - if( callerClasses.isEmpty() ) - { - if( illegallySetClasses.size() == 1 ) - { + if (callerClasses.isEmpty()) { + if (illegallySetClasses.size() == 1) { return illegallySetClasses.iterator().next().getName(); + } else { + System.out.println(String.format("WARNING: Unable to find outer class for %s. No caller and no illegally set field classes.", classEntry)); } - else - { - System.out.println( String.format( "WARNING: Unable to find outer class for %s. No caller and no illegally set field classes.", classEntry ) ); - } - } - else - { - if( callerClasses.size() == 1 ) - { + } else { + if (callerClasses.size() == 1) { return callerClasses.iterator().next().getName(); - } - else - { + } else { // multiple callers, do the illegally set classes narrow it down? - Set intersection = Sets.newHashSet( callerClasses ); - intersection.retainAll( illegallySetClasses ); - if( intersection.size() == 1 ) - { + Set intersection = Sets.newHashSet(callerClasses); + intersection.retainAll(illegallySetClasses); + if (intersection.size() == 1) { return intersection.iterator().next().getName(); - } - else - { - System.out.println( String.format( "WARNING: Unable to choose outer class for %s among options: %s", - classEntry, callerClasses - ) ); + } else { + System.out.println(String.format("WARNING: Unable to choose outer class for %s among options: %s", classEntry, callerClasses)); } } } @@ -512,99 +441,82 @@ public class JarIndex return null; } - private boolean isSaneOuterClass( ClassEntry outerClassEntry, ClassEntry innerClassEntry ) - { + private boolean isSaneOuterClass(ClassEntry outerClassEntry, ClassEntry innerClassEntry) { + // clearly this would be silly - if( outerClassEntry.equals( innerClassEntry ) ) - { + if (outerClassEntry.equals(innerClassEntry)) { return false; } // is the outer class in the jar? - if( !m_obfClassEntries.contains( outerClassEntry ) ) - { + if (!m_obfClassEntries.contains(outerClassEntry)) { return false; } return true; } - - @SuppressWarnings( "unchecked" ) - private boolean isIllegalConstructor( Set syntheticFieldTypes, CtConstructor constructor ) - { + + @SuppressWarnings("unchecked") + private boolean isIllegalConstructor(Set syntheticFieldTypes, CtConstructor constructor) { + // illegal constructors only set synthetic member fields, then call super() String className = constructor.getDeclaringClass().getName(); // collect all the field accesses, constructor calls, and method calls final List illegalFieldWrites = Lists.newArrayList(); final List constructorCalls = Lists.newArrayList(); - try - { - constructor.instrument( new ExprEditor( ) - { + try { + constructor.instrument(new ExprEditor() { @Override - public void edit( FieldAccess fieldAccess ) - { - if( fieldAccess.isWriter() && constructorCalls.isEmpty() ) - { - illegalFieldWrites.add( fieldAccess ); + public void edit(FieldAccess fieldAccess) { + if (fieldAccess.isWriter() && constructorCalls.isEmpty()) { + illegalFieldWrites.add(fieldAccess); } } @Override - public void edit( ConstructorCall constructorCall ) - { - constructorCalls.add( constructorCall ); + public void edit(ConstructorCall constructorCall) { + constructorCalls.add(constructorCall); } - } ); - } - catch( CannotCompileException ex ) - { + }); + } catch (CannotCompileException ex) { // we're not compiling anything... this is stupid - throw new Error( ex ); + throw new Error(ex); } // are there any illegal field writes? - if( illegalFieldWrites.isEmpty() ) - { + if (illegalFieldWrites.isEmpty()) { return false; } // are all the writes to synthetic fields? - for( FieldAccess fieldWrite : illegalFieldWrites ) - { + for (FieldAccess fieldWrite : illegalFieldWrites) { + // all illegal writes have to be to the local class - if( !fieldWrite.getClassName().equals( className ) ) - { - System.err.println( String.format( "WARNING: illegal write to non-member field %s.%s", fieldWrite.getClassName(), fieldWrite.getFieldName() ) ); + if (!fieldWrite.getClassName().equals(className)) { + System.err.println(String.format("WARNING: illegal write to non-member field %s.%s", fieldWrite.getClassName(), fieldWrite.getFieldName())); return false; } // find the field FieldInfo fieldInfo = null; - for( FieldInfo info : (List)constructor.getDeclaringClass().getClassFile().getFields() ) - { - if( info.getName().equals( fieldWrite.getFieldName() ) && info.getDescriptor().equals( fieldWrite.getSignature() ) ) - { + for (FieldInfo info : (List)constructor.getDeclaringClass().getClassFile().getFields()) { + if (info.getName().equals(fieldWrite.getFieldName()) && info.getDescriptor().equals(fieldWrite.getSignature())) { fieldInfo = info; break; } } - if( fieldInfo == null ) - { + if (fieldInfo == null) { // field is in a superclass or something, can't be a local synthetic member return false; } // is this field synthetic? boolean isSynthetic = (fieldInfo.getAccessFlags() & AccessFlag.SYNTHETIC) != 0; - if( isSynthetic ) - { - syntheticFieldTypes.add( fieldInfo.getDescriptor() ); - } - else - { - System.err.println( String.format( "WARNING: illegal write to non synthetic field %s %s.%s", fieldInfo.getDescriptor(), className, fieldInfo.getName() ) ); + if (isSynthetic) { + syntheticFieldTypes.add(fieldInfo.getDescriptor()); + } else { + System.err.println(String.format("WARNING: illegal write to non synthetic field %s %s.%s", fieldInfo.getDescriptor(), className, fieldInfo.getName())); return false; } } @@ -612,56 +524,51 @@ public class JarIndex // we passed all the tests! return true; } - - private BehaviorEntry isAnonymousClass( CtClass c, String outerClassName ) - { - ClassEntry innerClassEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); + + private BehaviorEntry isAnonymousClass(CtClass c, String outerClassName) { + + ClassEntry innerClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); // anonymous classes: - // can't be abstract - // have only one constructor - // it's called exactly once by the outer class - // the type the instance is assigned to can't be this type + // can't be abstract + // have only one constructor + // it's called exactly once by the outer class + // the type the instance is assigned to can't be this type // is abstract? - if( Modifier.isAbstract( c.getModifiers() ) ) - { + if (Modifier.isAbstract(c.getModifiers())) { return null; } // is there exactly one constructor? - if( c.getDeclaredConstructors().length != 1 ) - { + if (c.getDeclaredConstructors().length != 1) { return null; } CtConstructor constructor = c.getDeclaredConstructors()[0]; // is this constructor called exactly once? - ConstructorEntry constructorEntry = new ConstructorEntry( innerClassEntry, constructor.getMethodInfo().getDescriptor() ); - Collection> references = getBehaviorReferences( constructorEntry ); - if( references.size() != 1 ) - { + ConstructorEntry constructorEntry = new ConstructorEntry( + innerClassEntry, + constructor.getMethodInfo().getDescriptor() + ); + Collection> references = getBehaviorReferences(constructorEntry); + if (references.size() != 1) { return null; } // does the caller use this type? BehaviorEntry caller = references.iterator().next().context; - for( FieldEntry fieldEntry : getReferencedFields( caller ) ) - { - ClassEntry fieldClass = getFieldClass( fieldEntry ); - if( fieldClass != null && fieldClass.equals( innerClassEntry ) ) - { + for (FieldEntry fieldEntry : getReferencedFields(caller)) { + ClassEntry fieldClass = getFieldClass(fieldEntry); + if (fieldClass != null && fieldClass.equals(innerClassEntry)) { // caller references this type, so it can't be anonymous return null; } } - for( BehaviorEntry behaviorEntry : getReferencedBehaviors( caller ) ) - { + for (BehaviorEntry behaviorEntry : getReferencedBehaviors(caller)) { // get the class types from the signature - for( String className : SignatureUpdater.getClasses( behaviorEntry.getSignature() ) ) - { - if( className.equals( innerClassEntry.getName() ) ) - { + for (String className : SignatureUpdater.getClasses(behaviorEntry.getSignature())) { + if (className.equals(innerClassEntry.getName())) { // caller references this type, so it can't be anonymous return null; } @@ -670,330 +577,275 @@ public class JarIndex return caller; } - - public Set getObfClassEntries( ) - { + + public Set getObfClassEntries() { return m_obfClassEntries; } - public TranslationIndex getTranslationIndex( ) - { + public TranslationIndex getTranslationIndex() { return m_translationIndex; } - public Access getAccess( Entry entry ) - { - return m_access.get( entry ); + public Access getAccess(Entry entry) { + return m_access.get(entry); } - public ClassEntry getFieldClass( FieldEntry fieldEntry ) - { - return m_fieldClasses.get( fieldEntry ); + public ClassEntry getFieldClass(FieldEntry fieldEntry) { + return m_fieldClasses.get(fieldEntry); } - public ClassInheritanceTreeNode getClassInheritance( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) - { + public ClassInheritanceTreeNode getClassInheritance(Translator deobfuscatingTranslator, ClassEntry obfClassEntry) { + // get the root node List ancestry = Lists.newArrayList(); - ancestry.add( obfClassEntry.getName() ); - ancestry.addAll( m_translationIndex.getAncestry( obfClassEntry.getName() ) ); - ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get( ancestry.size() - 1 ) ); + ancestry.add(obfClassEntry.getName()); + ancestry.addAll(m_translationIndex.getAncestry(obfClassEntry.getName())); + ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( + deobfuscatingTranslator, + ancestry.get(ancestry.size() - 1) + ); // expand all children recursively - rootNode.load( m_translationIndex, true ); + rootNode.load(m_translationIndex, true); return rootNode; } - public ClassImplementationsTreeNode getClassImplementations( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) - { + public ClassImplementationsTreeNode getClassImplementations(Translator deobfuscatingTranslator, ClassEntry obfClassEntry) { + // is this even an interface? - if( isInterface( obfClassEntry.getClassName() ) ) - { - ClassImplementationsTreeNode node = new ClassImplementationsTreeNode( deobfuscatingTranslator, obfClassEntry ); - node.load( this ); + if (isInterface(obfClassEntry.getClassName())) { + ClassImplementationsTreeNode node = new ClassImplementationsTreeNode(deobfuscatingTranslator, obfClassEntry); + node.load(this); return node; } return null; } - public MethodInheritanceTreeNode getMethodInheritance( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) - { + public MethodInheritanceTreeNode getMethodInheritance(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { + // travel to the ancestor implementation String baseImplementationClassName = obfMethodEntry.getClassName(); - for( String ancestorClassName : m_translationIndex.getAncestry( obfMethodEntry.getClassName() ) ) - { + for (String ancestorClassName : m_translationIndex.getAncestry(obfMethodEntry.getClassName())) { MethodEntry ancestorMethodEntry = new MethodEntry( - new ClassEntry( ancestorClassName ), + new ClassEntry(ancestorClassName), obfMethodEntry.getName(), obfMethodEntry.getSignature() ); - if( containsObfBehavior( ancestorMethodEntry ) ) - { + if (containsObfBehavior(ancestorMethodEntry)) { baseImplementationClassName = ancestorClassName; } } // make a root node at the base MethodEntry methodEntry = new MethodEntry( - new ClassEntry( baseImplementationClassName ), + new ClassEntry(baseImplementationClassName), obfMethodEntry.getName(), obfMethodEntry.getSignature() ); MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode( deobfuscatingTranslator, methodEntry, - containsObfBehavior( methodEntry ) + containsObfBehavior(methodEntry) ); // expand the full tree - rootNode.load( this, true ); + rootNode.load(this, true); return rootNode; } - public MethodImplementationsTreeNode getMethodImplementations( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) - { + public MethodImplementationsTreeNode getMethodImplementations(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { + MethodEntry interfaceMethodEntry; // is this method on an interface? - if( isInterface( obfMethodEntry.getClassName() ) ) - { + if (isInterface(obfMethodEntry.getClassName())) { interfaceMethodEntry = obfMethodEntry; - } - else - { + } else { // get the interface class List methodInterfaces = Lists.newArrayList(); - for( String interfaceName : getInterfaces( obfMethodEntry.getClassName() ) ) - { + for (String interfaceName : getInterfaces(obfMethodEntry.getClassName())) { // is this method defined in this interface? MethodEntry methodInterface = new MethodEntry( - new ClassEntry( interfaceName ), + new ClassEntry(interfaceName), obfMethodEntry.getName(), obfMethodEntry.getSignature() ); - if( containsObfBehavior( methodInterface ) ) - { - methodInterfaces.add( methodInterface ); + if (containsObfBehavior(methodInterface)) { + methodInterfaces.add(methodInterface); } } - if( methodInterfaces.isEmpty() ) - { + if (methodInterfaces.isEmpty()) { return null; } - if( methodInterfaces.size() > 1 ) - { - throw new Error( "Too many interfaces define this method! This is not yet supported by Enigma!" ); + if (methodInterfaces.size() > 1) { + throw new Error("Too many interfaces define this method! This is not yet supported by Enigma!"); } - interfaceMethodEntry = methodInterfaces.get( 0 ); + interfaceMethodEntry = methodInterfaces.get(0); } - MethodImplementationsTreeNode rootNode = new MethodImplementationsTreeNode( deobfuscatingTranslator, interfaceMethodEntry ); - rootNode.load( this ); + MethodImplementationsTreeNode rootNode = new MethodImplementationsTreeNode(deobfuscatingTranslator, interfaceMethodEntry); + rootNode.load(this); return rootNode; } - public Set getRelatedMethodImplementations( MethodEntry obfMethodEntry ) - { + public Set getRelatedMethodImplementations(MethodEntry obfMethodEntry) { Set methodEntries = Sets.newHashSet(); - getRelatedMethodImplementations( methodEntries, getMethodInheritance( null, obfMethodEntry ) ); + getRelatedMethodImplementations(methodEntries, getMethodInheritance(null, obfMethodEntry)); return methodEntries; } - private void getRelatedMethodImplementations( Set methodEntries, MethodInheritanceTreeNode node ) - { + private void getRelatedMethodImplementations(Set methodEntries, MethodInheritanceTreeNode node) { MethodEntry methodEntry = node.getMethodEntry(); - if( containsObfBehavior( methodEntry ) ) - { + if (containsObfBehavior(methodEntry)) { // collect the entry - methodEntries.add( methodEntry ); + methodEntries.add(methodEntry); } // look at interface methods too - MethodImplementationsTreeNode implementations = getMethodImplementations( null, methodEntry ); - if( implementations != null ) - { - getRelatedMethodImplementations( methodEntries, implementations ); + MethodImplementationsTreeNode implementations = getMethodImplementations(null, methodEntry); + if (implementations != null) { + getRelatedMethodImplementations(methodEntries, implementations); } // recurse - for( int i=0; i methodEntries, MethodImplementationsTreeNode node ) - { + private void getRelatedMethodImplementations(Set methodEntries, MethodImplementationsTreeNode node) { MethodEntry methodEntry = node.getMethodEntry(); - if( containsObfBehavior( methodEntry ) ) - { + if (containsObfBehavior(methodEntry)) { // collect the entry - methodEntries.add( methodEntry ); + methodEntries.add(methodEntry); } // recurse - for( int i=0; i> getFieldReferences( FieldEntry fieldEntry ) - { - return m_fieldReferences.get( fieldEntry ); + + public Collection> getFieldReferences(FieldEntry fieldEntry) { + return m_fieldReferences.get(fieldEntry); } - public Collection getReferencedFields( BehaviorEntry behaviorEntry ) - { + public Collection getReferencedFields(BehaviorEntry behaviorEntry) { // linear search is fast enough for now Set fieldEntries = Sets.newHashSet(); - for( EntryReference reference : m_fieldReferences.values() ) - { - if( reference.context == behaviorEntry ) - { - fieldEntries.add( reference.entry ); + for (EntryReference reference : m_fieldReferences.values()) { + if (reference.context == behaviorEntry) { + fieldEntries.add(reference.entry); } } return fieldEntries; } - public Collection> getBehaviorReferences( BehaviorEntry behaviorEntry ) - { - return m_behaviorReferences.get( behaviorEntry ); + public Collection> getBehaviorReferences(BehaviorEntry behaviorEntry) { + return m_behaviorReferences.get(behaviorEntry); } - - public Collection getReferencedBehaviors( BehaviorEntry behaviorEntry ) - { + + public Collection getReferencedBehaviors(BehaviorEntry behaviorEntry) { // linear search is fast enough for now Set behaviorEntries = Sets.newHashSet(); - for( EntryReference reference : m_behaviorReferences.values() ) - { - if( reference.context == behaviorEntry ) - { - behaviorEntries.add( reference.entry ); + for (EntryReference reference : m_behaviorReferences.values()) { + if (reference.context == behaviorEntry) { + behaviorEntries.add(reference.entry); } } return behaviorEntries; } - public Collection getInnerClasses( String obfOuterClassName ) - { - return m_innerClasses.get( obfOuterClassName ); + public Collection getInnerClasses(String obfOuterClassName) { + return m_innerClasses.get(obfOuterClassName); } - public String getOuterClass( String obfInnerClassName ) - { + public String getOuterClass(String obfInnerClassName) { // make sure we use the right name - if( new ClassEntry( obfInnerClassName ).getPackageName() != null ) - { - throw new IllegalArgumentException( "Don't reference obfuscated inner classes using packages: " + obfInnerClassName ); + if (new ClassEntry(obfInnerClassName).getPackageName() != null) { + throw new IllegalArgumentException("Don't reference obfuscated inner classes using packages: " + obfInnerClassName); } - return m_outerClasses.get( obfInnerClassName ); + return m_outerClasses.get(obfInnerClassName); } - public boolean isAnonymousClass( String obfInnerClassName ) - { - return m_anonymousClasses.containsKey( obfInnerClassName ); + public boolean isAnonymousClass(String obfInnerClassName) { + return m_anonymousClasses.containsKey(obfInnerClassName); } - public BehaviorEntry getAnonymousClassCaller( String obfInnerClassName ) - { - return m_anonymousClasses.get( obfInnerClassName ); + public BehaviorEntry getAnonymousClassCaller(String obfInnerClassName) { + return m_anonymousClasses.get(obfInnerClassName); } - public Set getInterfaces( String className ) - { + public Set getInterfaces(String className) { Set interfaceNames = new HashSet(); - interfaceNames.addAll( m_interfaces.get( className ) ); - for( String ancestor : m_translationIndex.getAncestry( className ) ) - { - interfaceNames.addAll( m_interfaces.get( ancestor ) ); + interfaceNames.addAll(m_interfaces.get(className)); + for (String ancestor : m_translationIndex.getAncestry(className)) { + interfaceNames.addAll(m_interfaces.get(ancestor)); } return interfaceNames; } - public Set getImplementingClasses( String targetInterfaceName ) - { + public Set getImplementingClasses(String targetInterfaceName) { // linear search is fast enough for now Set classNames = Sets.newHashSet(); - for( Map.Entry entry : m_interfaces.entries() ) - { + for (Map.Entry entry : m_interfaces.entries()) { String className = entry.getKey(); String interfaceName = entry.getValue(); - if( interfaceName.equals( targetInterfaceName ) ) - { - classNames.add( className ); - m_translationIndex.getSubclassNamesRecursively( classNames, className ); + if (interfaceName.equals(targetInterfaceName)) { + classNames.add(className); + m_translationIndex.getSubclassNamesRecursively(classNames, className); } } return classNames; } - public boolean isInterface( String className ) - { - return m_interfaces.containsValue( className ); + public boolean isInterface(String className) { + return m_interfaces.containsValue(className); } - public MethodEntry getBridgeMethod( MethodEntry methodEntry ) - { - return m_bridgeMethods.get( methodEntry ); + public MethodEntry getBridgeMethod(MethodEntry methodEntry) { + return m_bridgeMethods.get(methodEntry); } - public boolean containsObfClass( ClassEntry obfClassEntry ) - { - return m_obfClassEntries.contains( obfClassEntry ); + public boolean containsObfClass(ClassEntry obfClassEntry) { + return m_obfClassEntries.contains(obfClassEntry); } - - public boolean containsObfField( FieldEntry obfFieldEntry ) - { - return m_access.containsKey( obfFieldEntry ); + + public boolean containsObfField(FieldEntry obfFieldEntry) { + return m_access.containsKey(obfFieldEntry); } - - public boolean containsObfBehavior( BehaviorEntry obfBehaviorEntry ) - { - return m_access.containsKey( obfBehaviorEntry ); + + public boolean containsObfBehavior(BehaviorEntry obfBehaviorEntry) { + return m_access.containsKey(obfBehaviorEntry); } - public boolean containsObfArgument( ArgumentEntry obfArgumentEntry ) - { + public boolean containsObfArgument(ArgumentEntry obfArgumentEntry) { // check the behavior - if( !containsObfBehavior( obfArgumentEntry.getBehaviorEntry() ) ) - { + if (!containsObfBehavior(obfArgumentEntry.getBehaviorEntry())) { return false; } // check the argument - if( obfArgumentEntry.getIndex() >= Descriptor.numOfParameters( obfArgumentEntry.getBehaviorEntry().getSignature() ) ) - { + if (obfArgumentEntry.getIndex() >= Descriptor.numOfParameters(obfArgumentEntry.getBehaviorEntry().getSignature())) { return false; } return true; } - public boolean containsObfEntry( Entry obfEntry ) - { - 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() ); + public boolean containsObfEntry(Entry obfEntry) { + 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()); } } } -- cgit v1.2.3