Android Hook入门

Hook系统源码实现权限管理架构。
简单的一个hook思想体现:
在这里插入图片描述

1. 准备工作

点击按钮,在不更改源代码的基础上,动态修改button文字内容。

        Button button = findViewById(R.id.btn);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, "button 文本内容: " + ((Button) v).getText());
            }
        });

思路:通过hook思想,在onClick()方法执行前,修改代码即可。即 将View.OnClickListener接口对象替换成自己的代理对象。

    public void setOnClickListener(@Nullable OnClickListener l) {
    	// ....
        getListenerInfo().mOnClickListener = l;
    }

即 set进去的变量l最终赋值给getListenerInfo().mOnClickListener 也就是android.view.View.ListenerInfo#mOnClickListener变量

2. 代理一个View.OnClickListener接口对象

        /**
         * 1. 动态代理 onClickListenerProxy实质是被监听的OnClickListener接口
         */
        Object onClickListenerProxy = Proxy.newProxyInstance(
                getClassLoader(),
                // 要监听的接口,监听什么接口就返回什么接口
                new Class[]{View.OnClickListener.class},
                // 监听接口方法的回调,
                new InvocationHandler() {
                    /**
                     * void onClick(View v);
                     * @param proxy
                     * @param method 对应 onClick(View v);
                     * @param args  对应 v
                     * @return
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 加入自己的逻辑,
                        Log.e(TAG, "hook: 拦截到了OnClickListener#onClick");

                        Button button = new Button(MainActivity.this);
                        button.setText("hello hook");
                        // 让程序继续执行
                        /**
                         * method.invoke()相当于 OnClickListener 中的onClick()方法
                         * @param obj  OnClickListener对象
                         * @param args
                         */
                        return method.invoke(onClickListenerObj, button);
                    }
                }
        );

通过button.setOnClickListener设置的接口类对象,查看源码最终赋值给ListenerInfomOnClickListener变量。需要找到该变量。

3. 通过反射找到ListenerInfo的mOnClickListener属性变量

通过反射替换掉View$ListenerInfo内部类的mOnClickListener属性。

先找打ListenerInfo

// 首先找到View$ListenerInfo
Class<?> listenerInfoClass = Class.forName("android.view.View$ListenerInfo");

找到ListenerInfo类的mOnClickListener变量

// getDeclaredField 获取私有属性  2.getField获取公开属性
Field onClickListenerFiled = listenerInfoClass.getField("mOnClickListener");

4. 替换

将步骤3中找打的onClickListenerFiled属性替换为 自己代理的onClickListenerProxy

onClickListenerFiled.set(listenerInfoObj, onClickListenerProxy);

缺少onClickListenerFiled 属性的类对象listenerInfoObj。查看源码,通过执行android.view.View#getListenerInfo方法可以返回一个ListenerInfo对象。代码如下:

        // 获取 ListenerInfo对象,执行 ListenerInfo getListenerInfo()  方法就可以获得对象
        Class<?> classView = Class.forName("android.view.View");
        Method getListenerInfoMethod = classView.getDeclaredMethod("getListenerInfo");
        //拿到方法之后,给方法授权 getListenerInfoMethod
        getListenerInfoMethod.setAccessible(true);
        //执行方法 getListenerInfo
        /**
         * @param obj 方法对应的对象  也就是 getListenerInfo 方法对应的View对象, view.getListenerInfo()
         */
        Object listenerInfoObj = getListenerInfoMethod.invoke(view);

        // 拿到字段对应的对象
        final Object onClickListenerObj = onClickListenerFiled.get(listenerInfoObj);

执行结果:

2020-02-27 10:17:27.367 14405-14405/com.purang.hook E/MainActivity: hook: 拦截到了OnClickListener#onClick
2020-02-27 10:17:27.369 14405-14405/com.purang.hook E/MainActivity: button 文本内容: hello hook

源码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值