hook钩子:
使用技术手段在运行时动态的将额外代码依附现进程,从而实现替换现有处理逻辑或插入额外功能的目的。
它的技术实现要点有两个:
1)如何注入代码(如何将额外代码依附于现有代码中)。
2)如何确定目标函数的地址及替换。
要素:
1)现有功能;
2)目标功能;
3)替换技术。
http://www.epubit.com.cn/book/onlinechapter/33620?utm_source=tuicool&utm_medium=referral
8.1 什么是Hook技术
还没有接触过Hook技术读者一定会对Hook一词感觉到特别的陌生,Hook英文翻译过来就是“钩子”的意思,那我们在什么时候使用这个“钩子”呢?我们知道,在Android操作系统中系统维护着自己的一套事件分发机制。应用程序,包括应用触发事件和后台逻辑处理,也是根据事件流程一步步地向下执行。而“钩子”的意思,就是在事件传送到终点前截获并监控事件的传输,像个钩子钩上事件一样,并且能够在钩上事件时,处理一些自己特定的事件。较为形象的流程如图8-1所示。
Hook的这个本领,使它能够将自身的代码“融入”被勾住(Hook)的程序的进程中,成为目标进程的一个部分。我们也知道,在Android系统中使用了沙箱机制,普通用户程序的进程空间都是独立的,程序的运行彼此间都不受干扰。这就使我们希望通过一个程序改变其他程序的某些行为的想法不能直接实现,但是Hook的出现给我们开拓了解决此类问题的道路。当然,根据Hook对象与Hook后处理的事件方式不同,Hook还分为不同的种类,如消息Hook、API Hook等。
图8-1 Hook原理图
8.1.1 Hook原理
Hook技术无论对安全软件还是恶意软件都是十分关键的一项技术,其本质就是劫持函数调用。但是由于处于Linux用户态,每个进程都有自己独立的进程空间,所以必须先注入到所要Hook的进程空间,修改其内存中的进程代码,替换其过程表的符号地址。在Android中一般是通过ptrace函数附加进程,然后向远程进程注入so库,从而达到监控以及远程进程关键函数挂钩。
Hook技术的难点,并不在于Hook技术,初学者借助于资料“照葫芦画瓢”能够很容易就掌握Hook的基本使用方法。如何找到函数的入口点、替换函数,这就涉及了理解函数的连接与加载机制。
从Android的开发来说,Android系统本身就提供给了我们两种开发模式,基于Android SDK的Java语言开发,基于AndroidNDK的Native C/C++语言开发。所以,我们在讨论Hook的时候就必须在两个层面上来讨论。对于Native层来说Hook的难点其实是在理解ELF文件与学习ELF文件上,特别是对ELF文件不太了解的读者来说;对于Java层来说,Hook就需要了解虚拟机的特性与Java上反射的使用。
8.1.1.1 Hook工作流程
之前我们介绍过Hook的原理就是改变目标函数的指向,原理看起来并不复杂,但是实现起来却不是那么的简单。这里我们将问题细分为两个,一个是如何注入代码,另一个是如何注入动态链接库。
注入代码我们就需要解决两个问题。
- 需要注入的代码我们存放在哪里?
- 如何注入代码?
注入动态共享库我们也需要解决两个问题:
- 我们不能只在自己的进程载入动态链接库,如何使进程附着上目标进程?
- 如何让目标进程调用我们的动态链接库函数?
这里我也不卖关子了,说一下目前对上述问题的解决方案吧。对于进程附着,Android的内核中有一个函数叫ptrace,它能够动态地attach(跟踪一个目标进程)、detach(结束跟踪一个目标进程)、peektext(获取内存字节)、poketext(向内存写入地址)等,它能够满足我们的需求。而Android中的另一个内核函数dlopen,能够以指定模式打开指定的动态链接库文件。对于程序的指向流程,我们可以调用ptrace让PC指向LR堆栈。最后调用,对目标进程调用dlopen则能够将我们希望注入的动态库注入至目标进程中。