Android逆向技术高阶大法

原文链接 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.rhkb.cn/news/141280.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【加载数据--自定义自己的Dataset类】

【加载数据自定义自己的Dataset类】 1 加载数据2 数据转换3 自定义Dataset类4 划分训练集和测试集5 提取一批次数据并绘制样例图 假设有四种天气图片数据全部存放与一个文件夹中,如下图所示: ├─dataset2 │ cloudy1.jpg │ cloudy10.jpg │ …

【React】JSX语法

目录 一、前言二、JSX介绍三、JSX原理1、DOM结构示例2、HTML的JSX结构示例3、编译之后的代码 四、为什么使用JSX1、JSX的特点2、JSX的书写规范 五、JSX的使用1、嵌入JS表达式2、条件渲染3、列表渲染①、arr.map() 六、组件1、类组件①、实例化组件 2、函数组件3、组件样式①、行…

全自动情感故事对话视频生成神器

搞笑聊天视频是近年来备受欢迎的一种娱乐形式,它能够快速、简单地制作出形象生动、幽默搞笑的对话视频,给人带来欢乐与笑声。而今天,我要向大家介绍的是一款功能强大、操作简单的搞笑聊天视频生成器。 这款聊天视频生成器具备多项令人惊叹的…

排序算法二 归并排序和快速排序

目录 归并排序 快速排序 1 挖坑法​编辑 2 Hoare法 快排的优化 快排的非递归方法 七大排序算法复杂度及稳定性分析 归并排序 归并排序是建立在归并操作上的一种有效的排序算法,将以有序的子序列合并,得到完全有序的序列,即先使每个子序列有序,在使子序列段间有序.若将两…

virtualbox无界面打开linux虚拟机的bat脚本,以及idea(代替Xshell)连接linux虚拟机的方法

virtualbox无界面打开linux虚拟机的bat脚本,以及idea连接linux虚拟机的方法 命令行运行代码成功运行的效果图 idea连接linux虚拟机的方法【重要】查看虚拟机的IP地址idea中选择菜单(该功能可代替Xshell软件)配置设置连接成功进入idea中的命令…

2018-2022年盟浪 ESG数据

2018-2022年盟浪 ESG数据 1、时间:2018-2022年 2、指标:证券代码、证券简称、盟浪ESG评级、省份、城市、所属证监会行业名称[交易日期] 最新收盘日[行业级别] 大类行业、所属证监会行业代码[交易日期] 最新收盘日[行业级别] 大类行业 3、范围&#xf…

ISE_ChipScope Pro的使用

1.ChipScope Pro Core Inserter 使用流程 在之前以及编译好的流水灯实验上进行学习 ChipScope的使用。 一、新建一个ChipScope 核 点击Next,然后在下一个框中选择 Finish,你就会在项目菜单中看到有XX.cdc核文件。 二、对核文件进行设置 右键“Synthesize – XST” …

【LeetCode热题100】--53.最大子数组和

53.最大子数组和 使用动态规划: 状态定义:设动态规划列表dp,dp[i]代表以元素nums[i]为结尾的连续子数组最大和 转移方程:若dp[i-1]≤0,说明dp[i-1]对dp[i]产生负贡献,即dp[i-1]nums[i]还不如nums[i]本身大 初始状态&…

vue+element项目创建步骤

一、创建vue项目步骤 要创建一个Vue Element UI的项目,你可以按照以下步骤进行操作: 1.确保你已经安装了Node.js和npm(Node.js的包管理器)。你可以在命令行中运行以下命令来检查它们是否已经安装: node -vnpm -v2.使…

打开深度学习的锁:(2)单隐藏层的神经网络

打开深度学习的锁 导言PS:神经网络的训练过程一、数据集和包的说明1.1准备文件1.2 需要导入的包 二、构建神经网络的架构三、初始化函数四、激活函数4.1 tanh(双曲正切函数)函数 五,前向传播六、损失函数七、后向传播八、梯度下降…

vite + vue3 + js 搭建组件库 + 核心配置与使用

vite.config.js 这个官网有写 import { defineConfig } from vite import vue from vitejs/plugin-vue import path from "path" // https://vitejs.dev/config/ export default defineConfig({plugins: [vue()],server:{open:true, //自动打开浏览port:8088 //默认…

适用于初学者,毕业设计的5个c语言项目,代码已开源

C语言项目集 项目介绍 该项目适用于初学者学习c语言,也适用于高校学生课程设计,毕业设计参考。 项目并不能满足所有人的需求,可进行项目指导,定制开发。 开源地址 c语言项目代码地址 项目列表 该项目包含如下5个管理系统&am…

游戏录屏软件推荐,教你录制高清游戏视频

“有没有好用的游戏录屏软件推荐呀,最近当上了游戏主播,平台要求每天都要发一个游戏视频,可是我的游戏录屏软件太拉胯了,录制出来的视频非常糊,导致平台审核不通过,所以想问问大家有没有游戏录屏软件推荐一…

Vue的单文件组件(Single File Components):优势与实例

Vue的单文件组件(Single File Components):优势与实例 Vue.js 是一款流行的前端 JavaScript 框架,它采用了一种特殊的组件化开发方式,被称为单文件组件(Single File Components,简称 SFC&#…

Eclipse初步学习使用

1.配置自动填充 window->preference 2.自动判断错误,并给出解决方法 3.创建可执行文件: 新建package, 包内新建 javaclass,选择psvm, 4.编写程序,进行执行 右键,选择 run as applic…

ideogram.ai 不同风格的效果图

https://ideogram.ai/ 提示词: French bulldog with sunglasses, playing skateboarding, speed up, happiness, front viewPhoto 相片 正常照片 Poster 海报 偏绘画,清晰的勾线 3D Render 3D 渲染 胶质感,像 3D 模型 Typography …

MySQL学习笔记15

1、内连接查询(重点): 基本语法: select 数据表1.字段列表,数据表2.字段列表 from 数据表1 inner join 数据表2 on 连接条件; 案例:获取产品表中每个产品的分类信息: mysql> select * from tb_goods …

Linux-文件和目录权限

文章目录 权限的作用普通文本文件的权限作用目录文件权限功能作用 文件权限的设置 权限的作用 权限对于普通文件和目录文件的作用是不一样的。 普通文本文件的权限作用 drwxr-xr-x第二个字母开始是文件的权限表示9列权限,前三列表示文件的"拥有者"对该…

vue组件样式 scoped 冲突

vue组件样式 冲突 <template><div class"base-one">BaseOne</div> </template><script> export default {}; </script>/* 1.style中的样式 默认是作用到全局的2.加上scoped可以让样式变成局部样式组件都应该有独立的样式&…

如何将前后端分离的项目部署在服务器上

宝塔Linux部署&#xff1a; 因为要部署前端我们先下个nigx Tomcat,下载这个只是为了java&#xff0c;它里面包含java的 前端 在去添加站点&#xff0c;域名暂时是自己的公网 然后打开新建的站点&#xff0c;把里面的文件全删掉&#xff0c;再把自己的前端dist里的文件全选拖…