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

2019-05-27  本文已影响0人  taoyyyy

前言

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

几个关键类

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

Binder的动态代理

几个关键方法

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;
   }

需要关注的是如下几点:

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;
    }
}

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

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接口中的方法的。

上一篇下一篇

猜你喜欢

热点阅读