Hook技术看这篇就够了[通俗易懂]

发布时间:2025-12-09 13:43:36 浏览次数:4

相信很多搞机的朋友都玩过Xposed, 它实现了很多不可思议的功能。它是怎么实现的呢?这里就得提到我们的Hook技术了。

关于 Android 中的 Hook 机制,大致有两个方式:

  • 要 root 权限,直接 Hook 系统,可以干掉所有的 App。
  • 免 root 权限,但是只能 Hook 自身,对系统其它 App 无能为力。

时间所限,这里不展开了。

知识点:

  • 反射
  • 动态代理

今天主要讲的是利用hook技术,将点击事件劫持,做点啥呢?你可以随意,我这里是将双击给屏蔽了。免得点击过快打开多个界面。

1、寻找Hook点

这一步比较关键,也是个难点。Android中主要是依靠分析系统源码类来做到的,首先我们得找到被Hook的对象,我称之为Hook点;什么样的对象比较好Hook呢?自然是容易找到的对象。什么样的对象容易找到?静态变量和单例;在一个进程之内,静态变量和单例变量是相对不容易发生变化的,因此非常容易定位,而普通的对象则要么无法标志,要么容易改变。我们根据这个原则找到所谓的Hook。

去看setOnClickListener里面做了什么?

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

看完了上面,就能猜到我们设置的Listener最终是被赋值给ListenerInfo的mOnClickListener成员了,ListenerInfo的实例可以说是信息的载体,那么很简单,只要把mOnClickListener,在ListenerInfo中还有mOnLongClickListener,mOnFocusChangeListener两个成员,分别对应了长按事件与焦点变化事件,所以处理长按事件与焦点变化事件与此类似。

public class HookViewClickUtil {        public static HookViewClickUtil getInstance() {        return UtilHolder.mHookViewClickUtil;    }    private static class UtilHolder {            private static HookViewClickUtil mHookViewClickUtil = new HookViewClickUtil();    }    public static void hookView(View view) {        try {            Class viewClazz = Class.forName("android.view.View");            //事件监听器都是这个实例保存的            Method listenerInfoMethod = viewClazz.getDeclaredMethod("getListenerInfo");            if (!listenerInfoMethod.isAccessible()) {                listenerInfoMethod.setAccessible(true);            }            Object listenerInfoObj = listenerInfoMethod.invoke(view);            Class listenerInfoClazz = Class.forName("android.view.View$ListenerInfo");            Field onClickListenerField = listenerInfoClazz.getDeclaredField("mOnClickListener");            if (!onClickListenerField.isAccessible()) {                onClickListenerField.setAccessible(true);            }            View.OnClickListener mOnClickListener = (View.OnClickListener) onClickListenerField.get(listenerInfoObj);            //自定义代理事件监听器            View.OnClickListener onClickListenerProxy = new OnClickListenerProxy(mOnClickListener);            //更换            onClickListenerField.set(listenerInfoObj, onClickListenerProxy);        } catch (Exception e) {            e.printStackTrace();        }    }    //自定义的代理事件监听器    private static class OnClickListenerProxy implements View.OnClickListener {            private View.OnClickListener object;        private int MIN_CLICK_DELAY_TIME = 1000;        private long lastClickTime = 0;        private OnClickListenerProxy(View.OnClickListener object) {            this.object = object;        }        @Override        public void onClick(View v) {            //点击时间控制            long currentTime = Calendar.getInstance().getTimeInMillis();            if (currentTime - lastClickTime > MIN_CLICK_DELAY_TIME) {                lastClickTime = currentTime;                Log.e("OnClickListenerProxy", "OnClickListenerProxy");                if (object != null) object.onClick(v);            }        }    }}

使用起来也是非常简单,首先在MainActivity的View渲染完毕的时候进行注入,即在 getWindow().getDecorView().post()中。

public class MainActivity extends Activity {        private Button  btn;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        final View btn = findViewById(R.id.btn);        btn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Log.e("MainActivity","Button 被点击了");            }        });        getWindow().getDecorView().post(new Runnable() {            @Override            public void run() {                HookViewClickUtil.hookView(btn);            }        });    }}
需要做网站?需要网络推广?欢迎咨询客户经理 13272073477