对 VirtualApp hook过程的理解

VirtualApp是一个开源的Android App虚拟化引擎,允许在其中创建虚拟空间,并在这个虚拟空间中运行其他应用。就是一个容器,可以进行双开处理。网上的讲解已经很详细了,我想从一个例子加深一下对va hook过程的理解。
可以从简单的startactivity入手
首先是mirror里的ActivityManagerNative

public class ActivityManagerNative {
    public static Class<?> TYPE = RefClass.load(ActivityManagerNative.class, "android.app.ActivityManagerNative");
    public static RefStaticObject<Object> gDefault;
    public static RefStaticMethod<IInterface> getDefault;
}

类成员变量会在安装时就会进行初始化,通过反射获取系统中的值,首先执行RefClass.load

//realClass 通过反射获得,这里是"android.app.ActivityManagerNative"
    public static Class load(Class mappingClass, Class<?> realClass) {
        //mirror对象获取字段 这里是ActivityManagerNative  有三个字段 TYPE gDefault getDefault
        Field[] fields = mappingClass.getDeclaredFields();
        for (Field field : fields) {
            try {
                if (Modifier.isStatic(field.getModifiers())) {
                    Constructor<?> constructor = REF_TYPES.get(field.getType());
                    //如果map里有这个字段才会替换值,TYPE.class不在
                    if (constructor != null) {
                        //对字段设置值
                        field.set(null, constructor.newInstance(realClass, field));
                    }
                }
            }
            catch (Exception e) {
                // Ignore
            }
        }
        return realClass;
    }

如果是getDefault 就会反射调用他的构造器

 public RefStaticMethod(Class<?> cls, Field field) throws NoSuchMethodException {
                                  ...
 //如果方法名和mirror中的方法名一致,则拿到method对象,之后可以反射调用方法
            for (Method method : cls.getDeclaredMethods()) {
                if (method.getName().equals(field.getName())) {
                    this.method = method;
                    this.method.setAccessible(true);
                    break;
                }
            }

mirror中的activitymanager就初始完成了,主要是为了得到getDefault方法返回值 在系统中 就是一个aidl接口

    static public IActivityManager getDefault() {
        return ActivityManager.getService();
    }

对这个接口首先进行动态代理,在MethodInvocationStub中

    public MethodInvocationStub(T baseInterface, Class<?>... proxyInterfaces) {
    //被代理类
        this.mBaseInterface = baseInterface;
        if (baseInterface != null) {
            if (proxyInterfaces == null) {
                proxyInterfaces = MethodParameterUtils.getAllInterface(baseInterface.getClass());
            }
     //代理类 处理类HookInvocationHandler
            mProxyInterface = (T) Proxy.newProxyInstance(baseInterface.getClass().getClassLoader(), proxyInterfaces, new HookInvocationHandler());
        } else {
            VLog.d(TAG, "Unable to build HookDelegate: %s.", getIdentityName());
        }
    }

处理类也在内部

    private class HookInvocationHandler implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            MethodProxy methodProxy = getMethodProxy(method.getName());
            //如果methodProxy被添加过了并且设置为可以得到,则执行methodProxy.call.
            boolean useProxy = (methodProxy != null && methodProxy.isEnable());
            boolean mightLog = (mInvocationLoggingCondition != LogInvocation.Condition.NEVER) ||
                    (methodProxy != null && methodProxy.getInvocationLoggingCondition() != LogInvocation.Condition.NEVER);

            String argStr = null;
            Object res = null;
            Throwable exception = null;
            if (mightLog) {
                // Arguments to string is done before the method is called because the method might actually change it
                argStr = Arrays.toString(args);
                argStr = argStr.substring(1, argStr.length()-1);
            }
            try {
                if (useProxy && methodProxy.beforeCall(mBaseInterface, method, args)) {
                //执行methodproxy.call方法
                    res = methodProxy.call(mBaseInterface, method, args);
                    res = methodProxy.afterCall(mBaseInterface, method, args, res);
                } else {
                    res = method.invoke(mBaseInterface, args);
                }
                return res;

            } catch (Throwable t) {
                exception = t;
                if (exception instanceof InvocationTargetException && ((InvocationTargetException) exception).getTargetException() != null) {
                    exception = ((InvocationTargetException) exception).getTargetException();
                }
                throw exception;

            } finally {
                if (mightLog) {
                    int logPriority = mInvocationLoggingCondition.getLogLevel(useProxy, exception != null);
                    if (methodProxy != null) {
                        logPriority = Math.max(logPriority, methodProxy.getInvocationLoggingCondition().getLogLevel(useProxy, exception != null));
                    }
                    if (logPriority >= 0) {
                        String retString;
                        if (exception != null) {
                            retString = exception.toString();
                        } else if (method.getReturnType().equals(void.class)) {
                            retString = "void";
                        } else {
                            retString = String.valueOf(res);
                        }
                    //   Log.println(logPriority, TAG, method.getDeclaringClass().getSimpleName() + "." + method.getName() + "(" + argStr + ") => " + retString);
                    }
                }
            }
        }
    }

这里要提到MethodProxy.添加MethodProxy方式有两种。一是调用 addMethodProxy,二是在 Stub 上添加 @Inject 注解。
关于 MethodProxies
叫这个名字的类很多,一个 MethodProxies 对应一个需要 Hook 的 framework 类型,需要 Hook 的方法以内部类(MethodProxy)的形式罗列在内部。

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

将要 Hook 的方法集合 MethodProxies 绑定到 Stub 上。然后就是 Stub 对自己头上注解的解析,最终还是会调用到内部的 addMethodProxy 方法。

    protected void onBindMethods() {

        if (mInvocationStub == null) {
            return;
        }

        Class<? extends MethodInvocationProxy> clazz = this.getClass();
        Inject inject = clazz.getAnnotation(Inject.class);
        if (inject != null) {
            Class<?> proxiesClass = inject.value();
            Class<?>[] innerClasses = proxiesClass.getDeclaredClasses();
            for (Class<?> innerClass : innerClasses) {
                if (!Modifier.isAbstract(innerClass.getModifiers())
                        && MethodProxy.class.isAssignableFrom(innerClass)
                        && innerClass.getAnnotation(SkipInject.class) == null) {
                    addMethodProxy(innerClass);
                }
            }

        }
    }

注解实际还是调用的 addMethodProxy 。如类startactivity就是其中的内部类

static class StartActivity extends MethodProxy

用stub替换系统中的对像的值。就完成了插桩操作。

 public void inject() throws Throwable {
 ...
 ActivityManagerNative.gDefault.set(getInvocationStub().getProxyInterface());
 ...
 }

这个stub完成了 ,最后通过这个代理startactivity的call,完成一些操作。比如启动A1界面,替换成启动va设好的stubactivity

   public Object call(Object who, Method method, Object... args) throws Throwable {
...
 int res = VActivityManager.get().startActivity(intent, activityInfo, resultTo, options, resultWho, requestCode, VUserHandle.myUserId());
...
}

参考资料:
http://blog.csdn.net/ganyao939543405/article/details/76146760?ref=myread
VA 的源码注释: https://github.com/ganyao114/VA_Doc

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
VirtualApp是一个开源的、提供虚拟应用的框架,其源码可以帮助我们了解和学习虚拟技术的实现原理。 VirtualApp的源码中主要包含了以下几个方面的内容: 1. Hook技术:VirtualApp使用了Xposed和Substrate等Hook框架,通过动态修改运行时的Java方法,实现对目标应用的API调用进行拦截和替换。通过Hook技术,VirtualApp能够在虚拟环境中替换目标应用的敏感操作,实现对应用的隔离和保护。 2. 虚拟环境创建:VirtualApp源码实现了一个独立的虚拟环境,可以在这个环境中安装和运行目标应用。这个虚拟环境通过Hook技术对系统运行时的一些特殊API进行拦截和修改,使得目标应用在虚拟环境中运行时能够调用到虚拟环境提供的资源、服务和功能。 3. 进程隔离:VirtualApp使用了Linux的Namespace和Cgroup等技术,实现了进程的隔离。在虚拟环境中运行的应用与宿主系统的应用是完全独立的,互不干扰。这种隔离可以保护宿主系统的安全,同时也可以保护虚拟环境中的应用不受外部环境的干扰。 4. 文件系统隔离:VirtualApp通过Hook技术对文件操作API进行拦截和修改,实现了虚拟环境与宿主系统的文件系统隔离。在虚拟环境中运行的应用只能访问到虚拟环境的文件系统,无法直接访问宿主系统的文件系统,从而保护了宿主系统的文件安全。 总的来说,VirtualApp的源码实现了虚拟应用的关键功能,如Hook技术、虚拟环境创建、进程隔离和文件系统隔离等。通过阅读和学习VirtualApp的源码,我们可以深入了解和掌握虚拟技术的实现原理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值