初识Hook技术

一、什么叫Hook

Hook字面意思是钩子,钩子是干什么的呢?日常生活中,我们的钩子是用来钩住某种东西的,比如说,鱼钩是用来钓鱼的,一旦鱼咬了钩,钩子就一直钩住鱼了,任凭鱼在水里怎么游,也逃不出鱼钩的控制。

我们可以通过api hook,改变一个系统api的原有功能。API HOOK技术是一种用于改变API执行结果的技术

基本的方法就是通过hook“接触”到需要修改的api函数入口点,改变它的地址指向新的自定义的函数。从java层面上讲,就是创建代理类代理目标对象,并将代理对象赋值给目标对象地址。

比如要求在不侵入业务代码的情况下监听所有的点击事件,并记录所有的点击数。那么就需要hook住view的点击事件,这样当点击事件发生时,执行被我们hook的监听器。
怎么找到监听器入口函数呢?
通过阅读View的源码发现一个很有用的方法 

ListenerInfo getListenerInfo() {
	if (mListenerInfo != null) {
		return mListenerInfo;
	}
	mListenerInfo = new ListenerInfo();
	return mListenerInfo;
}
所有监听器的对象都是保存在ListenerInfo类型的对象中

static class ListenerInfo {
	protected OnFocusChangeListener mOnFocusChangeListener;

	private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;

	protected OnScrollChangeListener mOnScrollChangeListener;

	private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;

	public OnClickListener mOnClickListener;

	protected OnLongClickListener mOnLongClickListener;

	protected OnContextClickListener mOnContextClickListener;

	protected OnCreateContextMenuListener mOnCreateContextMenuListener;

	private OnKeyListener mOnKeyListener;

	private OnTouchListener mOnTouchListener;

	private OnHoverListener mOnHoverListener;

	private OnGenericMotionListener mOnGenericMotionListener;

	private OnDragListener mOnDragListener;

	private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;

	OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
  }
接下来的事情就简单了,执行getListenerInfo()方法获取mListenerInfo对象,然后用静态代理对象替换掉mListenerInfo的各种监听器的成员变量,在我们自己的代理对象中我们就可以为所欲为了。比如OnclickListener的代理对象

public class OnClickListenerProxy implements View.OnClickListener{
    private View.OnClickListener realListener; //给View设置的点击事件

    public OnClickListenerProxy(View.OnClickListener realListener){
        this.realListener = realListener;
    }

    @Override
    public void onClick(View v) {
        if(realListener != null) realListener.onClick(v);
        //统计点击事件等
        ............
    }
}
realListener是真实的点击事件。其他监听器的代理实现类似。接下来就是轮询所有的子view,然后把给view设置的监听器对象换成代理对象即可。替换过程如下。

/**
 * 入口函数
 * @param activity
 */
public void startHook(Activity activity, OnClickListener hookListener){
    //得到所有的子view 
	List<View> views = getAllChildViews(activity);
	for(View v: views){
		hook(v,hookListener);
	}
}

private void hook(View view,OnClickListener hookListener){
	//获取listenerInfo对象
	mClassView = Class.forName("android.view.View");
	Method method = mClassView.getDeclaredMethod("getListenerInfo");
	method.setAccessible(true);
	Object listenerInfoObject = method.invoke(view);
	//获取listenerInfo中的OnClickListener
	Class mClassListenerInfo = Class.forName("android.view.View$ListenerInfo");
	Field feildOnClickListener = mClassListenerInfo.getDeclaredField("mOnClickListener");
	feildOnClickListener.setAccessible(true);
	View.OnClickListener mOnClickListenerObject = (View.OnClickListener) feildOnClickListener.get(listenerInfoObject);
	//hook替换成我们自己的监听器
	View.OnClickListener onClickListenerProxy = new OnClickListenerProxy(mOnClickListenerObject, hookListener);
	feildOnClickListener.set(listenerInfoObject, onClickListenerProxy);
}
这样hook监听器的过程就完成了,其他的监听器类似。

总结:Hook的目的就是钩住api入口,统一改变功能。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值