您的位置:首页 > 其它

初识Hook技术

2017-01-17 16:15 225 查看
一、什么叫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入口,统一改变功能。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: