为了账号安全,请及时绑定邮箱和手机立即绑定

Hook Android 应用启动页

问题

前两天看到联通沃商店的 SDK 能让接入方应用的入口 Activity 在联通的闪屏页面结束之后出现, 我想他是不是才用什么黑科技 hook 了人家应用的入口Activity, 反编译了它的源码看了下,并无什么黑科技, 而是要求接入方声明它的闪屏页面为入口页面,我在想能不能在接入方无知觉的情况下 hook 应用的入口 Activity,先 hold 住等我们自定义的 Activity 完成之后再进入?

问题再简化一下:如何 hook 一个应用的入口 Activity,插入自己的Activity?

思路

我们首先要知道一个应用的入口Activiy是怎么被创建,然后被现实出来的?如果看过插件化的相关实现文章就不难理解了,我们首先来看看用户点击启动图标之后是怎么进入第一个Activity的:

明白了Activity的创建和方法调用流程我们就可以决定在哪个环节 hook 了,不难发现,我们 hook 的最佳时间是 Activity 的 onCreate 方法被调用前, 也就是Instrumentation 的 callActivityOnCreate 方法,我们把它拦截掉, 怎么做?
你需要知道个知识点: 反射代理。我假定读我的文章的人都熟悉反射和代理了。

反射获取 Instrumentation

首先通过反射获取应用进程的 Instrumentation 对象,再来看看 Instrumentation 相关的引用关系:
ActivityThread -> Instrumentation
见 ActivityThread.java 中代码:

Instrumentation mInstrumentation;

现在我们想办法拿到 ActivityThread 的实例对象:

public static final ActivityThread currentActivityThread() {
 return sThreadLocal.get();
}

所以我们可以先反射 currentActivityThread() 方法拿到 ActivityThread 当前实例, 再反射 mInstrumentation 拿到 Instrumentation 对象。

      //获取当前的ActivityThread对象
        Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
        Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
        currentActivityThreadMethod.setAccessible(true);
        Object currentActivityThread = currentActivityThreadMethod.invoke(null);

        //拿到在ActivityThread类里面的原始mInstrumentation对象
        Field mInstrumentationField = activityThreadClass.getDeclaredField("mInstrumentation");
        mInstrumentationField.setAccessible(true);
        Instrumentation mInstrumentation = (Instrumentation) 
      mInstrumentationField.get(currentActivityThread);

获取了 Instrumentation 对象怎么拦截里面的方法?如果是接口实现类直接使用 JDK 的动态代理就能实现拦截, 这里只能使用静态代理, 我们自己创建一个 Instrumentation 的子类 ,就叫 InstrumentationProxy 吧,InstrumentationProxy 代替原来的 Instrumentation。

   //包装代理
        Instrumentation evilInstrumentation = new InstrumentationProxy(mInstrumentation);

        // 偷梁换柱

        mInstrumentationField.set(currentActivityThread, evilInstrumentation);

InstrumentationProxy 的实现:

public class InstrumentationProxy extends Instrumentation {

 public static final String TAG = "InstrumentationProxy";
 public Instrumentation target;

 //通过构造函数来传递对象
 public InstrumentationProxy(Instrumentation mInstrumentation) {
     target = mInstrumentation;
 }
 @Override
public void callActivityOnCreate(Activity activity, Bundle icicle) {
           // 就在这儿,干你想干的坏事

        target.callActivityOnCreate(activity, icicle);
 }

}

设计实现

以上算是完成了可行性技术预研, 接下来回到我们开头提的那个业务问题,就是针对问题的设计了, 首次启动时 hook 入口Acitvity。

首次启动注入广告

demo

https://github.com/liuguangli/HookLaunchActivity

点击查看更多内容
7人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
全栈工程师
手记
粉丝
1万
获赞与收藏
872

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消