基于cydia Hook在线热修复补丁方案
最近的在线热补丁修复的讨论相当激烈,从Xopsed到Dexposed,再到AndFix,再到QQ空间团队的Class补丁。可谓是各有特色。本文讨论的是基于Cydia Hook实现的在线Class热补丁。相对于Xopsed、Dexposed、AndFix这三种都是替换Java方法,和QQ空间class替换而言,优势明显。前者是替换方法,但是如果所替换的方法中遇到calss中的成员变量,就要通过反射得到,实现补丁方案。这相对于Class补丁来说解决性能问题,但是使用起来比较麻烦。而QQ空间团队使用的是替换整个Class,这就没有成员变量的问题。但是QQ空间的方案却牺牲了性能,主要是通过防止class打上CLASS_ISPREVERIFIED。本文所讨论的方案是基于两者实现的,没有成员变量反射得到麻烦,也没有防止class打上CLASS_ISPREVERIFIED牺牲性能的问题。那这是怎么实现的呢?请看下文:
我采用的是MultiDex方案实现的,这部分和QQ空间类似就是讲补丁dex文件,放在其他dex(包括主dex),这是因为一个ClassLoader可以包含多个dex文件,每个dex文件是一个Element,多个dex文件排列成一个有序的数组dexElements,当找类的时候,会按顺序遍历dex文件,然后从当前遍历的dex文件中找类,如果找类则返回,如果找不到从下一个dex文件继续查找。具体代码:
public Class findClass(String name, List<Throwable>suppressed){
for (Elementelement : dexElements) { //每个Element就是一个dex文件
DexFile dex = element.dexFile;
if (dex != null) {
Class clazz=dex.loadClassBinaryName(name, definingContext, suppressed);
if (clazz!= null) {
return clazz;
}
}
}
if (dexElementsSuppressedExceptions!= null){
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
return null;
}
我的方案中采用的是MultiDex,对其进行一部分改造,具体代码:
1、添加dex文件,并执行install
/**
* 添加apk包外的dex文件
* 自动执行install
* @param dexFile
*/
public static void addDexFileAutoInstall(Context context, List<File> dexFile,File optimizedDirectory) {
if (dexFile != null && !dexFile.isEmpty() &&!dexFiles.contains(dexFile)) {
dexFiles.addAll(dexFile);
LogUtil.d(TAG, "add other dexfile");
installDexFile(context,optimizedDirectory);
}
}
2、installDexFile直接调用MultiDex 的installSecondaryDexes方法。
/**
* 添加apk包外的dex文件,
* @param context
*/
publicstatic void installDexFile(Context context, File optimizedDirectory){
if (checkValidZipFiles(dexFiles)) {
try {
installSecondaryDexes(context.getClassLoader(), optimizedDirectory, dexFiles);
} catch (IllegalAccessExceptione){
e.printStackTrace();
} catch (NoSuchFieldExceptione) {
e.printStackTrace();
} catch (InvocationTargetExceptione){
e.printStackTrace();
} catch (NoSuchMethodExceptione) {
e.printStackTrace();
} catch (IOExceptione) {
e.printStackTrace();
}
}
}
3、将patch.dex放在所有dex最前面。
private static voidexpandFieldArray(Object instance, String fieldName, Object[]extraElements) throws NoSuchFieldException, IllegalArgumentException,
IllegalAccessException {
Field jlrField = findField(instance, fieldName);
Object[]original = (Object[]) jlrField.get(instance);
Object[]combined = (Object[]) Array.newInstance(original.getClass().getComponentType(),original.length + extraElements.length);
// 将后来的dex放在前面,主dex放在最后。
System.arraycopy(extraElements, 0, combined, 0, extraElements.length);
System.arraycopy(original, 0, combined, extraElements.length,original.length);
// 原始的dex合并,是将主dex放在前面,其他的dex依次放在后面。
//System.arraycopy(original, 0, combined, 0, original.length);
//System.arraycopy(extraElements, 0, combined, original.length,extraElements.length);
jlrField.set(instance, combined);
}
到此将patch.dex放进了Element,接下来的问题就是加载Class,当加载patch.dex中类的时候,会遇到一个问题,这个问题就是QQ空间团队遇到,Classd的CLASS_ISPREVERIFIED。具体原因是dvmResolveClass这个方法对Class进行了校验。判断这个要Resolve的class是否和其引用来自一个dex。如果不是,就会遇到问题。
当引用这和被引用者不在同一个dex中就会抛出异常,导致Resolve失败。QQ空间团队的方案是阻止所有的Class类打上CLASS_ISPREVERIFIED来逃过校验,这种方式其实是影响性能。
我们的方案是和QQ团队的类似,但是和QQ空间不同的是,我们将fromUnverifiedConstant设置为true,来逃过校验,达到补丁的路径。具体怎么实现呢?
要引用Cydia Hook技术来hook Native dalvik中dvmResolveClass这个方法。有关Cydia Hook技术请参考:
官网地址:http://www.cydiasubstrate.com/
官方教程:http://www.cydiasubstrate.com/id/38be592b-bda7-4dd2-b049-cec44ef7a73b
SDK下载地址:http://asdk.cydiasubstrate.com/zips/cydia_substrate-r2.zip
具体代码如下。
//指明要hook的lib :
MSConfig(MSFilterLibrary,"/system/lib/libdvm.so")
// 在初始化的时候进行hook
MSInitialize {
LOGD("Cydia Init");
MSImageRef image;
//载入lib
image = MSGetImageByName("/system/lib/libdvm.so");
if (image != NULL) {
LOGD("image is not null");
void *dexload=MSFindSymbol(image,"dvmResolveClass");
if(dexload != NULL) {
LOGD("dexloadis not null");
MSHookFunction(dexload, (void*)proxyDvmResolveClass, (void**)&dvmResolveClass_Proxy);
} else{
LOGD("errorfind dvmResolveClass");
}
}
}
// 在初始化的时候进行hook//保留原来的地址
ClassObject* (*dvmResolveClass_Proxy)(ClassObject* referrer, u4 classIdx, boolfromUnverifiedConstant);
// 新方法地址
static ClassObject* proxyDvmResolveClass(ClassObject* referrer, u4 classIdx,bool fromUnverifiedConstant) {
return dvmResolveClass_Proxy(referrer, classIdx,true);
}
有人可能会担心cydia Hook性能,稳定性问题,但是据我所知,目前有些公司已经用它来实现apk加壳和脱壳防止反编译技术方案。具体可以参考http://www.gitzx.com/android-cydiasubstrate/
到这里为止在线热补丁修补方案就完了,由于本人技术原因,可能有些东西没有讲清楚,或者有什么纰漏,请告知。最后,这个方案我近期会整理一下开源出来。
github代码:https://github.com/Jarlene/ClassPatch.git
基于cydia Hook在线热修复补丁方案相关推荐
- 手把手教你使用Tinker Platform进行热修复补丁管理
使用Tinker Platform进行热修复补丁管理 这是手把手教你使用腾讯的热修复框架-Tinker的姊妹篇,它主要讲述了如何接入Tinker以及Tinker的基本使用,不熟悉的可以点击了解一下. ...
- MySQL 主从架构在线热迁移MGR 方案
目录 迁移拓扑图 业务方案沟通 相关知识传送门 准备工作 MGR数据迁移 迁移拓扑图 例子中的场景是 M-S 3305 转到 G-R 3306 业务方案沟通 1.迁移前检查 a. 表必须使用Inno ...
- 国内基于浏览器的在线截屏插件方案汇总分析
国产比较好的支持多版本浏览器的在线截屏商业插件,应该就这三家了: http://blog.csdn.net/ldevs/article/details/10102693 http://www.cnb ...
- 【热修复】Andfix源码分析
转载请标注来源:http://www.cnblogs.com/charles04/p/8471301.html Andfix源码分析 0.目录 背景介绍 源码分析 方案评价 总结与思考 参考文献 1. ...
- Alibaba-Dexposed框架在线热补丁修复的使用
目录(?)[+] 前两篇已经介绍了alibaba的AndFix热修复: Alibaba-AndFix Bug热修复框架的使用 Alibaba-AndFix Bug热修复框架原理及源码解析 DexP ...
- 《android基于andFix的热修复方案》思路篇
1:需求背景 项目上线之后,发现BUG需要修复(比如安卓兼容性等测试难以发现的问题),频繁的更新影响用户体验 2:方案要求 静默下载,耗费流量少,打完补丁后立刻生效,不用重启apk 3:解决思路 3. ...
- 热修复系列之一----Android 热修复原理篇及几大方案比较
热修复说白了就是"即时无感打补丁",比如你们公司上线一个app,用户反应有重大bug,需要紧急修复.2015年以来,Android开发领域里对热修复技术的讨论和分享越来越多,同时也 ...
- Android 热修复原理篇及几大方案比较
热修复说白了就是"即时无感打补丁",比如你们公司上线一个app,用户反应有重大bug,需要紧急修复.2015年以来,Android开发领域里对热修复技术的讨论和分享越来越多,同时也 ...
- 干货满满,Android热修复方案介绍
摘要:在云栖社区技术直播中,阿里云客户端工程师李亚洲(毕言)从技术原理层面解析和比较了业界几大热修复方案,揭开了Qxxx方案.Instant Run以及阿里Sophix等热修复方案的神秘面纱,帮助大家 ...
最新文章
- 2021年大数据Flink(三十二):​​​​​​​Table与SQL案例准备 API
- [转]优化Flash性能
- Spring启动流程(原理)详解--结合web.xml加载配置分析 转
- 《Windows Server 2012 Hyper-V虚拟化管理实践》一第1章 Hyper-V服务器选型
- Dijkstra 算法
- Postman接口调试神器
- [译] 绘制路径:Android 中矢量图渲染
- 关于信贷资产逾期计算口径和小微模型的经典问题与答案
- Haproxy负载均衡详解,与keepalived的搭配
- python中的common_common:个人基础函数库
- Ubuntu linux下的命令大全
- Windows7下完美绿色版无损分区软件Paragon Partition Manager
- CCF-CSP历年真题大全附题解(202209已更)
- (适合小白)利用百度AI开放平台实现人脸检测,对比和搜索。
- 扩增子图表解读4曼哈顿图:差异OTU或Taxonomy
- 2015年3月PMP认证考试报名通知
- 【技术栈——00061】搭建关于python项目docker镜像的Dockerfile文件示例(自己的)
- 能详细讲一下关于 18 世纪哲学家大卫 • 休谟和恐怖悖论吗
- java中return不运行的情况_Java中try catch finally语句中含return语句的执行情况总结-编程陷阱...
- Arduino音乐频谱
热门文章
- vscode wamp php,在WAMP环境中为Visual Studio Code安装PHP CodeSniffer(phpcs)
- 如何正确地还原一个3阶魔方
- Chrome浏览器插件开发-淘宝自动登录
- On Equality-Generating Dependencies in Ontology Querying - Preliminary Report
- Home Server
- Multiple Lights
- python 练习 tcp 服务器与客户端发、接信息,pycharm
- Java 根据开始日期和结束日期,获取日期之间的工作日,去除了周末和法定节假日
- 云服务器架设网站教程_手把手教你搭建腾讯云服务器入门(图文教程)
- 2019年10月13日(周日)上午7:30起跑,2019郑州国际马拉松赛,比赛须知