hook AMS

通过了解activity启动流程,我们知道当调用startActivity后,会通过ipc和ActivityManagerService服务
进行通信,然后做任务栈管理,包的解析等等工作,最终调用ActivityThread中的scheduleLaunchActivity方法
来启动新的activity。 
了解这一基本知识后,我来练习一个小demo: 拦截ActivityManagerService 和 系统Handler ,加载一个没有注册的activity.

为什么拦截ActivityManagerService呢?
因为在自己的app进程中只能拦截我们自己的 ActivityManagerService 对象。(aidl对象),无法跨进程拦截
别的服务的对象。


hook 流程:
 一、先hook 我们进程中的IActivityManager 对象。(aidl对象),用动态代理模式来代理出这个对象。
 二、由于activity没有注册 是不能通过包管理器服务 检验的,所以 我们要找一个合格的activity来替换。
     因此 需要拦截startActivity方法,并修改意图。改为一个合格的activity意图。(ProxyIntent)
三、 在ProxyIntent 中 携带我们真正要启动的activity 意图。(无法通过包管理器检验的意图) 


四、通过管理器检验后将代理意图(ProxyIntent)替换回来 我们需要的意图。
    这一步需要拦截系统Handler,在系统handler启动activity之前替换意图。

代码如下:

先拦截ActivityManagerService

/**
     * 通过源码 得知当调用startActivity后 最终调用到AMS的startActivity.
     * 我们这里来拦截AMS 对象。(并修改intent)
     */
    public void hookActivityManagerService() {
        //instumentation  --execStartActivity

        //ActivityManagerNative.getDefault().startActivity
        //getDefault() :
        // private static final Singleton<IActivityManager> gDefault
        // = new Singleton<IActivityManager>()

        //第一步 :通过反射拿到AMS对象

        try {
            Class amNativeClazz = Class.forName("android.app.ActivityManagerNative");
            //拿到单例对象
            Field field = amNativeClazz.getDeclaredField("gDefault");
            field.setAccessible(true);
            Object singletonObj = field.get(null);

            //通过单例对象 拿到AMS对象
            //ams 对象是个普通成员,所以必须通过单例对象来获得。

            Class singletonClazz = Class.forName("android.util.Singleton");
            Method getMethod = singletonClazz.getDeclaredMethod("get");
            //最后获得 ams 对象
            Object amsObj = getMethod.invoke(singletonObj);

            // 第二部:拦截 ams对象,(用代理对象替换原来对象)这里用动态代理来实现。
            // 使用一个代理对象来包装ams对象。

            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            //真实对象实现的接口   的 Class
            Class interfaceClass = Class.forName("android.app.IActivityManager");
            // 生成我们的代理对象
            //
            MyInvoketionHandler myHandler = new MyInvoketionHandler(amsObj);

            Object proxyObj = Proxy.newProxyInstance(classLoader, new Class[]{interfaceClass}, myHandler);

            //用代理对象替换原来对象

            Field fInstance = singletonClazz.getDeclaredField("mInstance");
            fInstance.setAccessible(true);
            //替换singleton的instance对象
            fInstance.set(singletonObj, proxyObj);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

  class MyInvoketionHandler implements InvocationHandler {

        //真正的ams对象
        Object realAmsObj;

        public MyInvoketionHandler(Object realAmsObj) {
            this.realAmsObj = realAmsObj;
        }


        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

            // 拦截我们要拦截的方法
            String methodName = method.getName();
            //拦截startActivity方法 替换一个假的 意图,用来通过包管理器 检查。
            if (methodName.contains("startActivity")) {
                int len = args.length;
                // 查找startActivity 的参数
                for (int i = 0; i < len; i++) {
                    Object argsi = args[i];

                    if (argsi instanceof Intent) {
                        // 原来的意图 : 不合法的,因为没有注册此activity
                        Intent intent = (Intent) argsi;
                        ComponentName name = intent.getComponent();

                        // 创建新的假的意图
                        Intent newIntent = new Intent();
                        ComponentName newComponentName = new ComponentName(context, proxyActivityClazz);
                        // setClass 也可以
                        newIntent.setComponent(newComponentName);

                        // 用假的意图装载原来真的意图
                        newIntent.putExtra(TAG, intent);

                        // 替换真实意图
                        args[i] = newIntent;

                        return method.invoke(realAmsObj, args);
                    }

                }

            }


            return method.invoke(realAmsObj, args);
        }
    }


然后拦截系统Handler

    /**
     * 包管理服务 验证完后 通过Activity中的handler 来发送启动新 activity 的消息。
     * 那么就在这里 把原来代理意图 再次替换回来 ,就完成了 不用清单注册 的功能。
     */
    public void hookSysHandler() {

        // 从源码可以得知  ActivityThread 是单例的
        //private static volatile ActivityThread sCurrentActivityThread;
        // 系统的handler :负责启动activity,service 等等。
        //final H mH = new H();


        try {
            Class activityThreadClass = Class.forName("android.app.ActivityThread");
            //系统handler 对象
            Field handlerField = activityThreadClass.getDeclaredField("mH");
            //ActivityThread 对象
            Field activityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");

            activityThreadField.setAccessible(true);
            handlerField.setAccessible(true);


            Object activityThreadInstance = activityThreadField.get(null);
            Handler sysHandlerInstance = (Handler) handlerField.get(activityThreadInstance);

            // 通过了解handler 消息的回调机制,我们让handler先回调我们的callback
            // 然后再 回调handler 的 handMessage 方法。
            Field callBackField = Handler.class.getDeclaredField("mCallback");

            callBackField.setAccessible(true);
            // 通过了解handler源码 ,知道handler的回调机制后,我们这里来拦截 handler的回调
            // 回调完成后 再 回调原来的handMessage
            // 替换系统的Handler (相当于hook 系统handler)
            callBackField.set(sysHandlerInstance, new MyCallBack(sysHandlerInstance));//拦截 handler的回调
        } catch (Exception e) {
            e.printStackTrace();
        }


    }
// 定义我们自己的handler回调
    class MyCallBack implements Handler.Callback {
        // 系统的handler
        private Handler realHandler;

        public MyCallBack(Handler realHandler) {
            this.realHandler = realHandler;
        }

        @Override
        public boolean handleMessage(Message msg) {

            int what = msg.what;
            // 在这里将意图 替换回来。
            if (what == LAUNCH_ACTIVITY) {
                //msg.obj  就是ActivityClientRecord
                // 而就是ActivityClientRecord中就包含intent,
                try {
                    Field intentField = msg.obj.getClass().getDeclaredField("intent");
                    intentField.setAccessible(true);

                    Object activityClientRecord = msg.obj;
                    Intent proxyIntent = (Intent) intentField.get(activityClientRecord);

                    Intent realIntent = proxyIntent.getParcelableExtra(TAG);
                    if (realIntent != null) {
                        proxyIntent.setComponent(realIntent.getComponent());
                    }


                    //intentField.set(activityClientRecord,);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            realHandler.handleMessage(msg);
            return true;
        }
    }

app启动后,在Application 中拦截。

MyApplication extends Application 

  oncreate:

  HookUtil hookUtil = new HookUtil(this, ProxyActivity.class);

        hookUtil.hookActivityManagerService();
        hookUtil.hookSysHandler();


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值