virtualapp-InvocationStubManager相关

1.java动态代理机制

1.1 最简单的示例

ITest 接口

public interface ITest {
    void Run();
}

TestImpl 实现体

public class TestImpl implements ITest {
    @Override
    public void Run() {
        Log.e("hgy413", "Run: [TestImpl]");
    }
}

TestProxy代码类封装

public class TestProxy {
    private ITest mBaseInterface;

    public TestProxy(ITest ITest) {
        mBaseInterface = ITest;
    }

    public ITest asInterface() {
        final Class<?>[] interfaces = new Class[]{ITest.class};
        final TestHandler handler = new TestHandler(mBaseInterface);
        return (ITest) Proxy.newProxyInstance(ITest.class.getClassLoader(), interfaces, handler);
    }

    // 调用类
    class TestHandler implements InvocationHandler {
        private final ITest mBaseInterface;
        public TestHandler(ITest itest) {
            this.mBaseInterface = itest;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Log.e("hgy413", "Run: [TestHandler before]");
            Object ret = method.invoke(mBaseInterface, args);
            Log.e("hgy413", "Run: [TestHandler end]");
            return ret;
        }
    }
}

调用:

    void ITestProxyTest() {
        TestImpl test = new TestImpl();
        TestProxy proxy = new TestProxy(test);
        ITest mProxyInterface = proxy.asInterface();
        Log.e("hgy413", "proxy  parent classname:" + mProxyInterface.getClass().getSuperclass().getName());
        Log.e("hgy413", "proxy modifiy:" + Modifier.toString(mProxyInterface.getClass().getModifiers()));
        mProxyInterface.Run();
    }

输出结果:

07-15 10:50:10.757 20067-20067/com.hgy.invocation E/hgy413: Run: [TestHandler before]
07-15 10:50:10.757 20067-20067/com.hgy.invocation E/hgy413: Run: [TestImpl]
07-15 10:50:10.757 20067-20067/com.hgy.invocation E/hgy413: Run: [TestHandler end]

可以看到,代理类就是一个hook过程。

1.2 代理:设计模式

参考上例可以很轻松明白,代理其实就是一个hook过程,在函数到达前后做一些自己的操作。
在这里插入图片描述

1.3 相关的类和接口

1.3.1 java.lang.reflect.Proxy

Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象 ,注意,传入的是接口

// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy) 
 
// 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces) 
 
// 方法 3:该方法用于判断指定类对象是否是一个动态代理类
static boolean isProxyClass(Class cl) 
 
// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
1.3.2 java.lang.reflect.InvocationHandler

调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。

// 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象
// 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行
Object invoke(Object proxy, Method method, Object[] args)

注意,第一个参数是proxy对象,也就是前面示例中mProxyInterface,所以Object ret = method.invoke(mBaseInterface, args);,这里要传真正的对象,不要把这个proxy传进去,会一直死循环的。

1.4 如何使用代理机制

  1. 通过实现 InvocationHandler 接口创建自己的调用处理器
  2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类
  3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
  4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
// InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
// 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用
InvocationHandler handler = new InvocationHandlerImpl(..); 
 
// 通过 Proxy 为包括 Interface 接口在内的一组接口动态创建代理类的类对象
Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... }); 
 
// 通过反射从生成的类对象获得构造函数对象
Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class }); 
 
// 通过构造函数对象创建动态代理类实例
Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });

实际使用过程更加简单,因为 Proxy 的静态方法 newProxyInstance 已经为我们封装了步骤 2 到步骤 4 的过程, 所以简化后的过程如下

// InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
InvocationHandler handler = new InvocationHandlerImpl(..); 
 
// 通过 Proxy 直接创建动态代理类实例
Interface proxy = (Interface)Proxy.newProxyInstance( classLoader, new Class[] { Interface.class }, handler);

1.5 代理机制的特点

1)包:如果所代理的接口都是 public 的,那么它将被定义在顶层包(即包路径为空), 如果所代理的接口中有非 public 的接口,那么它将被定义在该接口所在包(假设代理了 com.ibm.developerworks 包中的某非 public 接口 A,那么新生成的代理类所在的包就是 com.ibm.developerworks)。

2)类修饰符:该代理类具有 finalpublic 修饰符,意味着它可以被所有的类访问,但是不能被再度继承

        ITest mProxyInterface = proxy.asInterface();
        Log.e("hgy413", "proxy modifiy:"  + Modifier.toString(mProxyInterface.getClass().getModifiers()));

输出:

07-15 11:36:39.328 20096-20096/com.hgy.invocation E/hgy413: proxy modifiy:public final

3)类名:格式是“$ProxyN”,其中 N 是一个逐一递增的阿拉伯数字,代表 Proxy 类第 N 次生成的动态代理类

        ITest mProxyInterface = proxy.asInterface();
        Log.e("hgy413", "proxy  classname:" + mProxyInterface.getClass().getName());

输出:

07-15 11:40:04.645 856-856/com.hgy.invocation E/hgy413: proxy  classname:$Proxy0

值得注意的一点是,并不是每次调用 Proxy 的静态方法创建动态代理类都会使得 N 值增加,原因是如果对同一组接口(包括接口排列的顺序相同)试图重复创建动态代理类,它会很聪明地返回先前已经创建好的代理类的类对象,而不会再尝试去创建一个全新的代理类,这样可以节省不必要的代码重复生成,提高了代理类的创建效率。

4)父类

   Log.e("hgy413", "proxy  parent classname:" + mProxyInterface.getClass().getSuperclass().getName());

输出:

07-15 12:14:42.703 3938-3938/com.hgy.invocation E/hgy413: proxy  parent classname:java.lang.reflect.Proxy

1.6 代理机制源码分析

Proxy 静态方法 newProxyInstance

   public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
    	// 检查 h 不为空,否则抛异常
     	Objects.requireNonNull(h);
     	// 复制代理类实现的所有接口
        final Class<?>[] intfs = interfaces.clone();
        // 获得与制定类装载器和一组接口相关的代理类类型对象
        Class<?> cl = getProxyClass0(loader, intfs);
         // 通过反射获取构造函数对象并生成代理类实例
        try {
        	 final Constructor<?> cons = cl.getConstructor(constructorParams);
        	 cons.setAccessible(true);
        	 return cons.newInstance(new Object[]{h});
        	 } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
            }
     }

—> getProxyClass0方法负责获取动态代理类类型对象

    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {// 目标类实现的接口不能大于65535
            throw new IllegalArgumentException("interface limit exceeded");
        }
        // 如果已存在,直接从缓存中copy一份,如果不存在就通过ProxyClassFactory创建
        return proxyClassCache.get(loader, interfaces);
    }

–>如果proxyClassCache 中已存在,直接从缓存中copy一份,如果不存在就通过ProxyClassFactory创建

    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

–>ProxyClassFactory的父类为BiFunction模板

  private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>>  
--public interface BiFunction<T, U, R> {
    R apply(T t, U u);
    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t, U u) -> after.apply(apply(t, u));
    }
}

–> BiFunction的构造就是调用apply函数, 所以关键函数为ProxyClassFactory::apply, 以下分步分析:

 public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
 		// 下面分块分析
 }

1.对这组接口进行一定程度的安全检查,包括:
a.检查接口类对象是否对类加载器可见,并且与类装载器所能识别的接口类对象是完全相同的
b.检查确保是 interface 类型而不是 class 类型。这个步骤通过一个循环来完成
c.检查 interface 类型有没有重复

  Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
  for (Class<?> intf : interfaces) { //a 检查接口类对象是否对类加载器可见,并且与类装载器所能识别的接口类对象是完全相同的
      Class<?> interfaceClass = Class.forName(intf.getName(), false, loader);// false表示不需要初始化类
      if (interfaceClass != intf) {
            throw new IllegalArgumentException( intf + " is not visible from class loader");
        }
  	  if (!interfaceClass.isInterface()) {//b 检查确保是 `interface` 类型而不是 `class` 类型
          throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");
    	}
 	 if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {//c 检查 `interface` 类型有没有重复
                   throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());
      }
  }

2.设置Proxy的包名,包括:
a. 如果所代理的接口都是 public 的,那么它将被定义在顶层包(即包路径为空)
b. 如果所代理的接口中有非 public 的接口,那么它将被定义在该接口所在包(假设代理了 com.ibm.developerworks 包中的某非 public 接口 A,那么新生成的代理类所在的包就是 com.ibm.developerworks)。

 String proxyPkg = null;     
 int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
 
   for (Class<?> intf : interfaces) {
        int flags = intf.getModifiers();
        if (!Modifier.isPublic(flags)) {// b. 如果所代理的接口中有非 `public` 的接口,那么它将被定义在该接口所在包
            accessFlags = Modifier.FINAL;
            String name = intf.getName();
           int n = name.lastIndexOf('.');
           String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
           if (proxyPkg == null) {
                 proxyPkg = pkg;
           } else if (!pkg.equals(proxyPkg)) {
                 throw new IllegalArgumentException("non-public interfaces from different packages");
           }
    	 }
      }
    if (proxyPkg == null) {
       // if no non-public proxy interfaces, use the default package.
        proxyPkg = "";//a. 如果所代理的接口都是 `public` 的,那么它将被定义在顶层包(即包路径为空)
   }

3.代理类的根类中三个方法同样做proxy转发,包括equals,hashCode,toString

    List<Method> methods = getMethods(interfaces);
    --private static List<Method> getMethods(Class<?>[] interfaces) {
        List<Method> result = new ArrayList<Method>();
        try {
            result.add(Object.class.getMethod("equals", Object.class));
            result.add(Object.class.getMethod("hashCode", EmptyArray.CLASS));
            result.add(Object.class.getMethod("toString", EmptyArray.CLASS));

4.generateProxy转到NDK层

   return generateProxy(proxyName, interfaces, loader, methodsArray,exceptionsArray);

–>NDK层代码:Android-9.0.0_r1\bin\Work\art\runtime\native\java_lang_reflect_Proxy.cc

static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring name, jobjectArray interfaces,
                                  jobject loader, jobjectArray methods, jobjectArray throws) {
  ScopedFastNativeObjectAccess soa(env);
  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
  return soa.AddLocalReference<jclass>(class_linker->CreateProxyClass(
      soa, name, interfaces, loader, methods, throws));
}
static JNINativeMethod gMethods[] = {
  FAST_NATIVE_METHOD(Proxy, generateProxy, "(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/Method;[[Ljava/lang/Class;)Ljava/lang/Class;"),
};
void register_java_lang_reflect_Proxy(JNIEnv* env) {
  REGISTER_NATIVE_METHODS("java/lang/reflect/Proxy");
}

–>NDK层代码:Android-9.0.0_r1\Android-9.0.0_r1\bin\Work\art\runtime\class_linker.cc

mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa,
                                             jstring name,
                                             jobjectArray interfaces,
                                             jobject loader,
                                             jobjectArray methods,
                                             jobjectArray throws) {
  temp_klass->SetObjectSize(sizeof(mirror::Proxy));
  // 设置类的访问权限,Public Final Proxy,设置类的ClassLoader
  temp_klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccVerificationAttempted);
  temp_klass->SetClassLoader(soa.Decode<mirror::ClassLoader>(loader));
  temp_klass->SetName(soa.Decode<mirror::String>(name));
  temp_klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache());
 // Object has an empty iftable, copy it for that reason.
  temp_klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
  
  // Needs to be before we insert the class so that the allocator field is set.
  LinearAlloc* const allocator = GetOrCreateAllocatorForClassLoader(temp_klass->GetClassLoader());
  .....
  // Now effectively in the loaded state.
  mirror::Class::SetStatus(temp_klass, ClassStatus::kLoaded, self);
  self->AssertNoPendingException();

  // At this point the class is loaded. Publish a ClassLoad event.
  // Note: this may be a temporary class. It is a listener's responsibility to handle this.
  Runtime::Current()->GetRuntimeCallbacks()->ClassLoad(temp_klass);
  }

简单的说就是调用了\Android-9.0.0_r1\bin\Work\art\runtime\mirror\class.cc来创建一个新类,并加载

1.7 JAVA代理机制源码分析

java也可以参考下openjdk的源码 https://github.com/unofficial-openjdk/openjdk , 核心内容就是去调用generateClassFile()实例方法来生成.class文件

private byte[] generateClassFile() {
    //第一步, 将所有的方法组装成ProxyMethod对象
    //首先为代理类生成toString, hashCode, equals等代理方法
    addProxyMethod(hashCodeMethod, Object.class);
    addProxyMethod(equalsMethod, Object.class);
    addProxyMethod(toStringMethod, Object.class);
    //遍历每一个接口的每一个方法, 并且为其生成ProxyMethod对象
    for (int i = 0; i < interfaces.length; i++) {
        Method[] methods = interfaces[i].getMethods();
        for (int j = 0; j < methods.length; j++) {
            addProxyMethod(methods[j], interfaces[i]);
        }
    }
    //对于具有相同签名的代理方法, 检验方法的返回值是否兼容
    for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
        checkReturnTypes(sigmethods);
    }
    
    //第二步, 组装要生成的class文件的所有的字段信息和方法信息
    try {
        //添加构造器方法
        methods.add(generateConstructor());
        //遍历缓存中的代理方法
        for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
            for (ProxyMethod pm : sigmethods) {
                //添加代理类的静态字段, 例如:private static Method m1;
                fields.add(new FieldInfo(pm.methodFieldName,
                        "Ljava/lang/reflect/Method;", ACC_PRIVATE | ACC_STATIC));
                //添加代理类的代理方法
                methods.add(pm.generateMethod());
            }
        }
        //添加代理类的静态字段初始化方法
        methods.add(generateStaticInitializer());
    } catch (IOException e) {
        throw new InternalError("unexpected I/O Exception");
    }
    
    //验证方法和字段集合不能大于65535
    if (methods.size() > 65535) {
        throw new IllegalArgumentException("method limit exceeded");
    }
    if (fields.size() > 65535) {
        throw new IllegalArgumentException("field limit exceeded");
    }

    //第三步, 写入最终的class文件
    //验证常量池中存在代理类的全限定名
    cp.getClass(dotToSlash(className));
    //验证常量池中存在代理类父类的全限定名, 父类名为:"java/lang/reflect/Proxy"
    cp.getClass(superclassName);
    //验证常量池存在代理类接口的全限定名
    for (int i = 0; i < interfaces.length; i++) {
        cp.getClass(dotToSlash(interfaces[i].getName()));
    }
    //接下来要开始写入文件了,设置常量池只读
    cp.setReadOnly();
    
    ByteArrayOutputStream bout = new ByteArrayOutputStream();
    DataOutputStream dout = new DataOutputStream(bout);
    try {
        //1.写入魔数
        dout.writeInt(0xCAFEBABE);
        //2.写入次版本号
        dout.writeShort(CLASSFILE_MINOR_VERSION);
        //3.写入主版本号
        dout.writeShort(CLASSFILE_MAJOR_VERSION);
        //4.写入常量池
        cp.write(dout);
        //5.写入访问修饰符
        dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);
        //6.写入类索引
        dout.writeShort(cp.getClass(dotToSlash(className)));
        //7.写入父类索引, 生成的代理类都继承自Proxy
        dout.writeShort(cp.getClass(superclassName));
        //8.写入接口计数值
        dout.writeShort(interfaces.length);
        //9.写入接口集合
        for (int i = 0; i < interfaces.length; i++) {
            dout.writeShort(cp.getClass(dotToSlash(interfaces[i].getName())));
        }
        //10.写入字段计数值
        dout.writeShort(fields.size());
        //11.写入字段集合 
        for (FieldInfo f : fields) {
            f.write(dout);
        }
        //12.写入方法计数值
        dout.writeShort(methods.size());
        //13.写入方法集合
        for (MethodInfo m : methods) {
            m.write(dout);
        }
        //14.写入属性计数值, 代理类class文件没有属性所以为0
        dout.writeShort(0);
    } catch (IOException e) {
        throw new InternalError("unexpected I/O Exception");
    }
    //转换成二进制数组输出
    return bout.toByteArray();
}

可以看到generateClassFile()方法是按照.class文件结构进行动态拼接的。

Java程序的执行只依赖于.class文件,和Java文件是没有关系的。JDK动态代理就是通过程序来动态生成.class文件的。我们再次回到上面的代码中,可以看到,生成.class文件主要分为三步:
第一步:收集所有要生成的代理方法,将其包装成ProxyMethod对象并注册到Map集合中。
第二步:收集所有要为.class文件生成的字段信息和方法信息。
第三步:完成了上面的工作后,开始组装.class文件。

我们知道一个类的核心部分就是它的字段和方法。我们重点聚焦第二步,看看它为代理类生成了哪些字段和方法。在第二步中,按顺序做了下面四件事。

  1. 为代理类生成一个带参构造器,传入InvocationHandler实例的引用并调用父类的带参构造器。
  2. 遍历代理方法Map集合,为每个代理方法生成对应的Method类型静态域,并将其添加到fields集合中。
  3. 遍历代理方法Map集合,为每个代理方法生成对应的MethodInfo对象,并将其添加到methods集合中。
  4. 为代理类生成静态初始化方法,该静态初始化方法主要是将每个代理方法的引用赋值给对应的静态字段。

通过以上分析,我们可以大致知道JDK动态代理最终会为我们生成如下结构的代理类:

public class Proxy0 extends Proxy implements ITest{

    //第一步, 生成构造器
    protected Proxy0(InvocationHandler h) {
        super(h);
    }

    //第二步, 生成静态域
    private static Method m1;   //hashCode方法
    private static Method m2;   //equals方法
    private static Method m3;   //toString方法
    private static Method m4;   //...
    
    //第三步, 生成代理方法
    @Override
    public int hashCode() {
        try {
            return (int) h.invoke(this, m1, null);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
    
    @Override
    public boolean equals(Object obj) {
        try {
            Object[] args = new Object[] {obj};
            return (boolean) h.invoke(this, m2, args);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
    
    @Override
    public String toString() {
        try {
            return (String) h.invoke(this, m3, null);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
    
    @Override
    public void Run(ITest test) {
        try {
            //构造参数数组, 如果有多个参数往后面添加就行了
            Object[] args = new Object[] {test};
            h.invoke(this, m4, args);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
    
    //第四步, 生成静态初始化方法
    static {
        try {
            Class c1 = Class.forName(Object.class.getName());
            Class c2 = Class.forName(UserDao.class.getName());    
            m1 = c1.getMethod("hashCode", null);
            m2 = c1.getMethod("equals", new Class[]{Object.class});
            m3 = c1.getMethod("toString", null);
            m4 = c2.getMethod("Run", new Class[]{ITest.class});
            //...
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.InvocationStubManager源码相关

代码位于com.lody.virtual.client.hook

结合前面的分析,再来看代码,是非常好理解的

2.1.MethodProxy

Hook 方法的代理接口,动态代理中的 call,每个要Hook的方法都会写得一个类,并继承于MethodProxy ,MethodProxy 有以下的几个关键函数,在VA中,它的封装集合对应每个Stub包边上的MethodProxies

public abstract class MethodProxy {
    private boolean enable = true; // 是否需要proxy
    public abstract String getMethodName(); // 由子类继承,返回要Hook的方法名

    public boolean beforeCall(Object who, Method method, Object... args) {
        // 为false会阻止后续的调用,直接调到原始method.call
        return true;
    }

    public Object call(Object who, Method method, Object... args) throws Throwable { 
        return method.invoke(who, args);
    }

    public boolean isEnable() { // 是否需要proxy
        return enable;
    }

    public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {
        // result为call返回的结果
        return result;
    }
}

其中beforeCall, call , afterCallMethodInvocationStub.HookInvocationHandler中体现了出来, 参考下面的分析

2.2 MethodInvocationStub

MethodInvocationStub是一个模板类,每一个需要 Hook 的类 执有一个对应的MethodInvocationStub对象,在它的内部对这个类的部分特定方法进行hook(通过MethodProxies中的MethodProxy过滤)

它有几个关键的成员变量:

    private Map<String, MethodProxy> mInternalMethodProxies = new HashMap<>(); // 存储方法名和MethodProxy的Map
    private T mBaseInterface;     // 原始对象
    private T mProxyInterface;    // Proxy对象

mInternalMethodProxies 是存储方法名MethodProxyMap,方法名由MethodProxy的抽象接口getMethodName获得

 mInternalMethodProxies.put(methodProxy.getMethodName(), methodProxy);

mBaseInterface是原始类对象,可以参考最开始的简单示例,名字是相同的。
mProxyInterface是Proxy类对象,可以参考最开始的简单示例,名字是相同的。

2.2.1 MethodInvocationStub.HookInvocationHandler

很明显,这是调用处理器接口
通过这里,可以看出methodProxy.beforeCall, methodProxy.call , methodProxy.afterCall 的调用关系:

  1. beforeCall返回false,直接调用原始的method.call ,同时不会再调用call , afterCall
  2. afterCall 的最后一个参数就是call 的返回值
private class HookInvocationHandler implements InvocationHandler { // 163
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            MethodProxy methodProxy = getMethodProxy(method.getName()); // 通过方法名取得MethodProxy对象
            // 是否使用动态hook
            boolean useProxy = VirtualCore.get().isStartup() && methodProxy != null && methodProxy.isEnable();
            Object res = null; // 返回值
            try {
                if (useProxy && methodProxy.beforeCall(mBaseInterface, method, args)) {
                    res = methodProxy.call(mBaseInterface, method, args);
                    res = methodProxy.afterCall(mBaseInterface, method, args, res);
                } else {
                    // 调用原始方式
                    res = method.invoke(mBaseInterface, args);
                }
                return res;
            } catch (Throwable t) {
               
            } finally { 
            }
        }
    }
2.2.2 MethodInvocationStub.MethodInvocationStub(生成Proxy对象)

生成Proxy对象

    public MethodInvocationStub(T baseInterface, Class<?>... proxyInterfaces) {
        this.mBaseInterface = baseInterface;
        if (baseInterface != null) {
            if (proxyInterfaces == null) {
                proxyInterfaces = MethodParameterUtils.getAllInterface(baseInterface.getClass());
            }
            mProxyInterface = (T) Proxy.newProxyInstance(baseInterface.getClass().getClassLoader(), proxyInterfaces, new HookInvocationHandler());
        }
    }
    public MethodInvocationStub(T baseInterface) {
        this(baseInterface, (Class[]) null);
    }

如果proxyInterfacesnull,就通过MethodParameterUtils.getAllInterface获取baseInterface这个类及它所有上层父类的全部Interface

    public static Class<?>[] getAllInterface(Class clazz) {
        HashSet<Class<?>> classes = new HashSet<>();
        getAllInterfaces(clazz, classes);
        Class<?>[] result = new Class[classes.size()];
        classes.toArray(result);
        return result;
    }

    public static void getAllInterfaces(Class clazz, HashSet<Class<?>> interfaceCollection) {
        Class<?>[] classes = clazz.getInterfaces();
        if (classes.length != 0) {
            interfaceCollection.addAll(Arrays.asList(classes));
        }
        if (clazz.getSuperclass() != Object.class) {
            getAllInterfaces(clazz.getSuperclass(), interfaceCollection);// 递归遍历
        }
    }

2.3 MethodInvocationProxy

MethodInvocationProxy是对MethodInvocationStub的上层包装,也可以认为是一个辅助类,用于支持Inject注解,前面说过,
每一个需要 Hook 的类 执有一个对应的MethodInvocationStub对象,这个需要 Hook 的类一般都继承于MethodInvocationProxy
通过遍历Inject注解,把MethodProxy加入到对应的MethodInvocationStub对象中

public abstract class MethodInvocationProxy<T extends MethodInvocationStub> implements IInjector {
    protected T mInvocationStub;

注解的详解可参考 https://blog.csdn.net/hgy413/article/details/95043842

Inject注解如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {
    Class<?> value();
}

对于virtualapp来说,它主要是用来解析@Inject(MethodProxies.class)注解,MethodProxies有很多子类,而且不同包下有不同的MethodProxies,所以MethodProxies的class前不能加public,因为每个Stub下都有一份MethodProxies

class MethodProxies {
    static class FinishReceiver extends MethodProxy {
        @Override
        public String getMethodName() {
            return "finishReceiver";
        }
    }

    static class GetRecentTasks extends MethodProxy {

        @Override
        public String getMethodName() {
            return "getRecentTasks";
        }
    }
    ....
    }

ActivityManagerStub为例,它继承于MethodInvocationProxy,并加入了@Inject(MethodProxies.class),这里要注意,MethodProxies.classActivityManagerStub同包下的那份,它是有多份的,没有设置public属性

@Inject(MethodProxies.class)
public class ActivityManagerStub extends MethodInvocationProxy<MethodInvocationStub<IInterface>> {

    public ActivityManagerStub() {
        super(new MethodInvocationStub<>(ActivityManagerNative.getDefault.call()));
    }

new MethodInvocationStub<>(xx)对应ActivityManagerStub 中的mInvocationStub成员,ActivityManagerNative.getDefault.call()获得原生的ActivityManager全局对象,并做为mInvocationStub对象中的mBaseInterface成员, 也是需要被hook的IInterface对象。

这部分可参考 virtualapp-RefClass反射机制

–》初始化后进入MethodInvocationProxy构造函数,MethodInvocationProxy会协助通过onBindMethods解析注解

    public MethodInvocationProxy(T invocationStub) {
        this.mInvocationStub = invocationStub;
        onBindMethods();
        afterHookApply(invocationStub);
2.3.1 onBindMethods

–》onBindMethods 方法从MethodProxies.class中以注解的方式取得它的所有子class,并加入到mInvocationStubmInternalMethodProxies

    protected void onBindMethods() {
        if (mInvocationStub == null) {
            return;
        }
        Class<? extends MethodInvocationProxy> clazz = getClass();
        Inject inject = clazz.getAnnotation(Inject.class);
        if (inject != null) {
            Class<?> proxiesClass = inject.value();
            Class<?>[] innerClasses = proxiesClass.getDeclaredClasses(); // 得到MethodProxies的所有子类
            for (Class<?> innerClass : innerClasses) {// 如 MethodProxies中的FinishReceiver ,GetRecentTasks 
                if (!Modifier.isAbstract(innerClass.getModifiers()) // 不是抽象类
                && MethodProxy.class.isAssignableFrom(innerClass) // MethodProxy是innerClass的超类
                && innerClass.getAnnotation(SkipInject.class) == null) { // 不包含SkipInject注解
                    addMethodProxy(innerClass);
                }
            }
            for (Method method : proxiesClass.getMethods()) {
                if (!Modifier.isStatic(method.getModifiers())) {
                    continue;
                }
                if (method.getAnnotation(SkipInject.class) != null) {
                    continue;
                }
                addMethodProxy(new DirectCallMethodProxy(method)); // 静态的方法
            }
        }

    }

onBindMethods 允许子类覆盖,来增加更多的Proxy类,如ActivityManagerStub中的重载来增加更多的MethodProxy调用

 protected void onBindMethods() {
        super.onBindMethods();
        if (VirtualCore.get().isVAppProcess()) {
            addMethodProxy(new ResultStaticMethodProxy("registerUidObserver", 0));
            addMethodProxy(new ResultStaticMethodProxy("unregisterUidObserver", 0));
            addMethodProxy(new ReplaceLastPkgMethodProxy("getAppStartMode"));
            addMethodProxy(new ResultStaticMethodProxy("updateConfiguration", 0));
            addMethodProxy(new ReplaceCallingPkgMethodProxy("setAppLockedVerifying"));
            addMethodProxy(new ReplaceCallingPkgMethodProxy("reportJunkFromApp"));
2.3.2 IInjector

ActivityManagerStub中对应的MethodInvocationStub对象只是实现的Proxy类对象,可以 通过getInvocationStub()得到。
真正的被hook的IInterface对象mBaseInterface,可以通过getInvocationStub().getBaseInterface()得到。

但对于ActivityManagerStub来说,它还是用的ActivityManagerNative.getDefault.call()这个原始的全局对象,这样Proxy还是不起作用

参看最开始示例,我们必须调用 mProxyInterface.Run();才能走到Proxyhook流程

IInjectorinject接口所做的操作就是把系统原始的全局对象替换成我们的Proxy对象mBaseInterfaceMethodInvocationStub类中)。

public void inject() {
        if (ActivityManagerNative.gDefault.type() == IActivityManager.TYPE) {
            ActivityManagerNative.gDefault.set(getInvocationStub().getProxyInterface());
        } else if (ActivityManagerNative.gDefault.type() == Singleton.TYPE) {
            Object gDefault = ActivityManagerNative.gDefault.get();
            Singleton.mInstance.set(gDefault, getInvocationStub().getProxyInterface());
        }

用stub替换系统中的对象的值。就完成了插桩操作,测试startActivity正常hook通过

参考:
JDK动态代理[4]----ProxyGenerator生成代理类的字节码文件解析
Android插件化系列第(一)篇—Hook技术之Activity的启动过程的拦截
对 VirtualApp hook过程的理解
如何使用VirtualApp的动态代理框架做动态代理
Android 双开沙箱 VirtualApp 源码分析(一)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值