热修复系列——Android热修复技术进阶篇
目录
1 前言
2 热修复技术
2.1 Dexposed
2.2 AndFix
2.3 QZone
2.4 Tinker
2.6 epic
2.7 YAHFA
2.8 FastHook
2.9 美团Robust
3 总结
1 前言
对热修复技术做一个总结,也是告一个段落(几年前的研究,有些可能过时了)
以AndFix入门,具体可以参考以前的使用步骤。
热修复系列——AndFix使用教程基础篇_疑是银河落九天的博客-CSDN博客_andfix使用
2 热修复技术
2.1 Dexposed
详情参考
Android中免Root实现Hook的Dexposed框架实现原理解析以及如何实现应用的热修复_尼古拉斯.赵四的博客-CSDN博客_dexposed
工作原理
- 基于Xposed的AOP框架
- 免root实现方法级粒度hook
- 通过JNI注册,从Java转Native,然后在native中修改被hook方法的一些信息,最后通过反射调用handleHookedMethod回到Java
- 立即生效
限制
不支持ART(xposed重新编译了自己的libart.so,并阻止内联,需要对不同版本兼容)
2.2 AndFix
详情参考
Android热修复框架AndFix原理解析及使用_尼古拉斯.赵四的博客-CSDN博客
工作原理
AndFixManager.java类的replaceMethod方法
private void replaceMethod(ClassLoader classLoader, String clz,String meth, Method method) {try {String key = clz + "@" + classLoader.toString();//key为新类名@默认类加载器名Class<?> clazz = mFixedClass.get(key);if (clazz == null) {// class not load//使用默认类加载器加载修复类对应的原始类Class<?> clzz = classLoader.loadClass(clz);...
}
ArtMethod结构替换代码
void replace_7_0(JNIEnv* env, jobject src, jobject dest) {art::mirror::ArtMethod* smeth =(art::mirror::ArtMethod*) env->FromReflectedMethod(src);art::mirror::ArtMethod* dmeth =(art::mirror::ArtMethod*) env->FromReflectedMethod(dest);// reinterpret_cast<art::mirror::Class*>(smeth->declaring_class_)->class_loader_ =
// reinterpret_cast<art::mirror::Class*>(dmeth->declaring_class_)->class_loader_; //for plugin classloaderreinterpret_cast<art::mirror::Class*>(dmeth->declaring_class_)->clinit_thread_id_ =reinterpret_cast<art::mirror::Class*>(smeth->declaring_class_)->clinit_thread_id_;reinterpret_cast<art::mirror::Class*>(dmeth->declaring_class_)->status_ =reinterpret_cast<art::mirror::Class*>(smeth->declaring_class_)->status_ -1;//for reflection invokereinterpret_cast<art::mirror::Class*>(dmeth->declaring_class_)->super_class_ = 0;smeth->declaring_class_ = dmeth->declaring_class_;smeth->access_flags_ = dmeth->access_flags_ | 0x0001;smeth->dex_code_item_offset_ = dmeth->dex_code_item_offset_;smeth->dex_method_index_ = dmeth->dex_method_index_;smeth->method_index_ = dmeth->method_index_;smeth->hotness_count_ = dmeth->hotness_count_;smeth->ptr_sized_fields_.dex_cache_resolved_methods_ =dmeth->ptr_sized_fields_.dex_cache_resolved_methods_;smeth->ptr_sized_fields_.dex_cache_resolved_types_ =dmeth->ptr_sized_fields_.dex_cache_resolved_types_;smeth->ptr_sized_fields_.entry_point_from_jni_ =dmeth->ptr_sized_fields_.entry_point_from_jni_;smeth->ptr_sized_fields_.entry_point_from_quick_compiled_code_ =dmeth->ptr_sized_fields_.entry_point_from_quick_compiled_code_;LOGD("replace_7_0: %d , %d",smeth->ptr_sized_fields_.entry_point_from_quick_compiled_code_,dmeth->ptr_sized_fields_.entry_point_from_quick_compiled_code_);}
限制
- 以Field为切入点,使用自定义类加载器生成新的ArtMethod,使用默认类加载器生成旧ArtMethod,再进行结构内字段的替换。
- AndFix采用的是替换结构体中的字段,但由于厂商可能会修改ArtMethod结构体,因此会有兼容问题。Sophix(是阿里推出的移动热修复方案,闭源,有本书《深入探索Android热修复原理》介绍了Sophix,支持)采用的是替换整个ArtMethod结构体,这样就不会存在兼容问题。
- 立即生效
- 目前支持2.3 - 7.0
- 《深入探索Android热修复原理》讲述sophix的对比图如下
2.3 QZone
详情参考
安卓App热补丁动态修复技术介绍
工作原理
- classloader可以包含多个dex文件,排成一个有序数组dexElements,当查找类时会按顺序遍历dex文件,如果不同的dex有相同的类存在,那么会优先选择排在前面的dex文件中的类
- 如果一个类与它直接引用的类在同一个dex文件中,那么该类会被打上preverify标签。因此如果需要修复类与引用类所在dex文件不同则会报错。解决方案是往所有类的构造函数插桩引用一个不存在的类,防止被打上标签
- 重启生效,因为已经加载过的类无法被卸载,想要重新加载新的类就需要重启APP。
限制
- 由于插桩导致所有类都非preverify,因此加载类时会触发verify与optimize操作,由于启动时会加载大量的类,因此效率影响较大
- 存在art下内存地址混乱问题,因为dex2oat将类能确定的各个地址写死,运行时补丁包的地址改变,原始类调用就会出错
2.4 Tinker
详情参考
GitHub - WeMobileDev/article: articles by WeChat Mobile Development Team
工作原理
使用DexDiff算法,在编译时通过新旧Dex生成差异包,将差异包与旧Dex还原为新Dex,重启生效
限制
- 占用Rom体积,大约是修改Dex数量的1.5倍(dexopt与dex压缩成jar)的大小
- 需要额外进程合成新的Dex,合成时间的长短与内存消耗也会影响最终的成功率
2.6 epic
详情参考
我为Dexposed续一秒——论ART上运行时 Method AOP实现 | Weishu's Notes
https://github.com/tiann/epic/blob/master/README_cn.md
工作原理
通过callee的ArtMethod对象得到方法的entrypoint,根据方法入口点找到对应地址,直接将内存的前8个字节修改为一段跳转指令,然后在跳转指令中执行二段跳板,进而跳转到新方法中执行
限制
- 受限于dynamic callee-side rewrite机制,如果被Hook函数的code段太短以至于一个简单的trampoline跳转都放不下,那么epic无效
- 如果ART中有深度内联,直接把本函数的代码内联到调用者,那么epic无效
- 仅支持Android 5-11
- 当前仅支持thumb2/arm64指令集,arm32/x86/x86_64/mips/mips64还没有适配
- 在支持硬浮点的cpu架构,比如(armeabi-v7a, arm64-v8a)上,带有double/float参数的函数Hook可能有问题,没有充分测试
- 还有一些其他机型上可能存在的闪退
- 目前已测机型:5.0, 5.1, 6.0, 7.0, 7.1个别机型,以及这些机型的thumb2指令集,和6.0/7.1 的arm64指令集(作者博客所述)
- 无法修改类初始化过程中执行的函数
2.7 YAHFA
详情参考
YAHFA--ART环境下的Hook框架 - 记事本
在Android N上对Java方法做hook遇到的坑 - 记事本
工作原理
修改目标方法的ArtMethod结构体,将hook方法的ArtMethod地址保存在原方法的entry_point_from_jni,并修改原方法的entry_point_from_quick_compiled_code,使其指向一段辅助代码,在这里完成eax的设置和跳转,即时生效。
从原理上看,还是走的虚拟机调用流程,与AndFix的不同之处在于,AndFix直接替换了Method,而YAHFA使用一种简单方式实现了AOP,能够实现方法的hook并回调原始方法
限制
- 无法解决方法直接跳转,也就是不走ArtMethod入口,目标方法地址直接写死(其实这种情况在高版本里比较少了,特别是第三方应用的方法更少)
- 由于class加载后才进行的结构替换,因此field在class中的相对地址已经确定,无法进行字段的新增与删除
- 因为直接替换方法,此时已经执行了loadClass初始化,因此在该过程中执行的方法如构造函数、静态成员都有问题
2.8 FastHook
详情参考
[原创]FastHook——一种高效稳定、简洁易用的Android Hook框架-Android安全-看雪论坛-安全社区|安全招聘|bbs.pediy.com
[原创]FastHook——实现.dynsym段和.symtab段符号查询-Android安全-看雪论坛-安全社区|安全招聘|bbs.pediy.com
[原创]FastHook——远超YAHFA的优异稳定性-Android安全-看雪论坛-安全社区|安全招聘|bbs.pediy.com
[原创]FastHook——巧妙利用动态代理实现非侵入式AOP-Android安全-看雪论坛-安全社区|安全招聘|bbs.pediy.com
https://github.com/turing-technician/FastHook
工作原理
这个框架很优秀,其实还是native替换,fasthook支持内联替换和entrypoint两种方式,而且手动jit的过程中处理了很多细节,值得参考。
限制
还是native替换的通病,不能新增类/字段,以及类初始化过程中执行的函数
2.9 美团Robust
详情参考
Android热更新方案Robust - 美团技术团队
工作原理
Instant Run类型方案,基于编译过程进行插桩,有代码侵入,对运行效率,包体积,方法数有一定影响。
限制
插桩原始代码,因此会有代码冗余
3 总结
总结,具体对比我就略过了,技术参考链接已经很详细了。
总的来说,就是Java整体替换的方式可以新增类/字段,native内存替换只能修改方法体本身。
整体全面的热修复方案以Sophix为代表,不过它不开源。
native替换以FastHook为代表,不过有点黑科技,处理适配和兼容应该会花不少时间。
Robust插桩方案除开对代码有侵入性的话,从稳定性和兼容性来说,应该是最好的(但是这套方案没有详细了解)
有错误欢迎指正,也欢迎技术交流!
热修复系列——Android热修复技术进阶篇相关推荐
- 1000篇干货好文!量子技术——进阶篇
阅读原文 1000篇干货好文!量子技术--入门篇 https://bbs.aliyun.com/read/581500.html 1000篇干货好文!量子技术--进阶篇 https://bb ...
- android热补丁作用,Android热修复之 - 阿里开源的热补丁
这里就有一个概念那就AndFix.apatch补丁用来修复方法,接下来我们看看到底是怎么实现的. 1.2 生成apatch包 假如我们收到了用户上传的崩溃信息,我们改完需要修复的Bug,这个时候就会有 ...
- Android工具修复属性,Android 热修复介绍之代码修复
什么是Android热修复技术 简单来说就是不重新安装apk的情况下,通过补丁,修复bug 正常开发流程 热修复开发流程 目前主流的热修复技术框架 阿里系的: Andfix.Hotfix.Sophix ...
- 跟着小马哥学系列之 Spring IoC(进阶篇:Environment)
学成路更宽,吊打面试官. --小马哥 简介 大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间< ...
- 跟着小马哥学系列之 Spring IoC(进阶篇:类型转换)
学成路更宽,吊打面试官. --小马哥 简介 大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间< ...
- android 热修复视频,Android热修复
所谓热修复,简单来说就是不以下载新版本apk的方式来修改应用的bug,而是在应用启动后从服务器下拉补丁包实现动态修复bug.所以在应用出现bug后,我们只需要打一个补丁,用户无需下载安装新的版本.主要 ...
- android中热更新模式,Android热更新与开启Instant Run
配置完热更新后,直接run模式运行,程序会报以下错误: Tinker does not support instant run mode, please trigger build by assemb ...
- android adb修复工具,Android——adb修复build.prop
从昨天开始就在刷手机,换了各种rom,今天中午总算刷了一个还算不错的rom,用了不到半天,晚上突发奇想修改了以下/system/build.prop文件,哪知手机重启后再也进不了系统,真是悲剧.不想再 ...
- 《Android插件化技术——原理篇》
| 导语 插件化技术最早从2012年诞生至今,已经走过了5个年头.从最初只支持Activity的动态加载发展到可以完全模拟app运行时的沙箱系统,各种开源项目层出不穷,在此挑选了几个代表性的框架,总结 ...
最新文章
- 微信小程序自定义组件Component的简单使用
- 看看Entity Framework 4生成的复杂的分页SQL语句
- MySQL 中主键的几种表设计组合的实际应用效果
- python教程:Json模块中dumps、dump、loads、load函数用法讲解
- QML 性能优化建议(一)
- python语言语句快的标记是什么_一文搞懂Python程序语句
- 怎么在linux下查看gpu版本号,linux.查看gpu版本
- C/C++内存分配方式 .
- 使用ETag识别ajax,如何使用jQuery AJAX请求访问ETag头?
- ArcEngine由点生成TIN
- 二叉树的之字形层序遍历
- iOS分段选择器、旅行App、标度尺、对对碰小游戏、自定义相册等源码
- Scala深入浅出实战经典---001-Scala开发环境搭建和HelloWorld解析
- 音乐专业如何利用计算机思维,太神奇了!带学生“玩音乐”居然可以打开思维创新...
- JavaScript之Ajax Util
- python图片,大家来找茬
- 小米平板2(2015716)官方线刷包_救砖包_解账户锁
- QML之gradient
- PyTorch搭建LSTM实现多变量多步长时间序列预测(四):多模型滚动预测
- python在excel中数据画线_python中操作excel数据