带你了解Hook技术

举报
yd_221104950 发表于 2020/12/04 01:28:55 2020/12/04
【摘要】 什么是Hook Hook 是“钩子”的意思,可以在事件传送的过程中截获并监控事件的传输,可以将我们的代码与系统方法进行融合。当这些系统方法被调用时,也会执行我们的代码。面向切面编程的思想(AOP)也是利用这个原理。 Hook 分类 Android有基于Android SDK的Java语言开发和基于Android NDK的Native C/C++语言开发,因此有...

什么是Hook

在这里插入图片描述

Hook 是“钩子”的意思,可以在事件传送的过程中截获并监控事件的传输,可以将我们的代码与系统方法进行融合。当这些系统方法被调用时,也会执行我们的代码。面向切面编程的思想(AOP)也是利用这个原理。

Hook 分类

Android有基于Android SDK的Java语言开发和基于Android NDK的Native C/C++语言开发,因此有:

  • Java层级的Hook
  • Native层级的Hook

根据Hook到的对象与Hook后处理事件方式的不同可以分为:

  • 消息Hook
  • API Hook

根据Hook到的进程的不同分为:

  • 全局Hook
  • 单个进程Hook

Hook的原理就是改变目标函数的指向。Hook技术无论对安全软件还是恶意软件都是十分关键的一项技术,其本质就是劫持函数调用。

Hook技术的难点是如何找到函数的入口点、替换函数,这就涉及了理解函数的连接与加载机制。

对于Android的开发来说,hook Native层关键是要理解好ELF文件(linux平台上的可执行文件),hook Java层关键是要了解虚拟机的特性和Java反射技术。

Hook例子

Hook 过程

  • 寻找 Hook 点,原则是尽可能是静态变量或者单例对象,因为它们容易定位,其次是尽量 Hook public 的对象和方法。
  • 选择合适的代理方式,如果是接口可以用动态代理。
  • 用代理对象替换原始对象

我们现在来拦截android控件的点击事件:

第一步:寻找 Hook 点

分析View.java代码:

public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
	... static class ListenerInfo { /** * Listener used to dispatch click events. * This field should be made private, so it is hidden from the SDK. * {@hide} */ public OnClickListener mOnClickListener; ... } ListenerInfo mListenerInfo; ListenerInfo getListenerInfo() { if (mListenerInfo != null) { return mListenerInfo; } mListenerInfo = new ListenerInfo(); return mListenerInfo; } public void setOnClickListener(@Nullable OnClickListener l) { if (!isClickable()) { setClickable(true); } getListenerInfo().mOnClickListener = l; } /** * Call this view's OnClickListener, if it is defined.  Performs all normal * actions associated with clicking: reporting accessibility event, playing * a sound, etc. * * @return True there was an assigned OnClickListener that was called, false * otherwise is returned. */ // NOTE: other methods on View should not call this method directly, but performClickInternal() // instead, to guarantee that the autofill manager is notified when necessary (as subclasses // could extend this method without calling super.performClick()). public boolean performClick() { // We still need to call this method to handle the cases where performClick() was called // externally, instead of through performClickInternal() notifyAutofillManagerOnClick(); final boolean result; final ListenerInfo li = mListenerInfo; if (li != null && li.mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); li.mOnClickListener.onClick(this); result = true; } else { result = false; } sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); notifyEnterOrExitForAutoFillIfNeeded(true); return result; } /** * Register a callback to be invoked when this view is clicked. If this view is not * clickable, it becomes clickable. * * @param l The callback that will run * * @see #setClickable(boolean) */ public void setOnClickListener(@Nullable OnClickListener l) { if (!isClickable()) { setClickable(true); } getListenerInfo().mOnClickListener = l; } /** * Interface definition for a callback to be invoked when a view is clicked. */ public interface OnClickListener { /** * Called when a view has been clicked. * * @param v The view that was clicked. */ void onClick(View v); }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88

通过分析 View.java的代码,我们可以知道setOnClickListener注册的OnClickListener 对象被保存在ListenerInfo内部类对象mListenerInfo里。ListenerInfo 里面保存了 View 的各种监听事件。因此,我们要劫持点击事件,就要hook得到 ListenerInfo对象里的mOnClickListener ,hook得到以后,用 Hook代理类替换原始的 OnClickListener,就可以实现我们的目的了。

第二步:选择代理方式

public class HookOnClickListenerProxy implements View.OnClickListener { private View.OnClickListener origin; public HookOnClickListenerProxy(View.OnClickListener origin){ this.origin = origin; } @Override public void onClick(View v) { Toast.makeText(v.getContext(), "Hook Click Listener", Toast.LENGTH_SHORT).show(); if(origin != null){ origin.onClick(v); } }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

可以看出我们的代理类做了一件事,就是先提示“Hook Click Listener”,然后再继续执行原先的东西。

第三步:用代理对象替换原始对象

		// 第一步:反射得到 ListenerInfo 对象 Method getListenerInfo = View.class.getDeclaredMethod("getListenerInfo"); getListenerInfo.setAccessible(true); Object listenerInfo = getListenerInfo.invoke(view); // 第二步:得到原始的 OnClickListener事件方法 Class<?> listenerInfoClz = Class.forName("android.view.View$ListenerInfo"); Field mOnClickListener = listenerInfoClz.getDeclaredField("mOnClickListener"); mOnClickListener.setAccessible(true); View.OnClickListener originOnClickListener = (View.OnClickListener)mOnClickListener.get(listenerInfo); // 第三步:用 Hook代理类替换原始的 OnClickListener View.OnClickListener hookedOnClickListener = new HookOnClickListenerProxy(originOnClickListener); mOnClickListener.set(listenerInfo,hookedOnClickListener);

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

Hook的过程,我们就演示了一遍了。demo示例

Hook通知栏,劫持通知栏的消息的demo
Hook剪贴板demo

Hook 框架

  • Xposed
  • Cydia Substrate
  • Legend
    Legend 是 Android 免 Root 环境下的一个 Apk Hook 框架,该框架代码设计简洁,通用性高,适合逆向工程时一些 Hook 场景。大部分的功能都放到了 Java 层,兼容性非常好。
    原理是直接构造出新旧方法对应的虚拟机数据结构,然后替换信息写到内存中即可。

谢谢阅读!

文章来源: blog.csdn.net,作者:WongKyunban,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/weixin_40763897/article/details/89091452

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。