VirtulApp

查看任意一個(gè)系統(tǒng)服務(wù)的stub

public class PowerManagerStub extends BinderInvocationProxy {

關(guān)鍵點(diǎn)是類BinderInvocationProxy
這個(gè)類繼承于MethodInvocationProxy
最后會調(diào)用到
mInvocationStub.addMethodProxy

Virtul有一個(gè)引擎叫做io.virtualapp:x

            VirtualCore.get().waitForEngine();

啟動native的引擎
public void waitForEngine() {
ServiceManagerNative.ensureServerStarted();
}

看看點(diǎn)擊一個(gè)應(yīng)用的調(diào)用順序


start一個(gè)activity

媽的 直接從binder就已經(jīng)hook住了M匦汀毕箍!
內(nèi)部虛擬了一套啟動流程帝美。

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

這個(gè)定義了ActivityManage的代理對象,代理了所有的方法。

看看這個(gè)類的定義
public class ActivityManagerStub extends MethodInvocationProxy<MethodInvocationStub<IInterface>> {

看看他的構(gòu)造函數(shù)
super(new MethodInvocationStub<>(ActivityManagerNative.getDefault.call()));
媽耶 構(gòu)造函數(shù)好怪嗎,沒有看到ActivityManagerNative.getDefault有new澳跫Α!栏豺!
field.set(null, constructor.newInstance(realClass, field));
設(shè)置一個(gè)變量
相當(dāng)與 (field = 使用構(gòu)造函數(shù))構(gòu)造一個(gè)東西彬碱,這個(gè)構(gòu)造函數(shù)有兩個(gè)參數(shù)
public RefObject(Class<?> cls, Field field) throws NoSuchFieldException {
this.field = cls.getDeclaredField(field.getName());
this.field.setAccessible(true);
}
看上面,field實(shí)際上就是系統(tǒng)中ActivityManagerNative的field奥洼。巷疼。。臥槽灵奖,因?yàn)閏ls就是android.app.ActivityManagerNative

//在inject的時(shí)候構(gòu)造了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的呢嚼沿??還是要看啟動流程瓷患。

應(yīng)該是做了動態(tài)代理的骡尽。但是動態(tài)代理需要靜態(tài)變量才行啊。

可以看到binder的回調(diào)時(shí)在
public class TransformBinder extends Binder {
這個(gè)東西是在類public class IPCBus {
中實(shí)例化的

    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中實(shí)例化的。傳入了一個(gè)IServerCache,看上去是緩存服務(wù)的寂曹。
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());
進(jìn)而調(diào)用
sCache.join(serverInterface.getInterfaceName(), binder);

                ServiceCache.addService(serverName, binder);

感覺就是把TransformBinder和VActivityManagerService連接起來了。

所以服務(wù)應(yīng)該都是通過ServiceCache來找谭贪。

所以我們找一下點(diǎn)擊后發(fā)生了什么,應(yīng)該就知道了锦担。
找點(diǎn)擊的入口俭识。
下面這個(gè)是入口,很快找到6从妗鱼的!
mPresenter.launchApp(data);
data數(shù)據(jù)如下


image.png

最后會在LoadingActivity中啟動應(yīng)用

    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函數(shù)才真正去用假裝的ActivityManager(VActivityManager)去拉起他T彻妗V钥臁!
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)

有一個(gè)單例
private IPCSingleton<IActivityManager> singleton = new IPCSingleton<>(IActivityManager.class);

最后還搞了個(gè)動態(tài)代理

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

動態(tài)代理有三個(gè)參數(shù)姨俩,一個(gè)是classloader蘸拔,一個(gè)是class 的interface师郑,第三個(gè)是代理對象。
put的時(shí)候是怎么put的调窍?宝冕?
IPCBus.register(IActivityManager.class, VActivityManagerService.get());

最終保存在sCache中,key是name邓萨,value是binder
就這里來說地梨,key應(yīng)該是com.lody.virtual.server.interfaces.IActivityManager,
value是public class VActivityManagerService implements IActivityManager
VActivityManagerService也是一個(gè)IActivityManager

終于來到了動態(tài)代理對象這里
public class IPCInvocationBridge implements InvocationHandler {

如何建立起來關(guān)系呢缔恳?宝剖?
binder

天 找到了,通過IServiceFetcherd.aidl文件實(shí)現(xiàn)binder通信歉甚。
BinderProvider是服務(wù)端万细,而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的實(shí)體在類BinderProvider中砰诵。

最終在IPCInvocationBridge類中征唬,用代理去執(zhí)行方法

    @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實(shí)體是什么?
TransformBinder

服務(wù)端如何管理Activity茁彭?总寒??

原來是使用一個(gè)provider來表示一個(gè)進(jìn)程

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

創(chuàng)建進(jìn)程會進(jìn)入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;
    }

后面調(diào)用VClientImpl的initProcess方法來執(zhí)行新建程序摄闸。

實(shí)際VClientImpl就是一個(gè)客戶端。

virtulcore的startActivity會進(jìn)入到HookInvocationHandler妹萨,難道是動態(tài)代理了年枕??

還有一個(gè)MethodInvocationStub乎完?熏兄?

在構(gòu)造ActivityManagerStub的時(shí)候new 了他出來!!
super(new MethodInvocationStub<>(ActivityManagerNative.getDefault.call()));

貌似對gDefault進(jìn)行了動態(tài)代理
Singleton.mInstance.set(gDefault, getInvocationStub().getProxyInterface());

getInvocationStub是什么摩桶?

看上去任何方法都會去到
MethodInvocationStub的HookInvocationHandler動態(tài)代理中處理桥状。

代理方法貌似在
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);
}
這個(gè)who就是原生的class android.app.ActivityManagerProxy

哪個(gè)過程啟動正式的Activity呢?貌似是下面的過程硝清。因?yàn)橛術(shù)ettype的操作辅斟。


image.png

看看啟動應(yīng)用的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這個(gè)東西了。
從這里inject進(jìn)來了
addInjector(AppInstrumentation.getDefault());

基本上發(fā)現(xiàn)了他的指導(dǎo)思想了芦拿,就是每一個(gè)代理都有一個(gè)base士飒,這個(gè)base來自與mirror。通過inject方法實(shí)現(xiàn)動態(tài)代理防嗡。

后續(xù)在啟動一個(gè)頁面會怎樣变汪,會再次startActivity,然后有啟動c0的stub蚁趁,然后在用inject的instrmentation去處理裙盾。

通過下面這句修改了進(jìn)程名字
VirtualRuntime.setupRuntime(data.processName, data.appInfo);

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市他嫡,隨后出現(xiàn)的幾起案子番官,更是在濱河造成了極大的恐慌,老刑警劉巖钢属,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件徘熔,死亡現(xiàn)場離奇詭異,居然都是意外死亡淆党,警方通過查閱死者的電腦和手機(jī)酷师,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來染乌,“玉大人山孔,你說我怎么就攤上這事『杀铮” “怎么了台颠?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長勒庄。 經(jīng)常有香客問我串前,道長,這世上最難降的妖魔是什么实蔽? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任荡碾,我火速辦了婚禮,結(jié)果婚禮上局装,老公的妹妹穿的比我還像新娘玩荠。我一直安慰自己漆腌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布阶冈。 她就那樣靜靜地躺著,像睡著了一般塑径。 火紅的嫁衣襯著肌膚如雪女坑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天统舀,我揣著相機(jī)與錄音匆骗,去河邊找鬼。 笑死誉简,一個(gè)胖子當(dāng)著我的面吹牛碉就,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闷串,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼瓮钥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了烹吵?” 一聲冷哼從身側(cè)響起碉熄,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肋拔,沒想到半個(gè)月后锈津,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凉蜂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年琼梆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窿吩。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡茎杂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出爆存,到底是詐尸還是另有隱情蛉顽,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布先较,位于F島的核電站携冤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏闲勺。R本人自食惡果不足惜曾棕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望菜循。 院中可真熱鬧翘地,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至橙喘,卻和暖如春时鸵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厅瞎。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工饰潜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人和簸。 一個(gè)月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓彭雾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親锁保。 傳聞我的和親對象是個(gè)殘疾皇子薯酝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容