Android逆向技术高阶大法

news2024/10/7 10:13:40

原文链接 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版本,都会对核心组件进行不同程度的强化和升级,这会导致之前的一些方案可能一下子就失效了。另外,手机厂商可能也会做一些修改,不过一般都比较小。

安卓 版本升级,会对插件化有影响,甚至会让现有方案全部失效,但这个还真不是这项技术的瓶颈。因为安卓 升级较慢,正常一年一个版本,但是对核心组件大变化,通常几年才有一次,这个速度对比三方技术的演进还是相当慢的。前面说了这项技术头部大厂最为受益,因此他们会有专门的专家级别的人物在研究,谷歌出了政策,很快就会对策出来,一般用不了多久,插件化技术大拿们就能给出针对 新版本的解决方案。

由于开源和技术分享,很快便会在业界普及。因此,单就技术本身,绝不是瓶颈,并且由于开源的发展,核心业务本身都是开源的,大家都能很快使用最先进的技术。

网络和平台能力才是瓶颈

插件化这个事情,想要真正的用好,光有核心业务还是不够的。核心业务现在都有现成的开源库,拿过来就可以用,但这远远不够。

就从一个插件从开发人员手中到用户手中,并成功安装生效,这一过程拆来看需要多少东西吧:

  1. 插件的开发,需要一些辅助工具。理想的情况下,一个插件模块的开发,应该与常规应用开发是一样的,但毕竟它的构建目标是一个插件,而非标准的app,所以你需要针对核心业务插件框架适用的一些开发工具。这个一般开源框架中都有提供,但不见得有那么好。
  2. 构建和打包。如果是一个合格的插件化框架,一定会有怎么构建 打包的配套设施。
  3. 测试和调试。这里面的难点在于,如何能尽可能的模拟真实的流程,并且能方便的来实施测试和验证结果
  4. 发布上线控制。一些细节就是如何精准推送,如何做灰度发布,以及发现问题后如何快速回滚(你看,这哪一项涉及插件化技术)
  5. 下载。客户端的一个最大的问题就是,客户端在客户那里,我们发布的东西都在服务器上,如何能让插件顺利的送达到用户手中。别小看这个,网络问题永远是出错误原因里面最多的一个,而且容易被测试忽略,因为研发人员自己的网络环境一般简单且稳定。(一个最简单的测试就是,当你在电梯里,地铁里,高铁时,厕所里,山上,河里,村里,手机里面的应用还有几个能正常联网的?)
  6. 安装和生效。这个也是插件化的核心业务,框架都会支持的。难点在于校验,就是客户端拿到的插件是不是符合预期的,文件有没有损坏,有没被篡改。
  7. 降级。这个通常插件化框架不会提供。降级的意思就是如果插件安装更新失败了,你怎么办?能否回滚,如果这个插件彻底废了,有没有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

原创不易,打赏点赞在看收藏分享 总要有一个吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1039793.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

系统集成|第十四章(笔记)

目录 第十四章 合同管理14.1 概述及相关概念14.2 项目合同14.3 《合同法》14.4 《仲裁法》 上篇:第十三章、干系人管理 第十四章 合同管理 14.1 概述及相关概念 主要包括合同签订管理,合同履行管理,合同变更管理以及合同档案管理。作为一个重…

自拟实现消息队列(MQ)基于Rabbit MQ(含概念和源码)巨详细!!!!!含思维导图

MQ目录 MQ基本概念什么是MQ?MQ的应用场景 首先先明白需求持久化分析那么MQ如何设计持久化? 可靠性分析高效性分析MQ核心概念(装配层)实现MQ组件思维导图创建项目导入数据库下载SqLite。 创建组件实体类创建交换机(要加…

精通Linux系列第一章:探索Linux世界的大门

文章目录 一、前言二、 什么是Linux?三、Linux系统与Windows系统的区别四、为什么要学习Linux?五、 Linux的优势六、什么是Linux发行版?七、常见的Linux发行版八、如何选择适合你的Linux发行版?九、Linux各种发行版的优势与应用十…

【C语言】进阶——结构体+枚举+联合

①前言: 在之前【C语言】初阶——结构体 ,简单介绍了结构体。而C语言中结构体的内容还有更深层次的内容。 一.结构体 结构体(struct)是由一系列具有相同类型或不同类型的数据项构成的数据集合,这些数据项称为结构体的成员。 1.结构体的声明 …

NVM:node多版本管理的下载安装及使用

NVM:node多版本管理的下载安装及使用 使用之前先卸载node,避免各种奇葩问题导致不成功。win卸载:win > 设置 > 应用 > 应用和功能,找到 node 点击出现卸载按钮并且卸载它。 1、下载安装: https://github.co…

信创之国产浪潮电脑+统信UOS操作系统体验1:硬件及软件常规功能支持情况介绍

一、引言 由于公司要求支持国产信创,最近办公的笔记本电脑换成了软硬件全国产,由于国产操作系统是在开源linux基础上演进的,在换之前,非常担心操作不方便,周边应用软件少,功能差,内心是比较抗拒…

C++:优先级队列模拟实现和仿函数的概念使用

文章目录 使用方法Compare仿函数一些场景模板参数和函数参数 本篇总结优先级队列 使用方法 首先在官网查看它的一些用法 template <class T, class Container vector<T>,class Compare less<typename Container::value_type> > class priority_queue;从…

软件测试之接口测试

1、什么是接口测试 顾名思义&#xff0c;接口测试是对系统或组件之间的接口进行测试&#xff0c;主要是校验数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及相互逻辑依赖关系。其中接口协议分为HTTP,WebService,Dubbo,Thrift,Socket等类型&#xff0c;测试类型又主…

Crypto:MD5

题目 下载了题目给的压缩包解压后&#xff0c;打开文件 使用md5解码器解码后得到&#xff0c;即为flag

DS18B20温度传感器

DS18B20简介 DS18B20 是由 DALLAS 半导体公司推出的一种的“一线总线&#xff08;单总线&#xff09;”接口的温度传感器 这种一线总线就是 三线制 SPI DS18B20的 配置寄存器&#xff1a; TM 是测试位&#xff0c;出厂设置就被设置为0&#xff0c;不需要改动&#xff0c; R1、R…

linux————ceph分布式部署

目录 一、概述 特点 1、统一存储 2、高扩展性 3、可靠性强 4、高性能 组件 1、Monitor 2、OSD 3、MOD 4、Objet 5、PG 6、RADOS 7. Libradio 8. CRUSH 9. RBD 10. RGW 11. CephFS 架构图 二、准备工作 三、ceph安装 创建集群目录 修改配置文件 安装 初…

数据结构上机1

1、题目&#xff1a; 将1~10存入数组a[10]&#xff0c;并将其逆序输出 #define _CRT_SECURE_NO_WARNINGS 1 //(1) 将1~10存入数组a[10]&#xff0c;并将其逆序输出#include <stdio.h>int main() {int a[10];// 将1到10存入数组a[10]for (int i 0; i < 10; i){a[i] i…

[硬件基础]-快速了解I2C串行通信协议

快速了解I2C串行通信协议 文章目录 快速了解I2C串行通信协议1、硬件接口2、数据帧3、数据操作4、时钟拉伸&#xff08;Clock Stretching&#xff09;5、总线仲裁6、权衡&#xff1a;功率与速度7、总结 内部集成电路协议&#xff08;Inter-Integrated Circuit Protocol&#xff…

TS编译选项——TS代码错误不生成编译文件

一、TS不生成编译文件 在tsconfig.js文件中配置noEmit属性 {"compilerOptions": {// outDir 用于指定编译后文件所在目录"outDir": "./dist", // 将编译后文件放在dis目录下// 不生成编译后的文件"noEmit": true,} } 二、TS代码错…

看到一个外贸经典案例, 分享一下

最近看到一个经典案例&#xff0c;案例可能没有多少新奇&#xff0c;但是大家的评论以及给出的解决方案却能给我们很多启发&#xff0c;一个事情要从多方面去进行假设然后一一排除去找到最合适的解决方法&#xff0c; 下面&#xff0c;让我们一起来看看这个外贸小伙伴遇到的问…

《你好,C语言》:从另一个视角学习并重新审视C语言的意义

《你好&#xff0c;C语言》&#xff1a;从另一个视角学习并重新审视C语言的意义 尽管C语言诞生了这么多年&#xff0c;但是它依然活跃在开发者一线&#xff0c;不可否认的是C语言的确有它独特的魅力。本文将从一个全新的视角&#xff0c;重新带领大家学习领悟C语言的奥秘&#…

[XR-FRAME] 1.O3 文档导览 || XR-FRAME / 有点寡淡,加上图像

开始 | 微信开放文档 文档导览 - XR-FRAME / 有点寡淡&#xff0c;加上图像 。 文档导览&#xff0c;知识点整理。 加入纹理 &#xff1a; 新学习标签&#xff1a; <xr-assets bind:progress"handleAssetsProgress" bind:loaded"handleAssetsLoaded…

TS编译选项——编译TS文件同时对JS文件进行编译

一、允许对JS文件进行编译 我们在默认情况下编译TS项目时是不能编译js文件的&#xff0c;如下图中的hello.js文件并未编译到dist目录下&#xff08;这里配置了编译文件放到dist目录下&#xff09; 如果我们想要实现编译TS文件同时对JS文件进行编译&#xff0c;就需要在tsconfi…

GIS基础教程之坐标系

本教程从以下几个方面入手&#xff1a; 坐标系的基本概念 地理坐标系 投影坐标系 如何选择坐标系 根据研究区域大小 根据研究目的&#xff08;等角&#xff1f;等面积&#xff1f;等距离&#xff1f;其他&#xff09; 推荐一个在线坐标系选择网站 GIS坐标系几种情况 数…

【dbeaver】win环境的kerberos认证和Clouders集群中Kerberos认证使用Dbeaver连接Hive和Phoenix

一、下载驱动 cloudera官网 1.1 官网页面下载 下载页面 的Database Drivers 挑选比较新的版本即可。 1.2 集群下载 Hive可能集群没有驱动包。驱动包名称&#xff1a;HiveJDBC42.jar。41结尾的包也可以使用的。注意Jar包的大小一定是十几MB的。几百KB的是thin包不可用。 …