From 67b8bad8950659365d6ea9e1af8481c14ff6ff6e Mon Sep 17 00:00:00 2001 From: Caleb Fenton Date: Thu, 4 Feb 2016 18:09:46 -0800 Subject: [PATCH] Commit byte-buddy failure before removing --- smalivm/build.gradle | 4 +- .../org/cf/smalivm/smali/ClassBuilder.java | 5 ++- .../smali/ClassDependencyCollector.java | 44 +++++++++++++++++++ .../cf/smalivm/smali/SmaliClassLoader.java | 37 +++++++++++++--- .../cf/smalivm/smali/ClassBuilderTest.java | 11 +++++ 5 files changed, 90 insertions(+), 11 deletions(-) create mode 100644 smalivm/src/main/java/org/cf/smalivm/smali/ClassDependencyCollector.java diff --git a/smalivm/build.gradle b/smalivm/build.gradle index 199f23909..07f9365aa 100644 --- a/smalivm/build.gradle +++ b/smalivm/build.gradle @@ -29,13 +29,13 @@ dependencies { compile 'org.smali:smali:2.1.1' compile 'org.smali:baksmali:2.1.1' - //compile 'net.bytebuddy:byte-buddy:0.8.0' + compile 'net.bytebuddy:byte-buddy:1.1.0' // Contains Android framework classes that should be reflected instead of virtually executed compile files('libs/android-local.jar') // Manually patched to allow for multiple fields of the same name but different types - compile files('libs/byte-buddy-0.8-SNAPSHOT.jar') + // compile files('libs/byte-buddy-0.8-SNAPSHOT.jar') // Testing testCompile depends.junit diff --git a/smalivm/src/main/java/org/cf/smalivm/smali/ClassBuilder.java b/smalivm/src/main/java/org/cf/smalivm/smali/ClassBuilder.java index 201e89183..ef0f5f75f 100644 --- a/smalivm/src/main/java/org/cf/smalivm/smali/ClassBuilder.java +++ b/smalivm/src/main/java/org/cf/smalivm/smali/ClassBuilder.java @@ -28,6 +28,7 @@ import net.bytebuddy.dynamic.DynamicType.Unloaded; import net.bytebuddy.dynamic.TargetType; import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; +import net.bytebuddy.dynamic.scaffold.TypeValidation; import net.bytebuddy.implementation.StubMethod; import net.bytebuddy.jar.asm.Opcodes; @@ -92,7 +93,7 @@ private void buildClass(String className, ClassDef classDef) throws ClassNotFoun startBuilding(className); - ByteBuddy buddy = new ByteBuddy(); + ByteBuddy buddy = new ByteBuddy().with(TypeValidation.DISABLED); Builder builder = setSuperclass(buddy, classDef.getSuperclass()); builder = setInterfaces(builder, classDef.getInterfaces()); builder = setAnnotations(builder, classDef.getAnnotations()); @@ -135,7 +136,7 @@ private void buildQueued() throws ClassNotFoundException { private void buildShallowClass(String className, boolean isInterface) throws ClassNotFoundException { startBuilding(className); - ByteBuddy buddy = new ByteBuddy(); + ByteBuddy buddy = new ByteBuddy().with(TypeValidation.DISABLED); Builder builder = setSuperclass(buddy, "Ljava/lang/Object;"); builder = builder.name(className); ModifierContributor.ForType[] modifiers = getShallowTypeModifiers(isInterface); diff --git a/smalivm/src/main/java/org/cf/smalivm/smali/ClassDependencyCollector.java b/smalivm/src/main/java/org/cf/smalivm/smali/ClassDependencyCollector.java new file mode 100644 index 000000000..6cbcdedf0 --- /dev/null +++ b/smalivm/src/main/java/org/cf/smalivm/smali/ClassDependencyCollector.java @@ -0,0 +1,44 @@ +package org.cf.smalivm.smali; + +import java.util.HashSet; +import java.util.Set; + +import org.jf.dexlib2.iface.ClassDef; +import org.jf.dexlib2.iface.Field; +import org.jf.dexlib2.iface.Method; + +public class ClassDependencyCollector { + + public static Set collect(ClassDef classDef) { + Set dependencies = new HashSet(); + + dependencies.add(classDef.getType()); + dependencies.add(classDef.getSuperclass()); + dependencies.addAll(classDef.getInterfaces()); + dependencies.addAll(collectMethodDependencies(classDef.getMethods())); + dependencies.addAll(collectFieldDependencies(classDef.getFields())); + + return dependencies; + } + + private static Set collectMethodDependencies(Iterable methods) { + Set dependencies = new HashSet(); + for (Method method : methods) { + for (CharSequence parameterType : method.getParameterTypes()) { + dependencies.add(parameterType.toString()); + } + } + + return dependencies; + } + + private static Set collectFieldDependencies(Iterable fields) { + Set dependencies = new HashSet(); + for (Field field : fields) { + dependencies.add(field.getType()); + } + + return dependencies; + } + +} diff --git a/smalivm/src/main/java/org/cf/smalivm/smali/SmaliClassLoader.java b/smalivm/src/main/java/org/cf/smalivm/smali/SmaliClassLoader.java index 1676c0592..c71ee57f1 100644 --- a/smalivm/src/main/java/org/cf/smalivm/smali/SmaliClassLoader.java +++ b/smalivm/src/main/java/org/cf/smalivm/smali/SmaliClassLoader.java @@ -3,11 +3,14 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.annotation.Nullable; +import org.cf.util.ClassNameUtils; +import org.jf.dexlib2.iface.ClassDef; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,6 +72,18 @@ protected Class findClass(String name) { return cachedClasses.get(name); } + private void filterAvailableClasses(Set classNames) { + Iterator iter = classNames.iterator(); + while (iter.hasNext()) { + String className = iter.next(); + String baseName = ClassNameUtils.getComponentBase(className); + String binaryName = ClassNameUtils.internalToBinary(baseName); + if (loadClassWithoutBuilding(binaryName) != null) { + iter.remove(); + } + } + } + @Override public synchronized Class loadClass(String name) throws ClassNotFoundException { Class klazz = loadClassWithoutBuilding(name); @@ -76,13 +91,21 @@ public synchronized Class loadClass(String name) throws ClassNotFoundExceptio return klazz; } - if (cachedClasses.isEmpty()) { - Set classNames = classManager.getNonFrameworkClassNames(); - // If I don't set this to null first, cachedClasses does not update. - // VERY VERY STRANGE - cachedClasses = null; - cachedClasses = classBuilder.build(classNames); - } + ClassDef classDef = classManager.getClass(ClassNameUtils.binaryToInternal(name)); + Set classNames = ClassDependencyCollector.collect(classDef); + filterAvailableClasses(classNames); + Map> newClasses = classBuilder.build(classNames); + cachedClasses.putAll(newClasses); + + // if (cachedClasses.isEmpty()) { + // Set classNames = classManager.getNonFrameworkClassNames(); + // classNames.clear(); + // classNames.add(name); + // If I don't set this to null first, cachedClasses does not update. + // VERY VERY STRANGE + // cachedClasses = null; + // cachedClasses = classBuilder.build(classNames); + // } klazz = findClass(name); if (klazz == null) { diff --git a/smalivm/src/test/java/org/cf/smalivm/smali/ClassBuilderTest.java b/smalivm/src/test/java/org/cf/smalivm/smali/ClassBuilderTest.java index 9f438e9e4..14434ef4a 100644 --- a/smalivm/src/test/java/org/cf/smalivm/smali/ClassBuilderTest.java +++ b/smalivm/src/test/java/org/cf/smalivm/smali/ClassBuilderTest.java @@ -132,6 +132,17 @@ public void canBuildInterfaceDoubleDependency() throws Exception { Class klazz = classes.get(className); } + @Test + public void testy() throws ClassNotFoundException, IOException { + classManager = new ClassManagerFactory().build("../simplify/obfuscated-example"); + classBuilder = new ClassBuilder(classManager); + String className = "android.support.v4.media.TransportMediatorJellybeanMR2$2"; + className = "org.cf.obfuscated.Reflection"; + // android.support.v4.view.accessibility.AccessibilityNodeInfoCompatJellybeanMr2 + Map> classes = classBuilder.build(className); + + } + @Test public void canBuildSelfReferencingClass() throws Exception { String className = "org.cf.test.SelfReference";