VirtulApp

查看任意一个系统服务的stub

public class PowerManagerStub extends BinderInvocationProxy {

关键点是类BinderInvocationProxy
这个类继承于MethodInvocationProxy
最后会调用到
mInvocationStub.addMethodProxy

Virtul有一个引擎叫做io.virtualapp:x

            VirtualCore.get().waitForEngine();

启动native的引擎
public void waitForEngine() {
ServiceManagerNative.ensureServerStarted();
}

看看点击一个应用的调用顺序


start一个activity

妈的 直接从binder就已经hook住了!!
内部虚拟了一套启动流程。

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

这个定义了ActivityManage的代理对象,代理了所有的方法。

看看这个类的定义
public class ActivityManagerStub extends MethodInvocationProxy<MethodInvocationStub<IInterface>> {

看看他的构造函数
super(new MethodInvocationStub<>(ActivityManagerNative.getDefault.call()));
妈耶 构造函数好怪吗,没有看到ActivityManagerNative.getDefault有new啊!!
field.set(null, constructor.newInstance(realClass, field));
设置一个变量
相当与 (field = 使用构造函数)构造一个东西,这个构造函数有两个参数
public RefObject(Class<?> cls, Field field) throws NoSuchFieldException {
this.field = cls.getDeclaredField(field.getName());
this.field.setAccessible(true);
}
看上面,field实际上就是系统中ActivityManagerNative的field。。。卧槽,因为cls就是android.app.ActivityManagerNative

//在inject的时候构造了stub
05-15 08:36:26.857 14727 14727 I RefClass: at mirror.RefClass.load(RefClass.java:35)
05-15 08:36:26.857 14727 14727 I RefClass: at mirror.android.app.ActivityManagerNative.<clinit>(ActivityManagerNative.java:11)
05-15 08:36:26.857 14727 14727 I RefClass: at com.lody.virtual.client.hook.proxies.am.ActivityManagerStub.<init>(ActivityManagerStub.java:44)
05-15 08:36:26.857 14727 14727 I RefClass: at com.lody.virtual.client.core.InvocationStubManager.injectInternal(InvocationStubManager.java:118)

那他如何hook住binder的呢??还是要看启动流程。

应该是做了动态代理的。但是动态代理需要静态变量才行啊。

可以看到binder的回调时在
public class TransformBinder extends Binder {
这个东西是在类public class IPCBus {
中实例化的

    public static void register(Class<?> interfaceClass, Object server) {
        checkInitialized();
        ServerInterface serverInterface = new ServerInterface(interfaceClass);
        TransformBinder binder = new TransformBinder(serverInterface, server);
        sCache.join(serverInterface.getInterfaceName(), binder);
    }

IPCBus是在VirtualCore中实例化的。传入了一个IServerCache,看上去是缓存服务的。
IPCBus.initialize(new IServerCache() {
@Override
public void join(String serverName, IBinder binder) {
ServiceCache.addService(serverName, binder);
}

            @Override
            public IBinder query(String serverName) {
                return ServiceManagerNative.getService(serverName);
            }
        });

怀疑是这句顶替了binder
IPCBus.register(IActivityManager.class, VActivityManagerService.get());
进而调用
sCache.join(serverInterface.getInterfaceName(), binder);

                ServiceCache.addService(serverName, binder);

感觉就是把TransformBinder和VActivityManagerService连接起来了。

所以服务应该都是通过ServiceCache来找。

所以我们找一下点击后发生了什么,应该就知道了。
找点击的入口。
下面这个是入口,很快找到!!
mPresenter.launchApp(data);
data数据如下


image.png

最后会在LoadingActivity中启动应用

    public static void launch(Context context, String packageName, int userId) {
        Intent intent = VirtualCore.get().getLaunchIntent(packageName, userId);
        if (intent != null) {
            Intent loadingPageIntent = new Intent(context, LoadingActivity.class);
            loadingPageIntent.putExtra(PKG_NAME_ARGUMENT, packageName);
            loadingPageIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            loadingPageIntent.putExtra(KEY_INTENT, intent);
            loadingPageIntent.putExtra(KEY_USER, userId);
            context.startActivity(loadingPageIntent);
        }
    }

天,终于找到,原来上面的确是启动了LoadingActivity,但是在他的oncreate函数才真正去用假装的ActivityManager(VActivityManager)去拉起他!!!
VActivityManager.get().startActivity(intent, userId);

我们看看查找代理的过程

05-15 09:30:42.389 18979 19006 I IServerCache: querycom.lody.virtual.server.interfaces.IActivityManager
05-15 09:30:42.389 18979 19006 I IServerCache: java.lang.Throwable
05-15 09:30:42.389 18979 19006 I IServerCache:  at com.lody.virtual.client.core.VirtualCore$1.query(VirtualCore.java:194)
05-15 09:30:42.389 18979 19006 I IServerCache:  at com.lody.virtual.helper.ipcbus.IPCBus.get(IPCBus.java:35)
05-15 09:30:42.389 18979 19006 I IServerCache:  at com.lody.virtual.helper.ipcbus.IPCSingleton.get(IPCSingleton.java:19)
05-15 09:30:42.389 18979 19006 I IServerCache:  at com.lody.virtual.client.ipc.VActivityManager.getService(VActivityManager.java:52)
05-15 09:30:42.389 18979 19006 I IServerCache:  at com.lody.virtual.client.ipc.VActivityManager.startActivity(VActivityManager.java:58)
05-15 09:30:42.389 18979 19006 I IServerCache:  at com.lody.virtual.client.ipc.VActivityManager.startActivity(VActivityManager.java:80)
05-15 09:30:42.389 18979 19006 I IServerCache:  at io.virtualapp.home.LoadingActivity.lambda$onCreate$0$LoadingActivity(LoadingActivity.java:71)

有一个单例
private IPCSingleton<IActivityManager> singleton = new IPCSingleton<>(IActivityManager.class);

最后还搞了个动态代理

    public static <T> T get(Class<?> interfaceClass) {
        checkInitialized();
        ServerInterface serverInterface = new ServerInterface(interfaceClass);
        IBinder binder = sCache.query(serverInterface.getInterfaceName());
        if (binder == null) {
            return null;
        }
        //noinspection unchecked
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new IPCInvocationBridge(serverInterface, binder));
    }

动态代理有三个参数,一个是classloader,一个是class 的interface,第三个是代理对象。
put的时候是怎么put的??
IPCBus.register(IActivityManager.class, VActivityManagerService.get());

最终保存在sCache中,key是name,value是binder
就这里来说,key应该是com.lody.virtual.server.interfaces.IActivityManager,
value是public class VActivityManagerService implements IActivityManager
VActivityManagerService也是一个IActivityManager

终于来到了动态代理对象这里
public class IPCInvocationBridge implements InvocationHandler {

如何建立起来关系呢??
binder

天 找到了,通過IServiceFetcherd.aidl文件實現binder通信。
BinderProvider是服务端,而ServiceManagerNative是客户端。

获取代理的过程中,为什么要获取contentprovider??
private static ContentProviderClient acquireContentProviderClient(Context context, Uri uri) {
if (VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
return context.getContentResolver().acquireUnstableContentProviderClient(uri);
}
return context.getContentResolver().acquireContentProviderClient(uri);
}

返回bundle干嘛??

bundle怎么返回的,查看BinderProvider类

    @Override
    public Bundle call(String method, String arg, Bundle extras) {
        if ("@".equals(method)) {
            Bundle bundle = new Bundle();
            BundleCompat.putBinder(bundle, "_VA_|_binder_", mServiceFetcher);
            return bundle;
        }
        if ("register".equals(method)) {

        }
        return null;
    }

所以最终client获得了ServiceFetcher的代理。。。ServiceFetcher的实体在类BinderProvider中。

最终在IPCInvocationBridge类中,用代理去执行方法

    @Override
    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
        IPCMethod ipcMethod = serverInterface.getIPCMethod(method);
        if (ipcMethod == null) {
            throw new IllegalStateException("Can not found the ipc method : " + method.getDeclaringClass().getName() + "@" +  method.getName());
        }
        return ipcMethod.callRemote(binder, args);
    }

传递的binder实体是什么?
TransformBinder

服务端如何管理Activity???

原来是使用一个provider来表示一个进程

        <provider
            android:name="com.lody.virtual.client.stub.StubContentProvider$C47"
            android:authorities="${applicationId}.virtual_stub_47"
            android:exported="false"
            android:process=":p47" />

创建进程会进入public class StubContentProvider extends ContentProvider {
的call方法,如下

    @Override
    public Bundle call(String method, String arg, Bundle extras) {
        if ("_VA_|_init_process_".equals(method)) {
            return initProcess(extras);
        }
        return null;
    }

    private Bundle initProcess(Bundle extras) {
        ConditionVariable lock = VirtualCore.get().getInitLock();
        if (lock != null) {
            lock.block();
        }
        IBinder token = BundleCompat.getBinder(extras,"_VA_|_binder_");
        int vuid = extras.getInt("_VA_|_vuid_");
        VClientImpl client = VClientImpl.get();
        client.initProcess(token, vuid);
        Bundle res = new Bundle();
        BundleCompat.putBinder(res, "_VA_|_client_", client.asBinder());
        res.putInt("_VA_|_pid_", Process.myPid());
        return res;
    }

后面调用VClientImpl的initProcess方法来执行新建程序。

实际VClientImpl就是一个客户端。

virtulcore的startActivity会进入到HookInvocationHandler,难道是动态代理了??

还有一个MethodInvocationStub??

在构造ActivityManagerStub的时候new 了他出来!!
super(new MethodInvocationStub<>(ActivityManagerNative.getDefault.call()));

貌似对gDefault进行了动态代理
Singleton.mInstance.set(gDefault, getInvocationStub().getProxyInterface());

getInvocationStub是什么?

看上去任何方法都会去到
MethodInvocationStub的HookInvocationHandler动态代理中处理。

代理方法貌似在
package com.lody.virtual.client.hook.proxies.am;
class MethodProxies {

可以看到流程控制是在MethodInvocationStub
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);
}

最后掉用 if (ComponentUtils.isStubComponent(intent)) {
return method.invoke(who, args);
}
这个who就是原生的class android.app.ActivityManagerProxy

哪个过程启动正式的Activity呢?貌似是下面的过程。因为有gettype的操作。


image.png

看看启动应用的oncreate堆栈

05-15 22:54:35.601  6370  6370 I MainActivity: onCreate
05-15 22:54:35.601  6370  6370 I MainActivity: java.lang.Throwable
05-15 22:54:35.601  6370  6370 I MainActivity:  at com.wenfengtou.wftgallery.MainActivity.onCreate(MainActivity.java:35)
05-15 22:54:35.601  6370  6370 I MainActivity:  at android.app.Activity.performCreate(Activity.java:6682)
05-15 22:54:35.601  6370  6370 I MainActivity:  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
05-15 22:54:35.601  6370  6370 I MainActivity:  at com.lody.virtual.client.hook.delegate.InstrumentationDelegate.callActivityOnCreate(InstrumentationDelegate.java:244)
05-15 22:54:35.601  6370  6370 I MainActivity:  at com.lody.virtual.client.hook.delegate.AppInstrumentation.callActivityOnCreate(AppInstrumentation.java:96)
05-15 22:54:35.601  6370  6370 I MainActivity:  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2619)
05-15 22:54:35.601  6370  6370 I MainActivity:  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2727)

看来他是hook了mInstrumentation这个东西了。
从这里inject进来了
addInjector(AppInstrumentation.getDefault());

基本上发现了他的指导思想了,就是每一个代理都有一个base,这个base来自与mirror。通过inject方法实现动态代理。

后续在启动一个页面会怎样,会再次startActivity,然后有启动c0的stub,然后在用inject的instrmentation去处理。

通过下面这句修改了进程名字
VirtualRuntime.setupRuntime(data.processName, data.appInfo);

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,188评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,464评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,562评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,893评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,917评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,708评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,430评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,342评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,801评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,976评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,115评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,804评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,458评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,008评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,135评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,365评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,055评论 2 355

推荐阅读更多精彩内容