美文网首页
如何使用VirtualApp的动态代理框架做动态代理

如何使用VirtualApp的动态代理框架做动态代理

作者: taoyyyy | 来源:发表于2019-05-27 04:33 被阅读0次

    前言

    VirtualApp是一个能够实现多开功能的沙盒,你可以在虚拟空间内任意的安装、启动和卸载APK,这一切都与外部隔离。要想实现对一个APP的虚拟化,就是不直接把APP安装进系统,同时又要提供APP运行过程中所需的一切,从而可以让它误以为自己是运行在正常系统中。这里就需要实现系统服务的虚拟化和相关路径的虚拟化。本文将侧重于分析系统服务虚拟化的过程,以及如何使用VA现有的动态代理框架去做代理。

    几个关键类

    • InvocationStubManager:统一注入代理对象
      1.遍历MethodInvocationProxy调用其inject方法去注入代理类。
      1. injectInternal方法中添加MethodInvocationProxy对象。

    普通方法的动态代理涉及类

    • MethodInvocationProxy:添加需要被代理的方法,处理动态代理类对象的替换逻辑。
      1.一般在onBindMethods()中或者借助@Inject(...)注解,addMethodProxy(...)添加MethodProxy对象。
      2.MethodInvocationProxy实现了IInjector接口,一般在inject()方法中用代理对象替换掉被代理的对象。

    Binder的动态代理

    • BinderInvocationProxy :
      • abstract class BinderInvocationProxy extends MethodInvocationProxy<BinderInvocationStub>
    • BinderInvocationStub
      • class BinderInvocationStub extends MethodInvocationStub<IInterface> implements IBinder

    几个关键方法

    addMethodProxy(MethodProxy methodProxy)

    protected void onBindMethods() {
        super.onBindMethods();
        addMethodProxy(new A1MethodProxy());
    }
    

    跟一下addMethodProxy()做了啥

    public MethodProxy addMethodProxy(MethodProxy methodProxy) {
        return mInvocationStub.addMethodProxy(methodProxy);
    }
    

    看看mInvocationStub是什么,在哪初始化的

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

    继续跟在哪调用了MethodInvocationProxy的构造方法,T是什么

    public AStub() {
            //StoreApplication.mA是被代理的对象
        //IA是被代理类实现的接口
        super(new MethodInvocationStub<IA>(StoreApplication.mA));
    }
    

    原来T是MethodInvocationStub类型对象。接着上面,我们看下MethodInvocationStub#addMethodProxy方法做了啥

    public MethodProxy addMethodProxy(MethodProxy methodProxy) {
        if (methodProxy != null && !TextUtils.isEmpty(methodProxy.getMethodName())) {
            if (mInternalMethodProxies.containsKey(methodProxy.getMethodName())) {
                LogTool.w(TAG, String.format("The Hook(%s, %s) you added has been in existence.", methodProxy.getMethodName(),
                        methodProxy.getClass().getName()));
                return methodProxy;
            }
            mInternalMethodProxies.put(methodProxy.getMethodName(), methodProxy);
        }
        return methodProxy;
    }
    

    mInternalMethodProxies是一个Hashmap,addMethodProxy方法只是将MethodProxy按方法名存储进了这个集合中。那被添加的方法是如何被成功代理的呢?

    com.zooksoft.faker.hookbase.client.hook.base.MethodInvocationStub.HookInvocationHandler
    private class HookInvocationHandler implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            MethodProxy methodProxy = getMethodProxy(method.getName());//根据方法名找到对应的MethodProxy
            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 {
                //start==具体的代理逻辑
                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;
                //end==具体的代理逻辑
    
    
            } 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);
                    }
                }
            }
        }
    }
    

    我们看到了非常熟悉的InvocationHandler接口,反射调用到代理对象的方法时会回调到其invoke()方法,此时根据方法名找到对应的MethodProxy对象,接下来就是代理的逻辑了。
    那么代理对象是在哪被构造的呢?

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

    inject()

    通过上面对onBindMethods()方法以及addMethodProxy(MethodProxy methodProxy)方法的跟踪分析,我们明白了代理对象是如何被构造的。那么代理对象是何时被替换的呢?
    那就是我们的inject()方法了,举个栗子

    public class AStub extends MethodInvocationProxy<MethodInvocationStub<IA>> {
    
    
        public AStub() {
            super(new MethodInvocationStub<IA>(StoreApplication.mA));
        }
    
    
        @Override
        protected void onBindMethods() {
            super.onBindMethods();
            addMethodProxy(new A1MethodProxy());
        }
    
    
        @Override
        public void inject() throws Exception {
            IA proxyInterface = getInvocationStub().getProxyInterface();
            StoreApplication.mA = proxyInterface;
        }
    
    
        @Override
        public boolean isEnvBad() {
            return false;
        }
    }
    

    那inject()方法是在何时被调用的呢?

    public void injectAll() throws Exception {
        for (IInjector injector : mInjectors.values()) {
            injector.inject();
        }
    }
    

    injectAll()方法遍历调用了所有代理对象的注入方法,那哪里调用了injectAll

      public static void setMyselfHooK(Context context) {
                    ...
            gCore.mContext = context;
            VEnvironment.systemReady();
            gCore.detectProcessType(context, context.getApplicationInfo().processName);
            IORedirectManager.getInstance().init(gCore.getVDeviceInfo());
            try {
                InvocationStubManager invocationStubManager = InvocationStubManager.getInstance();
                invocationStubManager.init();
                invocationStubManager.injectAll();
            } catch (Exception e) {
                e.printStackTrace();
            }
            ...
        }
    

    继续跟下哪里调用的setMyselfHooK

    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        try {
            LogToolManager.getInstance().init(VEnvironment.getLogsDir());
            LogTool.w(Constant.AD_TAG, "-----AdApplication attachBaseContext");
            HookCore.setMyselfHooK(base);
        } catch (Exception e) {
            LogTool.w(Constant.AD_TAG, "" + e.getMessage());
        }
    }
    

    跟到这里我们清楚了所有代理类的注入时机是在Application#attachBaseContext方法中。

    普通类方法的动态代理

    相关类的构造

    public interface IA {
        int a1();
        int a2();
    }
    

    被代理类

    public class A implements IA {
    
    
        public int a1(){
            return 1;
        }
    
    
        public int a2(){
            return 2;
        }
    }
    

    代理方法抽象

    public class A1MethodProxy extends MethodProxy {
        @Override
        public String getMethodName() {
            return "a1";
        }
        @Override
        public boolean beforeCall(Object who, Method method, Object... args) {
            return super.beforeCall(who, method, args);
        }
        @Override
        public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {
            return super.afterCall(who, method, args, result);
        }
        @Override
        public Object call(Object who, Method method, Object... args) throws Throwable {
            return 111;
    //        return super.call(who, method, args);
        }
    }
    
    public class AStub extends MethodInvocationProxy<MethodInvocationStub<IA>> {
        public AStub() {
            super(new MethodInvocationStub<IA>(StoreApplication.mA));
        }
        @Override
        protected void onBindMethods() {
            super.onBindMethods();
            addMethodProxy(new A1MethodProxy());//添加需要被代理的方法
        }
        @Override
        public void inject() throws Exception {
            IA proxyInterface = getInvocationStub().getProxyInterface();
            StoreApplication.mA = proxyInterface;
        }
        @Override
        public boolean isEnvBad() {//代理是否生效的开关
            return false;
        }
    }
    

    添加代理桩

    private void injectInternal() throws Exception {
            addInjector(new ConnectivityStub());
            addInjector(new ActivityManagerStub());
            addInjector(new PackageManagerStub());
            addInjector(new LocationManagerStub());
            //addInjector(new DisplayStub()); Xpose Hook的
            addInjector(new ISubStub());
            addInjector(new PhoneSubInfoStub());
            addInjector(new TelephonyStub());
            addInjector(new WifiManagerStub());
            addInjector(new BluetoothStub());
    
    
            Class<?> clz = Class.forName("com.zookingsoft.themestore.proxytest.AStub");
            IInjector iInjector = (IInjector)clz.newInstance();
            addInjector(iInjector);//代理测试
        }
    

    Binder的动态代理

    需要通过ServiceManager#getService获取binder对象的,可以采用如下动态代理方式。以hook ILocationManager接口方法为例。

    private static JSONObject getLocation(Context context) {
        LocationManager locationManager = (LocationManager) context.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
        JSONObject json = new JSONObject();
        try {
            List<String> allProviders = locationManager.getAllProviders();//通过ILocationManager调用
            if (Util.checkPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION) || Util.checkPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION)) {
                for (String pro : allProviders) {
                    Location location = locationManager.getLastKnownLocation(pro);//通过ILocationManager调用
                    if (location != null) {
                        json.put("CLCT", getLocation(location));
                    }
                }
            }
        } catch (Exception e) {
        }
        return json;
    }
    

    重点关注下context.getApplicationContext().getSystemService(Context.LOCATION_SERVICE)做了什么。我们知道ContextWrapper实际上把功能都委托给了ContextImp

    ContextImp#getSystemService
    public Object getSystemService(String name) {
        return SystemServiceRegistry.getSystemService(this, name);
    }
    

    继续跟到SystemServiceRegistry.getSystemService方法

    android.app.SystemServiceRegistry#getSystemService
    public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }
    

    看下SYSTEM_SERVICE_FETCHERS是什么

    private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();
    

    找到往SYSTEM_SERVICE_FETCHERS这个hashmap添加元素的位置

    android.app.SystemServiceRegistry#registerService
    private static <T> void registerService(String serviceName, Class<T> serviceClass,
            ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    }
    

    找到调用SystemServiceRegistry#registerService方法的位置

    final class SystemServiceRegistry {
        ...
        static {
            ...
            registerService(Context.LOCATION_SERVICE, LocationManager.class,
            new CachedServiceFetcher<LocationManager>() {
                @Override
                public LocationManager createService(ContextImpl ctx) throws ServiceNotFoundException {
                    IBinder b = ServiceManager.getServiceOrThrow(Context.LOCATION_SERVICE);
                    return new LocationManager(ctx, ILocationManager.Stub.asInterface(b));
                }});
            ...
        }
        ...
    }
    

    再看看ServiceManager.getServiceOrThrow做了什么

    public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException {
        final IBinder binder = getService(name);
        if (binder != null) {
            return binder;
        } else {
            throw new ServiceNotFoundException(name);
        }
    }
    

    最终调用到getService()方法里。

    android.os.ServiceManager#getService
    public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return Binder.allowBlocking(getIServiceManager().getService(name));
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }
    

    可以看到获取IBinder时先会去sCache缓存里找,找不到再会借助IServiceManage去找。
    至此我们可以做一个结论:每次通过ServiceManager#getService获取binder对象,最终都是先从ServiceManager中的sCache缓存中获取的,如果我们预先将代理binder添加到集合中,那么每次通过ServiceManager#getService获取到的就是我们的代理binder对象。

    下面要做的就是如何构造代理binder

    step1:构造映射类。

    public class ILocationManager {
        public static Class<?> TYPE = RefClass.load(ILocationManager.class, "android.location.ILocationManager");
    
        public static class Stub {
            public static Class<?> TYPE = RefClass.load(Stub.class, "android.location.ILocationManager$Stub");
            @MethodParams({IBinder.class})
            public static RefStaticMethod<IInterface> asInterface;
        }
    }
    

    之所以构造映射类,是为了通过封装减少繁琐的反射操作。RefClass.load(Stub.class, "android.location.ILocationManager$Stub")方法本质上就是给诸如RefStaticMethod等类型的反射字段赋值。
    step2:构造代理相关类

    @Inject(MethodProxies.class)
    public class LocationManagerStub extends BinderInvocationProxy {
        public LocationManagerStub() {
            super(ILocationManager.Stub.asInterface, Context.LOCATION_SERVICE);
        }
    
    
        @Override
        protected void onBindMethods() {
            super.onBindMethods();
            addMethodProxy(new FakeReplaceLastPkgMethodProxy("addProximityAlert", 0));
        }
    }
    

    接下来分析下Binder代理关键的两个类BinderInvocationProxy,BinderInvocationStub

    public abstract class BinderInvocationProxy extends MethodInvocationProxy<BinderInvocationStub> {
    
    
       protected String mServiceName;
    
    
       public BinderInvocationProxy(IInterface stub, String serviceName) {
          this(new BinderInvocationStub(stub), serviceName);
       }
    
    
       public BinderInvocationProxy(RefStaticMethod<IInterface> asInterfaceMethod, String serviceName) {
          this(new BinderInvocationStub(asInterfaceMethod, ServiceManager.getService.call(serviceName)), serviceName);
       }
    
    
       public BinderInvocationProxy(Class<?> stubClass, String serviceName) {
          this(new BinderInvocationStub(stubClass, ServiceManager.getService.call(serviceName)), serviceName);
       }
    
    
       public BinderInvocationProxy(BinderInvocationStub hookDelegate, String serviceName) {
          super(hookDelegate);
          this.mServiceName = serviceName;
       }
    
    
       @Override
       public void inject() throws Throwable {
          getInvocationStub().replaceService(mServiceName);
       }
    
    
       @Override
       public boolean isEnvBad() {
          IBinder binder = ServiceManager.getService.call(mServiceName);
          return binder != null && getInvocationStub() != binder;
       }
    

    需要关注的是如下几点:

    • BinderInvocationProxy继承自MethodInvocationProxy
    • BinderInvocationProxy的构造方法中传入的被代理binder对象是ServiceManager.getService.call(serviceName)获取的,本质上就是反射调用了ServiceManager#getService方法(ServiceMnager是hide的)
    • getInvocationStub().replaceService(mServiceName)方法中完成代理binder的替换
      那getInvocationStub().replaceService(mServiceName)是如何完成代理binder的替换的呢?其实就是在ServiceManager的sCache缓存集合里将代理binder添加进去了。
    public void replaceService(String name) {
        if (mBaseBinder != null) {
            ServiceManager.sCache.get().put(name, this);
        }
    }
    

    下面再来分析另一个Binder代理的关键类BinderInvocationStub

    public class BinderInvocationStub extends MethodInvocationStub<IInterface> implements IBinder {
    
    
        private static final String TAG = BinderInvocationStub.class.getSimpleName();
        private IBinder mBaseBinder;//被代理的binder,本质上是一个IA.Stub
    
    
        public BinderInvocationStub(RefStaticMethod<IInterface> asInterfaceMethod, IBinder binder) {
            this(asInterface(asInterfaceMethod, binder));
        }
    
    
        public BinderInvocationStub(Class<?> stubClass, IBinder binder) {
            this(asInterface(stubClass, binder));
        }
    
    
    
    
        public BinderInvocationStub(IInterface mBaseInterface) {
            super(mBaseInterface);
            mBaseBinder = getBaseInterface() != null ? getBaseInterface().asBinder() : null;
            addMethodProxy(new AsBinder());
        }
    
    
        private static IInterface asInterface(RefStaticMethod<IInterface> asInterfaceMethod, IBinder binder) {
            if (asInterfaceMethod == null || binder == null) {
                return null;
            }
            return asInterfaceMethod.call(binder);
        }
    
    
        private static IInterface asInterface(Class<?> stubClass, IBinder binder) {
            try {
                if (stubClass == null || binder == null) {
                    return null;
                }
                Method asInterface = stubClass.getMethod("asInterface", IBinder.class);
                return (IInterface) asInterface.invoke(null, binder);
            } catch (Exception e) {
                Log.d(TAG, "Could not create stub " + stubClass.getName() + ". Cause: " + e);
                return null;
            }
        }
    
    
        public void replaceService(String name) {
            if (mBaseBinder != null) {
                ServiceManager.sCache.get().put(name, this);
            }
        }
    
    
        private final class AsBinder extends MethodProxy {
    
    
            @Override
            public String getMethodName() {
                return "asBinder";
            }
    
    
            @Override
            public Object call(Object who, Method method, Object... args) throws Throwable {
                return BinderInvocationStub.this;
            }
        }
    
    
    
    
        @Override
        public String getInterfaceDescriptor() throws RemoteException {
            return mBaseBinder.getInterfaceDescriptor();
        }
    
    
        public Context getContext() {
            return VirtualCore.get().getContext();
        }
    
    
        @Override
        public boolean pingBinder() {
            return mBaseBinder.pingBinder();
        }
    
    
        @Override
        public boolean isBinderAlive() {
            return mBaseBinder.isBinderAlive();
        }
    
    
        @Override
        public IInterface queryLocalInterface(String descriptor) {//IA.Stub.asInterface(b)内部会调用到queryLocalInterface方法
            return getProxyInterface();
        }
    
    
        @Override
        public void dump(FileDescriptor fd, String[] args) throws RemoteException {
            mBaseBinder.dump(fd, args);
        }
    
    
        @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
        @Override
        public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
            mBaseBinder.dumpAsync(fd, args);
        }
    
    
        @Override
        public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            return mBaseBinder.transact(code, data, reply, flags);
        }
    
    
        @Override
        public void linkToDeath(DeathRecipient recipient, int flags) throws RemoteException {
            mBaseBinder.linkToDeath(recipient, flags);
        }
    
    
        @Override
        public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
            return mBaseBinder.unlinkToDeath(recipient, flags);
        }
    
    
        public IBinder getBaseBinder() {
            return mBaseBinder;
        }
    }
    

    需要重点关注的是如下几点:

    • BinderInvocationStub继承自MethodInvocationStub,更重要的是它实现了IBinder。
    • 那么它为何要实现Binder呢?如上面所述,在replaceService方法中它获取到了一个代理Binder用于添加到缓存集合中,而这个代理binder正是BinderInvocationStub它自己。
    • 如果BinderInvocationStub作为代理binder,但是却未实现ILocationManager接口,它如何能够代理掉ILocationManager接口中的那些方法呢?
      我们回顾下获取binder之后做了啥,以LocationManager为例
    return new LocationManager(ctx, ILocationManager.Stub.asInterface(b))
    

    他需要将Binder通过ILocationManager.Stub.asInterface转换为IInterface类型的接口,那我们看看ILocationManager.Stub.asInterface做了啥

    public static cc.abto.demo.UserManager asInterface(android.os.IBinder obj){
          if ((obj == null))
          {
          return null;
          }
          android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
          if (((iin != null) && (iin instanceof cc.abto.demo.UserManager)))
          {
          return ((cc.abto.demo.UserManager) iin);
          }
          return new cc.abto.demo.UserManager.Stub.Proxy(obj);
    }
    

    先会调用queryLocalInterface方法询问该接口是本进程的接口,如果不为空就直接返回。而在BinderInvocationStub中我们重写了queryLocalInterface方法,并返回了getProxyInterface方法返回的代理对象。
    至此我们明白了BinderInvocationStub作为代理binder是如何代理aidl接口中的方法的。

    相关文章

      网友评论

          本文标题:如何使用VirtualApp的动态代理框架做动态代理

          本文链接:https://www.haomeiwen.com/subject/cpgqtctx.html