竹笋

首页 » 问答 » 环境 » AndroidAPP漏洞之战插件化漏洞
TUhjnbcbe - 2022/5/14 14:44:00

本文为看雪论坛精华???文章看雪论坛作者ID:随风而行aa

前言

最近一直处于忙碌的状态,花了很长一段时间,抽出碎片时间才将这篇帖子写完,本文结合上文的动态加载文章一起学习,本文主要讲述Android中存在的插件化漏洞、签名机制漏洞、解压缩漏洞等,并对一些经典的漏洞进行了复现,本文的相关实验文件由于太多,后面都会上传到知识星球。本文第二节主要讲述Dex文件结构、Zip文件结构、Android签名机制。本文第三节主要讲述插件化漏洞和解压缩漏洞的安全场景。本文第四节主要对插件化漏洞进行讲述。本文第五节主要对解压缩漏洞进行讲述。本文第六节主要对Janus漏洞原理进行讲述。

基础知识

1.Dex文件基本结构dex文件是anroid虚拟机Dalik运行的一种文件,包含应用程序的全部操作指令以及运行时数据,下面我们看下.class文件和.dex文件的区别:我们可以发现dex文件将原来每个文件都有的共有信息合成一体,从而减少了class的冗余。下面我们进一步详细看dex文件结构。我们可以发现dex文件主要由大部分组成,分别是:文件头、索引区、数据区。其中索引区主要包括字符串、类型、方法、域、方法的索引。数据区主要包括类的定义、数据区、链路数据区。上面我们可以看出Dex文件由许多部分组成,其中DexHeader最为重要,因为Dex的其他组成部分,都需要通过DexHeader中的索引才能找到。(1)DexHeaderdex文件头一般固定为0x70个字节大小,包括标志、版本号、校验码、sha-1签名以及其他一些方法、类的数量和偏移地址等信息。如图所示:结合上面的两张图进行对照,下面我们进一步详细的描述dex文件的结构。()索引区dex文件索引区主要是对一些字符串、类型、方法、域、方法的索引,方法可以查找到对应的数据位置。()数据区数据区一般包括类的定义区、数据区、链接数据区。类的定义区一般存放dex文件中一些类对象的声明,数据区则存放代码原数据,链接数据区一般提供从索引区到数据区的链接映射关系。.Zip文件结构zip文件是比较常见的压缩文件,我们先来看一下zip文件的基本结构图:通过图中我们可以看出,zip文件一般分为三个部分:源文件数据存储区、中心目录区、中心目录结束标识。(1)源文件数据存储区记录着压缩的所有文件的内容信息,其数据组织结构是每个文件都由localfileheader、filedata、datadescriptor三部分组成。1fileheader用于标识文件的开始,文件结构如下:filedata主要存放相应的压缩文件的源数据。datadescriptor一般用于标识该文件压缩结束,该结构只有在相应的header中通用标记字段的第3位设为1时才会出现,紧接在压缩文件源数据后。这个数据描述符只用在不能对输出的ZIP文件进行检索时使用。例如:在一个不能检索的驱动器(如:磁带机上)上的ZIP文件中。如果是磁盘上的ZIP文件一般没有这个数据描述符。()中心目录区对于待压缩的目录而言,每一个子目录对应一个压缩目录源数据,记录该目录的描述信息。压缩包中所有目录源数据连续存储在整个归档包的最后,这样便于向包中追加新的文件。头部的结构如下:()中心目录结束标识目录结束标识存在于整个归档包的结尾,用于标记压缩的目录数据的结束,结构如下:.AndroidAPK签名机制应用签名主要是避免外部恶意解压、破解或者反编译修改内容,签名的本质是:认证:Android平台上运行的每个应用都必须有开发者的签名。在安装应用时,软件包管理器会验证APK是否已经过适当签名,安装程序会拒绝没有获得签名就尝试安装应用。验证完整性:软件包管理器在安装应用前会验证应用摘要,如果破解者修改了apk里的内容,那么摘要就不再匹配,验证失败。(1)应用签名方案类型截止到Android1,Android支持三种应用签名方案:

v1:基于jar签名v:提高验证性能覆盖范围(Android7.0Nougat引入)v:支持密钥轮换(Android9.0Pie引入)为了提高兼容性,必须按照v1,v,v的先后顺序采用签名方案,低版本平台会忽略高版本的签名方案在APK中添加额外数据,具体流程图如下:1签名方案v1最基本的签名方案,是基于Jar的签名。v1签名后会增加META-INF文件夹,其中会有如下三个文件:v1签名流程:

①计算每个文件的SHA-1摘要,进行BASE6编码后写入摘要文件,即MANIFEST.MF文件;

②计算整个MANIFEST.MF文件的SHA-1摘要,进行BASE6编码后写入签名文件,即*.SF文件;

③计算MANIFEST.MF文件中每一块摘要的SHA-1摘要,进行BASE6编码后写入签名文件,即*.SF文件;

④计算整个*.SF文件的数字签名(先摘要再私钥加密);

⑤将数字签名和X.09开发者数字证书(公钥)写入*.RSA文件;

验证流程:主要包括验证签名、校验完整性两个步骤:步骤1:验证签名步骤

①取出*.RSA中包含的开发者证书,并校验其合法性

②用证书中的公钥解密*.RSA中包含的签名

③用证书中的公钥计算*.SF的签名

④对比()和()的签名是否一致

步骤:验证完整性

①检查APK中包含的所有文件,对应的摘要值与MANIFEST.MF文件中记录的值一致

②使用证书文件(RSA文件)检验签名文件(SF文件)没有被修改过

③使用签名文件(SF文件)检验MF文件没有被修改过

上面任何一个步骤验证失败,则整个APK验证失败。问题:覆盖范围不足:Zip文件中部分内容不在验证范围,例如META-INF文件夹;验证性能差:验证程序必须解压所有压缩的条目,这需要花费更多时间和内存存在Janus漏洞:恶意开发人员可以通过Janus漏洞去绕过Android的v1签名验证机制。签名方案vAndroid7.0中开始引入了APK签名方案v,一种全文件签名方案,该方案能够发现对APK的受保护部分进行所有更改,相比v1来说校验速度更快,覆盖的范围也更广。但是考虑到版本兼容的问题,所以一般常见了v1+v的混合签名模式。我们由上文知道Zip文件主体分为:源文件数据存储区、中心目录区、中心目录结束标识。EoCD中记录了中央目录的起始位置,在源文件数据存储区和中心目录区插入其他数据不会影响Zip的解压。因此v签名后会在源文件数据存储区和中心目录区插入APK签名分块(APKSigningBlock)。如下图所示。从左到右边,我们定义为区块1~。v签名块(APKSigningBlock)本身又主要分成三部分:

SignerData(签名者数据):主要包括签名者的证书,整个APK完整性校验hash,以及一些必要信息。

Signature(签名):开发者对SignerData部分数据的签名数据。

PublicKey(公钥):用于验签的公钥数据。

签名流程:相比v1签名方案,v签名方案不再以文件为单位计算摘要,而是以1MB为单位将文件拆分为多个连续的快(chunk),每个分区的最后一个快可能会小于1MB。v签名流程如下:①对区块1、、,按照1MB大小分割为多个块(chunk)

②计算每个块的摘要

③计算()中所有摘要的签名

④添加X.09开发者数字证书(公钥)

验证流程:因为v签名机制是在Android7.0上版本才支持,因此对于Android7.0以及以上版本,在安装过程中,如果v签名块,则必须走v签名机制,不能绕过。否则降级走v1签名机制。v1和v签名机制是可以同时存在的,其中对于v1和v版本同时存在的时候,v1版本的META_INF的.SF文件属性当中有一个X-Android-APK-Signed属性:

X-Android-APK-Signed:v签名本身的验证过程:

①利用PublicKey解密Signature,得到SignerData的hash明文。

②计算SignerData的hash值。

③两个值进行比较,如果相同则认为APK没有被修改过,解析出SignerData中的证书。否则安装失败。

④如果是第一次安装,直接将证书保存在应用信息中。

⑤如果是更新安装,即设备中原来存在这个应用,验证之前的证书是否与本次解析的证书相同。若相同,则安装成功,否则失败。

签名方案vAndroid9.0中引入了新的签名方式v,v签名在v的基础上,仍然采用检查整个压缩包的校验方式。不同的是在签名部分增可以添加新的证书(Attr块)。在这个新块中,会记录我们之前的签名信息以及新的签名信息,支持密钥轮换,即以密钥转轮的方案,来做签名的替换和升级。这意味着,只要旧签名证书在手,应用能够在APK更新过程中更改其签名密钥。v签名新增的新块(attr)存储了所有的签名信息,由更小的Level块,以链表的形式存储。签名流程:v版本签名块也分成同样的三部分,与v不同的是在SignerData部分,v新增了attr块,其中是由更小的level块组成。每个level块中可以存储一个证书信息。前一个level块证书验证下一个level证书,以此类推。最后一个level块的证书,要符合SignerData中本身的证书,即用来签名整个APK的公钥所属于的证书。从v到v的过渡:签名校验:Android的签名方案的升级都需要确保向下兼容。因此,在引入v方案后会根据APK签名方案,v-v-v1依次尝试验证APK。而较旧的平台会忽略v签名并尝试v签名,最后才去验证v1签名。如下图所示:注意:对于覆盖安装的情况,签名校验只支持升级而不支持降级。即一个使用V1签名的Apk,可以使用V签名的Apk进行覆盖安装,反之则不允许。v签名自身的校验:

①利用PublicKey解密Signature,得到SignerData的hash明文。

②计算SignerData的hash值。

③两个值进行比较,如果相同则认为APK没有被修改过,解析出SignerData中的证书。否则安装失败。

④逐个解析出level块证书并验证,并保存为这个应用的历史证书。

⑤如果是第一次安装,直接将证书与历史证书一并保存在应用信息中。

⑥如果是更新安装,验证之前的证书与历史证书,是否与本次解析的证书或者历史证书中存在相同的证书,其中任意一个证书符合即可安装。

三种签名的比较和校验时机v、v的比较如下图所示:v1签名方案:基于Jar的签名方案,但存在的问题:完整性覆盖范围不足验证性能差。v签名方案:通过条目内容区、中央目录区之间插入APK签名分块(APKSigningBlock)对v1签名进行了优化。v签名方案:支持密钥轮换,新增的新块(attr)存储了所有的签名信息,对v签名进行了优化。验证签名的时机主要要了解Android安装应用的方式:

系统应用安装:开机时完成,没有安装界面。

网络下载的应用安装:通过市场应用完成,没有安装界面。

ADB工具安装:没有安装界面。

第三方应用安装:通过packageinstall.apk应用安装,有安装界面。

但是其实无论通过哪种方式安装都要通过PackageManagerService来完成安装的主要工作,最终在PMS中会去验证签名信息,如v验证方式一样。.Android动态加载Android动态加载总会涉及到插件化、热部署、热修复等,这里我在网上查阅资料后,给大家总结了下动态加载的场景使用和分类:动态加载,就是程序运行时,可以加载外部的可执行文件并运行,这样使得我们可以不用安装apk就可以更新应用,针对一些SDK项目,可以加快app新版本的覆盖率、快速修复线上bug。这里运行时是指应用冷启动并开始工作后,外部可以是SD卡,可以是data目录,也可以是jniLib目录,这些可执行文件是没有随着应用一起编译的。动态加载的特点:

①app在运行的时候,可以通过加载一些本身不存在的文件,来实现一定功能,这种经常应用在app更新的过程中。

②可执行文件是可以替换的,更换静态资源不属于动态加载。

③动态加载的核心思想就是动态调用外部的dex文件,AndroidApk自带的dex是程序入口,所有功能可以直接从服务器中下载dex来完成。

Android动态加载按照工作机制不同,可以分为虚拟机层动态加载和Native层动态加载两大类。这里由于本文主要讲解动态加载方面漏洞,所以对热更新、热修复等原理就不深究了,大家感兴趣可以下去查阅相关资料,动态加载原理详细可以参考我上一篇帖子:Android加壳脱壳学习(1)——动态加载和类加载机制详解(
1
查看完整版本: AndroidAPP漏洞之战插件化漏洞