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 如何使用代理机制
- 通过实现
InvocationHandler
接口创建自己的调用处理器; - 通过为
Proxy
类指定ClassLoader
对象和一组interface
来创建动态代理类; - 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
- 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
// 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)类修饰符:该代理类具有 final
和 public
修饰符,意味着它可以被所有的类访问,但是不能被再度继承
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
文件。
我们知道一个类的核心部分就是它的字段和方法。我们重点聚焦第二步,看看它为代理类生成了哪些字段和方法。在第二步中,按顺序做了下面四件事。
- 为代理类生成一个带参构造器,传入
InvocationHandler
实例的引用并调用父类的带参构造器。 - 遍历代理方法
Map
集合,为每个代理方法生成对应的Method
类型静态域,并将其添加到fields
集合中。 - 遍历代理方法
Map
集合,为每个代理方法生成对应的MethodInfo
对象,并将其添加到methods
集合中。 - 为代理类生成静态初始化方法,该静态初始化方法主要是将每个代理方法的引用赋值给对应的静态字段。
通过以上分析,我们可以大致知道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
, afterCall
在MethodInvocationStub.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
是存储方法名和MethodProxy
的Map
,方法名由MethodProxy
的抽象接口getMethodName
获得
mInternalMethodProxies.put(methodProxy.getMethodName(), methodProxy);
mBaseInterface
是原始类对象,可以参考最开始的简单示例,名字是相同的。
mProxyInterface
是Proxy类对象,可以参考最开始的简单示例,名字是相同的。
2.2.1 MethodInvocationStub.HookInvocationHandler
很明显,这是调用处理器接口
通过这里,可以看出methodProxy.beforeCall
, methodProxy.call
, methodProxy.afterCall
的调用关系:
beforeCall
返回false,直接调用原始的method.call
,同时不会再调用call
,afterCall
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);
}
如果proxyInterfaces
传null
,就通过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.class
是ActivityManagerStub
同包下的那份,它是有多份的,没有设置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
,并加入到mInvocationStub
的mInternalMethodProxies
中
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();
才能走到Proxy
的hook
流程
IInjector
中inject
接口所做的操作就是把系统原始的全局对象替换成我们的Proxy
对象mBaseInterface
(MethodInvocationStub
类中)。
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 源码分析(一)