【Android签名机制详解】二:Android V1、V2、V3、V4签名方案

前言

书接上回【Android签名机制详解】一:密码学入门,在了解了消息摘要、非对称加密、数字签名、数字证书的基本概念后,我们趁热打铁、直奔主题,讲解签名在Android中的实际应用。

基础知识

Android的数字证书(.der 或 .pem )是存放在密钥库文件(.jks 或 .keystore)当中的,而数字证书作用就是保管公钥。除此之外,密钥库中还存有私钥。
Android的数字证书和传统数字证书有很大的不同,它是根证书,也就是自认证的证书,颁发者和使用人是同一个,也就是说我们自己即是CA机构,又是证书使用者。所以,Android系统在安装APK的过程中并不会校验证书的合法性,只是从中提取公钥和算法。Google这样做的目的是为了降低开发成本,吸引更多的人来开发Android应用,巩固Android生态圈。毕竟正儿八经的证书申请是要花钱的。
但是,这也就会导致一个很严重的问题,就是Android证书没有权威性,任何人都可以制作。攻击者可以篡改APK里的内容,替换掉原来的签名和证书,重新生成一份自己的签名和证书(所谓的重签名),再二次发行,谋取利益。那怎么办呢?
其实应用安全是每个Android开发者都应该关心的。大公司会有专门的部门对APP的进行安全加固,小公司或个人也可以购买第三方的加固服务。
我们也可以在APK里面添加校验签名的逻辑,一旦校验失败就停止运行,像支付宝就有这种防止重签名的机制,但道高一尺魔高一丈,Android加固Android逆向了解一下。
在这里插入图片描述
言归正传,我们继续讲解Android的签名方案。
目前 Android 支持以下四种应用签名方案:

  1. v1签名:基于 JAR 签名。
  2. v2签名:Android 7.0 引入,改动大。
  3. v3签名:Android 9.0 引入,基于 v2 的优化。
  4. v4签名:Android 11.0 引入,用来支持 ADB 增量 APK 安装。

V1签名方式也称作Jar签名,顾名思义,Jar 包也是用这种方式进行签名检验的。 V1签名并不是Android独有的签名方式。直到Android 7.0开始才推出V2签名,这个就是Android独创的签名方案,与V1签名方式截然不同,完全颠覆以前签名方案。后面Android 9.0又推出了V3签名,再到Android 11推出了V4签名方案,都是在V2的签名架构进行优化升级。所以我们可以把V2、v3、v3划分为一类,称为V2+方案。

V1签名方案

我们对含有V1签名的APK进行解压,部分压缩软件支持直接解压,有些需要修改APK后缀为.zip进行解压。解压后有一个MATE-INF目录,进入后会看到三个文件,分别是 MANIFEST.MF、*.SF 和 *.RSA 。因为*.SF 和*.RSA 具体的文件名是由签名时上下文环境(参数)决定的,所以这边用通配符*代替。

文件分析

MANIFEST.MF文件

我们先看MANIFEST.MF文件,这里简称MF文件。

Manifest-Version: 1.0
Created-By: 1.8.0_92 (Oracle Corporation)

Name: res/drawable-hdpi-v4/abc_list_longpressed_holo.9.png
SHA1-Digest: KQunCQh0E4bP0utgN0cHdQr9OwA=

Name: res/drawable-xxhdpi-v4/abc_ic_star_half_black_16dp.png
SHA1-Digest: EikVyBT5I7pmbJO2k8qF0V5hUc0=

......

这里面保存了除META-INF目录外的所有文件对应的摘要信息。在签名过程中, jarsigner(签名工具)首先会遍历APK中所有文件, 采用SHA1(JDK7.0之后采用SHA256)算法计算每个文件的16进制的消息摘要,再用 base64 进行编码,将值写入MF文件的一块中。该块有一个“Name”属性,其值就是该文件在APK包中的路径。我们将Name和其对应的摘要称为一个Entry。

*.SF文件

SF文件的主要作用是对MF做校验,防止MF的数据被篡改。

Signature-Version: 1.0
SHA1-Digest-Manifest: odZIAbrTVCfKGy6HEd5+gdBHw0I= //整个MF文件的消息摘要
Created-By: 1.8.0_92 (Oracle Corporation)

Name: res/drawable-hdpi-v4/abc_list_longpressed_holo.9.png
SHA1-Digest: xcQ0bHWRc+R9tuxQ3wgY1a2eY0k=

Name: res/drawable-xxhdpi-v4/abc_ic_star_half_black_16dp.png
SHA1-Digest: pj+V2r2pJOgJwGGNpeqxnykl0Nc=

......

这里保存了MF整个文件的消息摘要+MF中每个Entry的二次消息摘要。在签名过程中, jarsigner首先计算MF文件的整体SHA1值,再经过base64 编码后,记录在CERT.SF主属性块(在文件头上)的“SHA1-Digest-Manifest”属性值中;
再逐条计算MF文件中每一个Entry的SHA1,并经过BASE64编码后,记录在CERT.SF中每个Entry中。

*.RSA文件

首先计算CERT.SF文件消息摘要,用私钥计算出签名,然后将签名以及包含公钥信息的数字证书一同写入 CERT.RSA 中,以二进制形式保存。在这里插入图片描述

验签

  • 校验SF文件的签名:计算*.SF文件的摘要,然后用*.RSA文件中公钥解密*.RSA中签名得到的摘要,如果两者一致则进入下一步;
  • 校验MANIFEST.MF文件的完整性:计算MANIFEST.MF文件的摘要,与*.SF主属性中的摘要进行对比,如一致则逐一校验MANIFEST.MF文件各个条目的完整性;
  • 校验APK中每个文件的完整性:逐一计算APK中每个文件(META-INF目录除外)的摘要,与MANIFEST.M中的记录进行对比,如全部一致,刚校验通过;
  • 校验签名的一致性:如果是升级安装,还需校验证书签名是否与已安装APP一致,如果应用中存在相同包名但签名不一样的APP,则安装失败;

存在的问题

  • 签名和验签速度慢:因为要对APK做每个文件进行签名和验签的过程,导致构建和安装时间变长。
  • 完整性保障不够:META-INF目录用来存放签名,自然不计入签名校验过程的。所以可以随意在这个目录中添加文件,比如早期的一些批量打包方案就选择在这个目录里做文章,在这里标记文件,来标识每一个APK所属于的渠道;
    为了解决这两个问题,Google在Android 7.0推出了V2签名方案。

V2签名方案

V2签名完全颠覆了V1签名的过程,是一款全新的签名方案。我们知道,APK实际上是一个ZIP格式的压缩包,而ZIP结构如下图所示。

ZIP文件结构

在这里插入图片描述
ZIP 文件结构分为三大部分:

  • 数据区:存放真正数据的地方。
  • 中央目录区:存放关于数据区的元数据的地方。
  • 中央目录结尾区:存放关于中央目录区的元数据的地方。

这边咱们只是简单了解关于ZIP文件结构,更加详细内容,可以参考这篇文章:[Zip文件格式详解]

而V2签名过程,就是在对这数据区、中央目录区和中央目录结尾区,这3块块区域进行切分,切分成一个个大小为1M的小块,然后并行计算每个小块的消息摘要,将所有小块的消息摘要拼接在一起,整体计算消息摘要并用私钥进行签名,最后将签名、公钥、证书、算法、签名者信息等相关内容作为一个新的区域,插入到ZIP结构中,该区域位于“中央目录区”部分之前并紧邻该区域。而新插入的区域我们称之为 APK 签名分块(APK Signing Block)。如下图所示。
在这里插入图片描述

APK签名分块解析

在这里插入图片描述
APK签名分块由四部分组成,分别是size of blockID-VALUE序列size of blockmagic。其中两个size of block相同,记录着ID-VALUE序列的长度,ID-VALUE序列可以理解是一个键值对序列。而magic里面记录着一个固定值0x7109871a,该值为ID-VALUE序列的Key值,而其对应的Value值存储一份或者多份APK签名信息,我们称每份签名信息为“ APK 签名方案 v2 分块”。而ID-VALUE序列的其他键值对,目前暂未使用。

APK 签名方案 v2 分块

APK 签名方案 v2 分块也不止一个,多个签名者可以对同一个APK进行签名。每个签名信息都会形成一个APK 签名方案 v2 分块。而APK 签名方案 v2 分块的内部结构又可以细分,由三部分组成。

  1. 带长度前缀的signed data:使用多种算法对APK进行消息摘要,将摘要值、证书信息,以及额外信息记录在此处。
  2. 带长度前缀的signatures序列:使用多种算法对signed data进行签名,签名算法和结果记录在这里,形成一个signatures序列。
  3. 证书公钥:存放该签名者的公钥。
    在这里插入图片描述

计算APK摘要

在这里插入图片描述
这个张图咱们从下往上看,V2计算APK摘要时,首先将ZIP中数据区、中央目录区和中央目录结尾区这3块区域拆分成一个个大小为 1MB的小块。每个区域的最后一个小块可能会小于1M。然后并行计算每个分块的消息摘要,将所有小块的消息摘要拼接在一起,整体计算消息摘要。那么最终值就是整个APK的消息摘要。

验签过程

V2验证过程着实有点复杂,我们直接引用官方文档中的流程描述

待我有空再用白话翻译一边。这里不得不吐槽一下。部分官方文档写太TM晦涩难懂了,缺乏承上启下的过渡,突然蹦跶出来一堆专有名词,又缺乏通俗易懂的解释,跟看个文言文一样。不过,我有个学习技巧,就是先看前辈们咀嚼后吐露出来的由浅入深的文章,吸收理解七七八八,再去观摩官方文档的磅礴大气。官方文档还是要肯的,毕竟内容都是最新最专业的。

  • 找到APK 签名分块并验证以下内容:
    a. APK 签名分块的两个大小字段包含相同的值。
    b. ZIP 中央目录结尾紧跟在ZIP 中央目录记录后面。
    c. ZIP 中央目录结尾之后没有任何数据。
  • 找到APK 签名分块中的第一个APK 签名方案 v2 分块。如果 v2 分块存在,则继续执行第 3 步。否则,回退至使用 v1 方案验证 APK。
  • 对APK 签名方案 v2 分块中的每个 signer 执行以下操作:
    a. 从 signatures 中选择安全系数最高的受支持 signature algorithm ID。安全系数排序取决于各个实现/平台版本。
    b. 使用 public key 并对照signed data 验证 signatures 中对应的 signature。(现在可以安全地解析 signed data 了。)
    c. 验证 digests 和 signatures 中的签名算法 ID 列表(有序列表)是否相同。(这是为了防止删除/添加签名。)
    d. 使用签名算法所用的同一种摘要算法计算 APK 内容的摘要。
    e. 验证计算出的摘要是否与 digests 中对应的 digest 相同。
    f. 验证 certificates 中第一个 certificate 的 SubjectPublicKeyInfo 是否与 public key 相同。
  • 如果找到了至少一个 signer,并且对于每个找到的 signer,第 3 步都取得了成功,APK 验证将会成功。
    在这里插入图片描述

注意事项

  • V2签名是在Android 7.0中引入的。为了使 APK 可在 Android 6.0及更低版本的设备上安装,应先对APK进行V1签名,然后再进行V2签名。
  • 在Android 7.0及更高版本中,可以根据 APK 签名方案 v2+ 或 JAR 签名(v1 方案)验证 APK。更低版本的平台会忽略 v2 签名,仅验证 v1 签名。
    在这里插入图片描述

V3签名方案

V3 签名方案是Android 9.0时引入的签名解决方案,在V2的基础上进行了小的优化升级,其中最大的特色“支持密钥轮替”。
在以前,如果准备安装的APK与手机里已经安装的APK包名相同,但签名不一样,是无法安装的,会提示“已安装了存在签名冲突的同名数据包”,然后安装失败”。但如果使用V3签名方案,就能安装成功。
具体实现细节和限制,详见官方文档。下面贴一张签名校验的流程图。
在这里插入图片描述

V4签名方案

V4签名方案是Android 11.0引入,其目的是为了支持ADB增量APK安装

传统的应用安装方案中,用户需要等待整个APK下载完毕后才能启动安装。而增量安装技术是一种流式的安装方案:一旦APK的核心文件传输完成便可启动应用,但只能使用应用的基本功能,应用的后续功能会在后台流式传输。
在Android 11中,Google在内核中实现了增量文件系统用于对增量安装的支持。这使得 Android OS可以通过ADB流式传输APK。同时,Android 11为了适应增量安装,添加了新的v4签名方案。

具体实现细节和限制,详见官方文档。下面贴一张签名校验的流程图。
在这里插入图片描述

实际应用

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android Binder机制Android系统中一种进程间通信(IPC)的机制,用于在不同进程之间进行数据交换和通信。通过Binder机制Android应用程序可以实现进程间的数据共享和相互调用。 Binder机制基于C/S架构,主要由服务端、客户端和Binder驱动组成。服务端提供一个或多个服务,将其注册到Binder驱动中,并通过Binder对象发送和接收数据;客户端通过获取服务端的Binder对象,与其进行通信和交互;而Binder驱动负责管理Binder对象的创建、销毁和通信。 在Binder机制中,Binder对象充当了交互的桥梁。每个Binder对象都有一个唯一的标识符(具体是一个32位的整数),用于识别和查找对应的服务端。通过Binder对象,客户端和服务端可以进行方法调用、数据传输等操作。服务端通过Binder对象将数据发送给客户端,客户端通过Binder对象将数据传递给服务端。 Binder机制设计了多种数据结构来实现进程间通信,如BpBinder、BpRefBase、Parcel等。BpBinder负责处理进程间的通信,并通过Binder Proxy将方法调用转发给服务端;BpRefBase用于引用计数,确保对象在不再使用时能够正确释放;Parcel用于在进程间传递数据,可以实现序列化和反序列化。 总结来说,Android Binder机制Android系统中一种进程间通信的机制,通过Binder对象实现不同进程之间的数据交换和通信。通过服务端、客户端和Binder驱动的协作,应用程序可以实现进程间的数据共享和相互调用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值