什么是Hook

Hook是什么?

Hook 又叫“钩子”,它可以在事件传送的过程中截获并监控事件的传输,将自身的代码与系统方法进行融入。

这样当这些方法被调用时,也就可以执行我们自己的代码,这也是面向切面编程的思想(AOP)。

示例:Hook 修改 View.OnClickListener 事件

点击事件的方法:

将OnClickListener对象赋予给了ListenerInfo对象的mOnClickListener。

    public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }

    @UnsupportedAppUsage
    ListenerInfo getListenerInfo() {
        if (mListenerInfo != null) {
            return mListenerInfo;
        }
        mListenerInfo = new ListenerInfo();
        return mListenerInfo;
    }

ListenerInfo类是View的抽象内部类,声明了View的各种事件listener,而我们要找的mOnClickListener就在其中。

    static class ListenerInfo {

        @UnsupportedAppUsage
        ListenerInfo() {
        }
        protected OnFocusChangeListener mOnFocusChangeListener;

        private ArrayList mOnLayoutChangeListeners;

        protected OnScrollChangeListener mOnScrollChangeListener;

        public OnClickListener mOnClickListener;

        protected OnLongClickListener mOnLongClickListener;

        private OnKeyListener mOnKeyListener;

        private OnTouchListener mOnTouchListener;

        private OnHoverListener mOnHoverListener;

        private OnDragListener mOnDragListener;
实现思路:

1.利用反射获取 ListenerInfo 对象
2.获取原始的 OnClickListener事件方法
3.用 Hook代理类 替换原始的 OnClickListener

代码实现:

首先去创建自己需要hook的类:

class MyClickListener implements View.OnClickListener {
    private View.OnClickListener onClickListener;

    public MyClickListener(View.OnClickListener onClickListener) {
        this.onClickListener = onClickListener;
    }

    @Override
    public void onClick(View v) {
        Toast.makeText(v.getContext(), "系统OnClickListener已经被我替换啦", Toast.LENGTH_SHORT).show();

        onClickListener.onClick(v);
    }
}

去实现偷梁换柱功能:

public class HookHelper {

    public static void hookOnClickListener(View view) throws Exception {
        Method getListenerInfo = View.class.getDeclaredMethod("getListenerInfo");  //获取getListenerInfo方法
        getListenerInfo.setAccessible(true);

        Object mListenerInfo = getListenerInfo.invoke(view);  //执行完getListenerInfo方法即可返回ListenerInfo对象

        //去得到原始OnClickListener
        Class aClass = Class.forName("android.view.View$ListenerInfo");
        Field mOnClickListener = aClass.getDeclaredField("mOnClickListener");
        mOnClickListener.setAccessible(true);
        View.OnClickListener originOnClickListener = (View.OnClickListener) mOnClickListener.get(mListenerInfo);//从ListenerInfo中获取原始OnClickListener类对象

        View.OnClickListener hookClickListener = new MyClickListener(originOnClickListener);

        mOnClickListener.set(mListenerInfo, hookClickListener); //将原始的onClickListener替换成自己的
    }
}

最后用一个textView测试结果:

        findViewById(R.id.textView).apply {
            setOnClickListener {  }

            HookHelper.hookOnClickListener(this) 
        }
参考:

Android Hook 机制之简单实战

你可能感兴趣的:(什么是Hook)