启动没有在 AndroidManifest 中注册的 Activity

本文介绍了一种在Android中启动未在AndroidManifest.xml中注册的Activity的方法,通过hook ActivityManager.getService()和ActivityThread#mH#mCallback,绕过系统验证,实现目标Activity的启动。

一、报错

启动没有在 AndroidManifest 中注册的 Activity,会报错:

android.content.ActivityNotFoundException: Unable to find explicit activity class {...}; have you declared this activity in your AndroidManifest.xml?

二、思路

Android 使用的是 C/S 架构,我们的 app 是 client 客户端,内核是 Server 服务端。

Activity 是否注册的验证是在服务端进行的,所以我们客户端无法修改判断条件。但我们可以修改客户端的请求,让服务端以为我们要启动的是另外一个已注册的 Acitivity,在客户端得到启动许可后,再去启动真正的目标 Activity。

这一操作要通过 hook 来实现。

在这里插入图片描述

三、启动流程

android 28 启动流程:
在这里插入图片描述

3.1 hook 点的选择

替换:

在 android 28 上,通过 ActivityManager.getService().startActivity() 来向服务端发起请求。所以我们要在这一步之前,将要启动的 Activity 替换为已注册的 Activity。

恢复:

通过 mInstrumentation.newActivity() 来创建 Activity。所以我们要在这一步之前,将要启动的 Activity 替换回未注册的 Activity。

本文选择的替换点是 ActivityManager.getService().startActivity(),即要 hook ActivityManager.getService()

恢复点是:ActivityThread#mH.handleMessage(),即要 hook ActivityThread#mH#mCallback

3.2 版本差异

获取 AMSP:

  • android 26 及以上:
    ActivityManager.getService()

  • android 26 以下:
    ActivityManagerNative.getDefault()

处理启动 Activity 的 message:

  • android 28 及以上
    handleMessage(ActivityThread.H.EXECUTE_TRANSACTION)

  • android 28 以下:
    handleMessage(H.LAUNCH_ACTIVITY)

四、代码

完整代码见 github.com/Gdeeer

新建三个 Activity:

  • CommonActivity 已注册,用于点击跳转 TargetActivity
  • StubActivity 已注册,用于占位
  • TargetActivity 已注册,用于跳转

4.1 Hook

AMSPHookHelper

class AMSPHookHelper {
   
   
    static final String EXTRA_TARGET_INTENT = "extra_target_intent";


    static void hookAMSP() {
   
   
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
   
   
            hookAMSPBefore26();
        } else {
   
   
            hookAMSPSince26();
        }
    }


    /**
     * android 26 以下版本 AMSP 的 hook
     */
    private static void hookAMSPBefore26() {
   
   
        try {
   
   
            Class classActivityManagerNative = Class.forName("android.app.ActivityManagerNative");
            Object gDefault = FieldUtils.readStaticField(classActivityManagerNative, "gDefault");
            Object mInstance = FieldUtils.readField(gDefault, "mInstance");
            Class classIActivityManager = Class.forName("android.app.IActivityManager");
            Object proxy = Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),
                new Class[]{
   
   classIActivityManager},
                new MockAMSP(mInstance)
            );

            FieldUtils.writeField(gDefault, "mInstance", proxy);
        } catch (Exception e) {
   
   
            e.printStackTrace();
        }
    }


    /**
     * android 26 及以上版本 AMSP 的 hook
     */
    private static void hookAMSPSince26() {
   
   
        try {
   
   
            Object IActivityManagerSingleton = FieldUtils.readStaticField(ActivityManager.class, "IActivityManagerSingleton");
            Object mInstance = FieldUtils.readField(IActivityManagerSingleton, "mInstance");
            Class classIActivityManager = Class.forName("android.app.IActivityManager");
            Object proxy = Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),
                new Class[]{
   
   classIActivityManager},
                new MockAMSP(mInstance)
            );

            FieldUtils.writeField(IActivityManagerSingleton, "mInstance", proxy);
        } catch (Exception e) {
   
   
            e.printStackTrace();
        }
    }

    static void hookActivityThread() {
   
   
        try {
   
   
            Class classActivityThread = Class.forName("android.app.ActivityThread");
            Object currentActivityThread = FieldUtils.readStaticField(classActivityThread, "sCurrentActivityThread");
            Handler mH = (Handler) FieldUtils.readField(currentActivityThread, "mH");
            FieldUtils.writeField(mH, "mCallback", new MockHCallback(mH));
        } catch (Exception e) {
   
   
            e.printStackTrace();
        }
    }
}

StubActivityApplication

public class StubActivityApplication extends Application {
   
   
    @Override
    protected void attachBaseContext(Context base) {
   
   
        super.attachBaseContext(base);

        // 解除 android P 上的私有 api 限制,见http://weishu.me/2018/06/07/free-reflection-above-android-p/
        Reflection.unseal(base);

        // hook
        AMSPHookHelper.hookAMSP();
        AMSPHookHelper.hookActivityThread();
    }
}

4.2 替换点

MockAMSP:

public class MockAMSP implements InvocationHandler {
   
   
    private static final String START_ACTIVITY = "startActivity";

    
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值