android native hook方法
主要分为:
GOT HOOK 即import table hook(导入表hook)
inline hook(内联hook)
export table hook (导出表hook)
Exception Hook 通过系统的异常信号处理机制接管当前指令,实现hook
一、导入表(GOT HOOK)
熟悉ELF结构的读者都知道,SO引用外部函数的时候,在编译时会将外部函数的地址以Stub的形式存放在.GOT表中,加载时linker再进行重定位,即将真实的外部函数写到此stub中。
HOOK的思路就是:替换.GOT表中的外部函数地址。
具体流程:
1.注入进程
2.可能有读者想到马上就是读取并解析SO的结构,找到外部函数对应在GOT表中的存放地址。在http://bbs.pediy.com/showthread.php?t=194053中已经讨论dlopen返回的是solist已经包含SO信息。
优缺点比较:
优点:
1、直接通过SOLIST实现替换HOOK代码量很小、实现简单
缺点:
1、导入表的 HOOK功能是很有限的。
2、导入表 HOOK对进程通过dlopen动态获得并调用外部符号是无效的。
3、导入表 HOOK只能影响被注入进程。
4、got_hook好像不能hook自己代码中的局部函数,只能hook其他so的导入函数。
二、inline hook
Inline Hook即内部跳转Hook,通过替换函数开始处的指令为跳转指令,使得原函数跳转到自己的函数,通常还会保留原函数的调用接口。与GOT表Hook相比,Inline Hook具有更广泛的适用性,几乎可以Hook任何函数,不过其实现更为复杂,考虑的情况更多,并且无法对一些太短的函数Hook。
优缺点比较:
优点:
1、Inline Hook具有更广泛的适用性,几乎可以Hook任何函数。
缺点:
1. 实现较为复杂,与硬件平台相关。
至少要考虑3个问题
a、相对寻址指令
b、arm v6 v7 thumb1 thumb2
c、cache 刷新
d、线程的处理
可以参考substrate 就是实现了inline hook的。
2. ARM 的 inline替换字节为8-14字节,远远高于x86平台的5字节。当函数比较简短时,是无法发挥作用的。
参考:
三、基于 Android linker 的导出表HOOK
熟悉ELF格式的读者应该知道ELF并没有类似PE格式的显式导出表。但ELF文件的symtab表说明了符号是导入符号还是导出符号,这点可以在linker.c的源码中可以看到。
要实现导出表 HOOK,先来分析下linker是如何帮助SO获得外部符号的地址的。
在linker源码中可以看到,linker将SO加载到内存之后,最后阶段最主要的是对符号进行重定位。在重定位过程中,如果发现符号为外部符号,就会去解析NEEDED SO,获取外部符号的地址。
具体一点来说,就是通过NEEDED SO,根据外部符号的名字,找到对应的Elf32_Sym,从这个Elf32_Sym中的st_value字段得到函数的虚地址。那么修改NEEDED SO中的这个符号st_value字段,即可实现导出表HOOK。
参考:http://bbs.pediy.com/showthread.php?p=1342351
四、Exception Hook
http://www.jianshu.com/p/3399bbed77db
实现原理
利用SIGILL异常去做Hook操作,具体可以是对我们想要的监控的地址设一个非法指令,然后当程序执行到非法指令位置时系统会回调我们预先设定好的异常处理函数,我们在这个异常处理函数里面恢复地址的原指令,获取context信息,然后打印寄存器信息即可。
其实,一般我们为了长时间对某个地址监控,我们恢复目标地址的指令后还需要找时机去改目标地址,为下一次获取信息做准备。那么我们可以在获取到异常后,对目标地址的下一条指令做异常Hook操作,然后在下一个异常来临的时候,在异常处理函数中恢复当前异常指令并重新对目标地址写非法指令,以等待下一次目标地址被调用时获取我们想要的信息。
事实上,我们会通过sigaction这个API来设置SIGILL信号的异常处理函数
函数Hook技术的本质就是劫持函数的调用。在Android平台上,可以在Java层对API函数进行Hook,也可以在Native层对进程的So库函数进行Hook。
Native层的Hook方式多种多样,包括导入表Hook、基于异常的Hook、Inline Hook等。
导入表Hook是通过替换对应So文件的.Got表中指定函数地址实现对函数的Hook,
基于异常的Hook方式是修改指定地址处代码为异常指令,通过异常处理函数捕获异常,获取执行权限和当前执行的上下文环境。
Android平台上的Inline Hook实现原理与其他平台相似,都是通过修改函数指令跳转到Hook函数。