原文链接 Android 逆向技术高阶大法
安卓利用是一个客户端,与传统软件相似,须要把软件打包,而后通过某种渠道(利用市场)分发给用户,这是惯例的公布形式,它的更新节奏很慢,从你在利用市场上更新后,到用户真正的执行降级,这两头很慢的,而且很多用户基本不会降级新版本,这对于互联网来说是极不敌对的。传统的互联网,用户刷新一下网页后,就能看失去更新了,但对于客户端,这行不通,要想实现小时级别的公布和分钟级别的问题修复,正规的公布渠道是做不到的。于是各路大神和专家开始钻研客户端的前端化,也就是使用各种技术能让公布,特地是一些问题修复性的小规模公布能够更快的传递到用户手中。
这与正向办法不一样,谷歌或者水果针对 利用市场有明确 的流程的,这是惯例公布也即是正向形式。明天咱们来聊一聊非正向办法,非常规形式,来实现小模块的公布和热修复。
核心技术原理
任何一项技术都离不开编程语言和操作系统上的反对,对于插件化技术来说,最为外围的原理就是 Java 反对反射,这是一种运行时批改代码的技术,另外就是动静代理,这是插件化可行的基本技术撑持。
说到底,Java 仍是一种解释型语言,它的外围是 JVM,即也虚拟机,咱们所相熟的 Java 编程语言,实质上是套在 JVM 上的一层语法规定,换了一种语言规定也是可行的。就好比 Kotlin,Scala 和 Groovy 它们的语法与 Java 相差很大,但它们编译过后的字节码是完全符合 JVM 标准的,能够间接运行在 JVM 之上。
其余的纯解释型语言,如 Python 和 JavaScript,它们在运行时能够动静的加载一段源码,这即是动态化,能够实现真正的插件化,运行时间接加载运行一段代码。Java 略变态一些,但它实质上是 JVM,而 JVM 通过反射和动静代理,在肯定水平上反对了相似的动态化,就是通过 ClassLoader 来动静加载一些编译好的 Class。
此为插件化的外围原理。
动静代理机制,能够读这几篇文章:
- 动静代理大揭秘,带你彻底弄清楚动静代理
- 动静代理
- Java 的动静代理(dynamic proxy)
- java 动静代理实现与原理详细分析
- 小白也能看懂的插件化 DroidPlugin 原理(一)– 动静代理
Hook 大法
有了外围原理,才有可行的计划。Hook 次要钻研三方面内容,一是钻研 ClassLoader,因为不同的 dex 分属于不同的层级,它们的 ClassLoader 不一样,反射的第一步就是要能加载到想要的 Class,这个要靠找到适合的 ClassLoader;二是动静代理机制,hook 的外围原理就是用动静代理机制,创立一个 Mock 对象用以替换掉原来的,所以接口 Interface 是要害,原零碎设计中必须应用大量接口,并且是以规范形式应用的(没有强制向下转型 downcast),这样你创立进去的动静代理去替换才是平安的;三就是学习安卓系统核心组件 的流程,以找到最佳的 hook 地点。
其实,第 3 条才是对大部分人最为无益的。
具体如何做 hook,能够参考以下文章:
- Android 插件化原理解析——Service 的插件化
- Android 插件化原理解析——Hook 机制之 AMS&PMS
- 摸索 Android 开源框架 – 10. 插件化原理
- 小白也能看懂的插件化 DroidPlugin 原理(二)– 反射机制和 Hook 入门
因为安卓版本升级的起因,下面这几个文章都生效了,例子行不通了。然而这几遍对于原理解释的还是相当分明的。
以下文章对于新版本也是实用的。
- 基于 Android9.0 的 Hook Activity 的启动(插件化)
- Android Hook Activity 的几种姿态
- Activity 插件化原理第一种计划:Hook Instrumentation
- Activity 插件化原理第二种计划:Hook IActivityManager
- 拦挡 Activity 的启动流程绕过 AndroidManifest 检测
须要留神的是,hook 这件事件,最根底的技术很简略,就通过反射来替换对象,把零碎中的对象替换为仿造的,仿造有三种形式,一是间接创立,这须要类是比较简单的状况,并不需要凋谢进去,通过反射所有皆可创立;二是持续,这个对于简单对象也能仿造,如 Instrumentation,然而须要类是凋谢进去的;三是接口,通过动静代理 创立仿造对象(也即代理)。核心技术就这些。其余的,全是对于零碎代码的了解,找到可行的关键点来进行 hook。
另外就是,谷歌对逆向办法限度越来越严了,反射零碎的货色,会有限度,有时仅是打印日志,但指不定哪天就不给反射了。
Accessing hidden field Landroid/app/ActivityManager;->IActivityManagerSingleton:Landroid/util/Singleton; (light greylist, reflection)
插件化原理
学习一门技术最好的形式就是去研读优良的开源库的源码,对于插件化,当初有很多比拟成熟 的开源框架存在了,能够挑几个比拟有代表性的来钻研 一下。
DroidPlugin
这个基于动静代理创立的插件办法,较为风行,外面有大量的 hook 技术,网络上也有很多解析此框架的文章,能够帮忙了解。
它用了大量的 hook,长处就是插件自身能够是失常的 apk,无太多的限度,就用惯例的 app 开发方式开发就好,这是它的最大劣势,因为对插件无限度,所以框架自身就须要做大量的 hook,是学习 hook 技法的良好例子。
DL : Apk 动静加载框架
这个是以动态代理为根底创立的插件框架,并没有大量的 hook,能够参看它的解析文章。
任大神的框架适配性较好,基本上是纯软件层的技术(动态代理),没怎么 hook。当然毛病也相当显著,就是对于插件的开发要求很刻薄,必须实现框架自身自定义的一坨货色,与安卓规范的 app 开发差别较大,且越来越大,并且对于打包和开发过程并无工具反对,在理论利用过程中较为麻烦。退一步讲,并未有真正达到插化的目标,它对插件的限度较大。
当初曾经根本没人用了,不过这属于开山之作。
Qigsaw
这个与其余插件框架的最大差异在于,它最靠近于官网的货色(App bundle),它的重点在于我的项目模块化和打包下面,对于惯例了解上的『插件』所做的事件特地少,hook 特地少,装置和加载插件的过程比拟很简略,靠近原生,外围在于它的打包过程。这里有具体的介绍。
另外,包建强的书《Android 插件化开发指南》也能够读一读的,书的益处在于,它毕竟是一个整体,从根底的技术原理到 hook 原理都有讲,还是相当不错的。不过书比拟旧了,要联合作者的勘误,以及网上的文章一起来消化了解。
热修复原理
除了插件化,另外一个大厂热衷的技术便是热修复,这也是大厂头部利用的标配技术。其实插件化,也能实现热修复,比方某个插件,个别是厂里的一个业务,出问题了,紧急打包公布一个修复的版本,而后更新插件。不过,这略显轻便,相当于用牛刀去杀鸡了,总之就是效率不高。
真正的热修复技术考究效率,且要玲珑,针对 点对点式的修复。它的外围原理就是替换,用反射去替换类(批改 dex classloader 中的 dex 程序),以及对办法的替换(侵入虚拟机中的 method 表,进行替换),还分冷失效(类替换个别是冷失效,也即下次启动时失效)和热失效(办法替换个别是热的,下次调用此办法时就失效了,因为它并不波及 classloader,无须要从新加载类),还有插桩式的,在代码中间接插桩,先查看有没有 patch,有 patch 就先运行 patch(这个思路最简略,适配性也好,但履行难度大,须要对现有代码进行插桩)。
这几篇文章有比拟具体的探讨。
- Android 热修复技术原理详解
- Android 热修复技术,你会怎么选?
- 摸索 Android 开源框架 – 11. 热修复原理
具体的热修复工具
xposed 派别
也即原生的 Xposed 和 Xposed framework
以及大阿里的衍生版本 dexposed。
针对 办法能够热失效的 hook,当年 Dalvik 时代,这个货色还是相当牛逼的,时过境迁尽管 Art 上无奈用了,但无妨用来学习。
Andfix
原产自支付宝的与 Xposed 相似的办法级的 hook 工具,反对 Dalvik 与 Art,值得应用和学习。
AndroidMethodHook
能够用来学习 sophix,sophix 是大阿里的货色,把 andfix 以及 dexposed 商业化了,不再开源收费用了。这个我的项目比拟靠近它们,能够用来学习。
Tinker
微信出品的 Tinker,核心技术还是用 dex 替换实现的 class 替换,冷失效。
它的重点在于补丁 dex 的差量生成,以及公布平台,还做成了免费平台,变成一种服务。所以,你看核心技术是由指标平台(安卓)决定的,原理大家也都懂,各家也都大差不差的,也都有开源现成的计划能够用,但这远远不够,整个链路是值得深挖的,这也是能产生商业价值的中央。
HotFix
安卓 App 热补丁动静修复技术介绍
Nuwa
安卓热更新之 Nuwa 实现步骤
Robust
Android 热更新计划 Robust 开源,新增自动化补丁工具
这个与 Nuwa 一样,都用了代码插桩,当然插桩过程,是用了字节码工具(如 ASM),进行编译时自动化解决,最终字节码(APK)是受影响的,但源码层面是无感知的。
瓶颈在哪里
插件化这项技术,它的老本特地高,但收益无限,须要宏大的研发体系来反对,并且只有长期投入,能力产出一些价值。因而,当初来说只有头部大厂才真正玩得转。
技术自身并不是瓶颈
这项技术的可行性是由 Java 决定的,因而始终是可行的。但每年的 Android 版本,都会对外围组件进行不同水平的强化和降级,这会导致之前的一些计划可能一下子就生效了。另外,手机厂商可能也会做一些批改,不过个别都比拟小。
安卓 版本升级,会对插件化有影响,甚至会让现有计划全副生效,但这个还真不是这项技术的瓶颈。因为安卓 降级较慢,失常一年一个版本,然而对外围组件大变动,通常几年才有一次,这个速度比照三方技术的演进还是相当慢的。后面说了这项技术头部大厂最为受害,因而他们会有专门的专家级别的人物在钻研,谷歌出了政策,很快就会对策进去,个别用不了多久,插件化技术大拿们就能给出针对 新版本的解决方案。
因为开源和技术分享,很快便会在业界遍及。因而,单就技术自身,绝不是瓶颈,并且因为开源的倒退,外围业务自身都是开源的,大家都能很快应用最先进的技术。
网络和平台能力才是瓶颈
插件化这个事件,想要真正的用好,光有外围业务还是不够的。外围业务当初都有现成的开源库,拿过去就能够用,但这远远不够。
就从一个插件从开发人员手中到用户手中,并胜利装置失效,这一过程拆来看须要多少货色吧:
- 插件的开发,须要一些辅助工具。现实的状况下,一个插件模块的开发,应该与惯例利用开发是一样的,但毕竟它的构建指标是一个插件,而非标准的 app,所以你须要针对外围业务插件框架实用的一些开发工具。这个个别开源框架中都有提供,但不见得有那么好。
- 构建和打包。如果是一个合格的插件化框架,肯定会有怎么构建 打包的配套设施。
- 测试和调试。这外面的难点在于,如何能尽可能的模仿实在的流程,并且能不便的来施行测试和验证后果
- 公布上线管制。一些细节就是如何精准推送,如何做灰度公布,以及发现问题后如何疾速回滚(你看,这哪一项波及插件化技术)
- 下载。客户端的一个最大的问题就是,客户端在客户那里,咱们公布的货色都在服务器上,如何能让插件顺利的送达到用户手中。别小看这个,网络问题永远是出谬误起因外面最多的一个,而且容易被测试疏忽,因为研发人员本人的网络环境个别简略且稳固。(一个最简略的测试就是,当你在电梯里,地铁里,高铁时,厕所里,山上,河里,村里,手机外面的利用还有几个能失常联网的?)
- 装置和失效。这个也是插件化的外围业务,框架都会反对的。难点在于校验,就是客户端拿到的插件是不是合乎预期的,文件有没有损坏,有没被篡改。
- 降级。这个通常插件化框架不会提供。降级的意思就是如果插件装置更新失败了,你怎么办?是否回滚,如果这个插件彻底废了,有没有 H5 页面能够用?
咱们粗略来看,就能分出下面 7 个步骤,其实还有更细的。下面这些里,插件化开源框架肯定能解决的是 2 和 6,1 和 3 会在肯定水平上反对。而其余的只有靠本人了,当然 也可能会有一些开源软件能够用,但它们并不纯是为了插件化而做的。这些货色都属于研发效率平台,甚至是波及软件流程,基本上都属于商业公司的外围业务秘密了,基本上是不可能开源的,而且不同的公司文化制度流程都不一样,即便开源给你了,也不肯定用得上。但这恰好又是最能体现一个公司联合技术实力的中央,小公司或者综合能力差的公司,即便有现成的插件化框架计划给你,你也用不好,因为配套设施不行。再次佐证,插件化这货色只有头部大厂能力玩得转,并产生正收益。
这些才是真正的瓶颈。
这是逆向工程技术
插件化须要用到大量的反射和动静代理技术去 hook 安卓零碎,从而实现官网并不间接反对的个性,这属于逆向工程,与官网提倡的方向并不统一。
而且,只有在国内圈子外面才比拟风行,国外的一些大厂和专家仿佛并不违心花工夫和精力搞这些事件。很难简略的用好与坏来评估,只能说文化不同。
逆向工程技术局限性较大,很难短暂倒退,一旦官网把某个要害中央堵住(不能说是破绽,而一些要害的对象和接口),很多插件框架可能就废掉了,当然了道高一尺,魔高一丈,总还是能找到能够 hook 的中央,仍总感觉怪怪的。
惯例的技术,如编程范式(函数式编程,Reactive,RxJava),编程语言,平台框架和轮子(如 Picasso,如 OkHttp),这些是纯正的技术,不受制于任何平台,岂但能短暂倒退,更能反过来推动官网提高(如 OkHttp 已被谷歌内置为安卓外部作为 HTTP 协定的实现)。
综合来说,除非你须要专门钻研插件化,并能失去收益之外(对业务,对公司,对集体),对于插件化技术,理解一下就够了,而且这货色并不能真正的晋升软件品质(它带来的问题比它解决的要多很多)。不如把工夫花在业务下面,花在编程范式,花在编程语言,花在风行的框架和轮子下面,这更能晋升软件品质,且是终生受害的。毕竟,如果代码品质够好,收回去的版本都可控,都能达到预期,也就没必要折腾插件化了(即便是对大厂头部利用来说,版本的公布仍次要是靠失常的 apk 公布,插件迭代个别用在失常版本来不及时应用比方电商的双 11 期间)。
研发工具(如 Instant Run),调试工具(如获取 一些运行时的信息,在线调试),测试工具(如 Mock),不侵入源码式编程(动静插桩,AOP 和依赖注入)才是反射和动静代理以及 Hook 的最终归宿,是值得咱们深入研究和学习的方向。
参考资料
- 动静注入技术(hook 技术)
- Android 插件化原理解析——Hook 机制之动静代理
- 插件化常识具体合成及原理 之代理,hook,反射
- 盘点 Android 罕用 Hook 技术
- 了解 Android Hook 技术以及简略实战
- Android Hook 技术防备漫谈
- Android 插件化——高手必备的 Hook 技术
- Android Hook 机制之简略实战
- 字节跳动开源 Android PLT hook 计划 bhook