Hook方案很多,Android中如下
方案 | 作用时机 | 操作对象 | 优点 | 缺点 | 要求 |
---|---|---|---|---|---|
APT | 编译时:java文件还未编译成class文件 | .java文件 | 1.可以织入所有类;2.编译时代理,减少运行时消耗 | 1.需要使用apt编译器编译;2.需要手动拼接代理代码(可以使用Javapoet弥补);3.生成大量代理类 | 设计模式和解耦思想的灵活应用 |
AspectJ | 编译时、加载时 | .java文件 | 功能强大,除了hook之外,还可以为目标类添加变量,接口。也有抽象继承等各种更高级的玩法 | 1.不够轻量级;2.定义的切点依赖编程语言,无法兼容Lambda语法;3.无法织入第三方库;4.会有一些兼容问题,如:D8、Gradle4.x等 | 语法复杂,但掌握几个简单的,就能实现绝大多数场景 |
Javassist | 编译时:class文件未编译为dex或者运行时 | class字节码 | 1.减少了生成类的开销;2.直接操作修改编译后的字节码,直接绕过java编译器,所以突破很多限制的事情,例如,跨dex引用,解决热修复中CLASS_ISPREVERIFIED问题 | 运行时加入切面逻辑,产生性能开销 | 1.自定义Gradle插件;2.掌握groovy语言 |
ASM | 编译时或运行时 | class字节码 | 小巧轻便、性能好,效率比Javassist高 | 学习成本高 | 需要熟悉字节码语法,ASM通过树表示复杂的字节码结构,并利用Push模型来对树进行遍历,在遍历过程中对字节码进行修改 |
ASMDEX | 编译时和加载时:转化为.dex后 | Dex字节码,创建class文件 | 可以织入所有类 | 学习成本高 | 需要对class文件比较熟悉,编写过程复杂 |
DexMaker | 同上 | Dex字节码,创建dex文件 | 同上 | 同上 | 同上 |
Cglib | 运行时生成子类拦截方法 | 字节码 | 没有接口也可以织入 | 1.不能代理final字段修饰的方法;2.需要和DexMaker结合使用 | -- |
JDK动态代理 | 运行时反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理 | 接口的类生成代理 | JDK动态代理机制是委托机制,只能对实现接口的类生成代理,通过反射动态实现接口类 | 1.实现InvocationHandler接口,重写invoke() 2.使用Proxy.newProxyInstance()产生代理对象 3.被代理的对象必须要实现接口 | |
xposed | 运行时hook | -- | 能hook自己应用进程的方法,能hook其他应用的方法,能hook系统方法 | 依赖第三方包的支持,兼容性差,手机需要root | -- |
dexposed | 运行时hook | - | 只能hook自己应用的进程方法,但无需root | 1.依赖第三方包的支持,兼容性差;2.只能支持Dalvik虚拟机 | - |
epic | 运行时hook | - | 支持Dalvik和Art虚拟机 | 只适合在开发调试中使用,碎片化严重有兼容性问题 | - |
面试:Hook框架Xposed、Dexposed、Epic原理_沙漠一只雕得儿得儿的博客-CSDN博客_epic hook框架
ART虚拟机编译有什么特别的?
为什么Dexposed能够在Dalvik上为所欲为,到ART时代就不行了呢?排除其他非技术因素来讲,ART确实比Dalvik复杂太多;更要命的是,从Android L到Android O,每一个Android版本中的ART变化都是天翻地覆的,大致列举一下:
- Android L(5.0/5.1) 上的ART是在Dalvik上的JIT编译器魔改过来的,这个编译器会做一定程度的方法内联,因此很多基于入口替换的Hook方式一上来就跪了。
- Android M(6.0) 上的ART编译器完全重新实现了:寄存器分配方式改变。且不说之前在Android L上的Hook实现要在M上重新做一遍,这个编译器的寄存器分配比quick好太多,结果就是hook实现的时候你要是乱在栈或者寄存器上放东西,代码很容易就跑飞。
- Android N(7.0/7.1) N 开始采用了混合编译的方式,既有AOT也有JIT,还伴随着解释执行;混合模式对Hook影响是巨大的,以至于Xposed直到今年才正式支持Android N。首先JIT的出现导致方法入口不固定,跑着跑着入口就变了,更麻烦的是还会有OSR(栈上替换),不仅入口变了,正在运行时方法的汇编代码都可能发生变化;其次,JIT的引入带来了更深度的运行时方法内联,这些都使得虚拟机层面的Hook更为复杂。
- Android O(8.0) Android O的Runtime做了很多优化,传统Java VM有的一些优化手段都已经实现,比如类层次分析,循环优化,向量化等;除此之外,DexCache被删除,跨dex方法内联以及Concurrent compacting GC的引入,使得Hook技术变的扑朔迷离。