Android签名机制
1.Android签名作用和原理
2.多渠道打包原理
3.APK Signature Scheme v2介绍
签名的作用和原理
签名的作用
Android App在开发时都有一个唯一的标识,我们把它叫做包名,包名就像身份证号一样,是和每一个人一一对应的,在把App安装时机器也是通过包名来识别应用的,一个机器中不能存在两个包名一样的应用,这就是App在机器中的唯一性。我们在给App升级的时候,比如覆盖安装,就是通过包名来进行识别和对应的覆盖,这样才能保证App可以顺利升级而不会覆盖了其他的App,同样,别的App包名不同也无法覆盖我们的App。虽然Android提供了一套包名识别机制,但仅有包名就可以了吗?试想一下,如果别人用我们的包名新建一个App想要覆盖我们的App亦或是不法分子破解我们的App往里面添加一些自己的内容,比如内嵌广告来牟利,把篡改过的App再发出去让用户覆盖安装,我们可能会受到巨大的损失。当然这种事情是不会发生的
,Google为每一个App增加了一个签名机制,App正是通过这种机制保证了自身的唯一性和安全性。那么,签名是如何做到这些的呢?
签名的原理
对Apk签名有好几种工具,但原理都是大同小异的。在使用签名工具之前我们必须准备好签名要用的私钥和公钥,然后再用签名工具对apk签名,之后签名流程会在apk里新建META-INF文件夹并在里面生成三个文件,这三个文件就是签名的关键和验证的依据。
从图中可以看到三个文件分别是:MANIFEST.MF
CERT.RSA
CERT.SF
接下来说说这三个文件是怎么生成的。
1.MANIFEST.MF
先看看它的内容,可以看到是一些Name对应的SHA1的值,很容易就能知道这个文件保存的是每一个文件对应的一个唯一的值。MANIIFEST.MF文件的功能就如刚才说的一样,在对APK签名的时候,首先会对每一个文件内容做一次SHA1算法,就是计算出文件的摘要信息,然后用Base64进行编码,把这些内容都保存在一个新建的MANIFEST.MF文件中,并把这个文件放到META-INF目录下,就完成了第一个签名文件的生成。下面我们用工具来做个案例看看是不是这样。我们以AndroidManifest.xml文件为例,首先利用软件计算出SHA1值,然后再用Base64进行编码(在线计算Base64的网站),我们发现结果完全一致。
2.CERT.SF
在生成了一个MANIFEST.MF文件之后,就能记录下我们每一个文件的唯一值,从而保证文件不被篡改,这样虽然保证了MANIFEST.MF中记录文件的安全,但却无法保证自身的安全,别人照样可以修改原有文件之后生成对应的SHA1值然后再修改MANIFEST文件,所以我们还要对MANIFEST进行加固,从而保证安全性。在进行完第一个文件生成后,签名工具开始生成第二个文件了,这个文件就是CERT.SF。
先来看一下文件内容,这里的内容感觉和MANIFEST.MF的内容差不多,其实它主要做了两件事:
- 计算这个MANIFEST.MF文件的整体SHA1值,再经过BASE64编码后,记录在CERT.SF主属性块(在文件头上)的“SHA1-Digest-Manifest”属性值值下。
- 逐条计算MANIFEST.MF文件中每一个块的SHA1,并经过BASE64编码后,记录在CERT.SF中的同名块中,属性的名字是“SHA1-Digest”。
具体的相关源码大家可以参考下文提供的方式寻找。
注:1.利用新的Android Stuido(2.2以后)打包生成的CERT.SF文件中,已经不再做这样的处理了,如图所示。但是为什么依然可以兼容之前的版本呢?下文见。
3.CERT.RSA
这个文件都是二进制的,生成完CERT.SF文件之后,我们用私钥对CERT.SF进行加密计算得出签名,将得到的签名和公钥的数字证书的信息一起保存到CERT.RSA中,整个签名过程就结束了。
校验
下面再简单叙述一下Apk安装过程中的验证步骤,其实就是和生成签名文件的步骤类似:
- 使用证书文件(在META-INF目录下,以.DSA、.RSA或者.EC结尾的文件)检验签名文件(在META-INF目录下,和证书文件同名,但扩展名为.SF的文件)是否被修改过的。
- 使用签名文件CERT.SF,检验MANIFEST.MF文件中的内容是否被被篡改过。
- 查保证Apk文件中包含的所有文件,对应的摘要值是否与MANIFEST.MF文件中记录的一致(如果一个文件存在于Apk中,但是并未在MANIFEST.MF文件中列出,验证失败)。
- 校验当前安装Apk文件的签名是否和已经安装的同包名应用签名一致。
综上所述:
- 如果你改变了apk包中的任何文件,那么在apk安装校验时,改变后的文件摘要信息与MANIFEST.MF的检验信息不同,于是验证失败,程序就不能成功安装。
- 其次,如果你对更改的过的文件相应的算出新的摘要值,然后更改MANIFEST.MF文件里面对应的属性值,那么必定与CERT.SF文件中算出的摘要值不一样,照样验证失败。
- 如果你还不死心,继续计算MANIFEST.MF的摘要值,相应的更改CERT.SF里面的值,那么数字签名值必定与CERT.RSA文件中记录的不一样,还是失败。
- 那么能不能继续伪造数字签名呢?不可能,因为没有数字证书对应的私钥。
所以,从上面的分析可以得出,只要修改了Apk中的任何内容,就必须重新签名,不然会提示安装失败。如果重新签名那么必然会和已经安装在手机上的相同包名的应用的签名不一致,因此无法安装。
所以,签名的作用可以总结为签名只能保证别人在不修改应用签名的前提下篡改我们应用的资源文件,代码等,并不能保证一个未安装过正版应用的用户使用的应用一定是正版的。
注:
- 在校验的第二步中,如果MANIFEST.MF文件的摘要和CERT.SF中SHA1-Digest-Manifest保存的摘要相同,则不需要将每个条目的摘要信息和MANIFEST.MF文件中相同Name的摘要信息进行哈希值计算并编码比较。这也是为什么AS2.2之后两个文件的“SHA1-Digest”相同,但是可以通过验证的原因。(个人猜测之所以放弃计算MANIFEST.MF中每个条目的摘要并保存在CERT.SF中,可能因为AS2.2之后默认同时进行两种签名,为了兼顾效率因此放弃计算。如了解相关知识,欢迎告知,谢谢!)
- 相关签名校验源码可以参考尼古拉斯_赵四的相关博客或直接查看相关源码。
多渠道打包方式
根据以上签名方式可以发现v1签名存在的问题。
- 从来就没有对META-INF里的任何文件进行数字编码和加密,因为这个文件夹是签名时生成的。在生成第一个文件MANIFEST.MF时并没有对这个文件夹里的任何文件进行数字编码,因为这个文件夹一定是空的,第二个文件是基于第一个文件生成的,第三个文件又是基于第二个生成的,所以整个过程中,这个META-INF文件夹几乎是在控制范围之外的。我们可以在里面通过添加一些空文件从而躲过签名这个过程,同时利用这个空文件的名字标识渠道号等信息。
- 签名只针对解压后的所有文件,校验也是针对解压后的文件做校验,并未对APK压缩文件做任何的校验,因此可以通过在压缩文件最后添加注释的方式保存渠道号。Packer-ng使用的便是这种方式。我们可以将Apk文件修改为zip文件查看注释信息。
v2签名
APK签名方案v2是一个全文件签名方案,通过检测APK的受保护部分的任何更改,提高验证速度和加强完整性保证。
使用APK签名方案v2 签名会在APK中心目录部分之前的APK文件中插入一个APK签名块。在APK签名块中,v2签名和签名者身份信息存储在APK签名方案v2块中。
新的签名方式是根据zip文件结构来进行签名的,Apk文件本质上就是一个压缩文件,如图所示,在被签名前可以分为三块内容。
- 压缩文件实体数据 包含所有的元素具体数据
- 核心目录数据 包含所有元数据的相对偏移量
- 目录结束标志 包含目录数据的偏移位置和相关目录详情记录
而签名之后增加了一个APK签名块,该签名块是根据未签名的ZIP文件三个模块的所有内容进行编码签名后产生的一个唯一的数据,这三块任何内容发生改变后所产生的这块的数据都是不一致的,所以在签名之后无法对Apk的任何内容进行修改。
以下内容是利用软件翻译的官方文档,如需查看原文请移步官方文档。
APK签名块
为了保持与当前APK格式的向后兼容性,v2和新的APK签名方式存储在APK签名块中,该签名块是用于支持v2签名方案的新容器。在APK文件中,APK签名块位于ZIP中心目录之前,该目录位于文件末尾。
该块包含一个更容易在APK中定位块的方式的ID键值对。APK的v2签名存储在ID为0x7109871a的键值对中。
格式
APK签名块的格式如下(所有数字字段都是小字节序):
size of block 以字节为单位(不包括此字段)(uint64)
- uint64长度前缀的ID值对的序列:
- ID (uint32)
- value (可变长度:对的长度为4字节)
- size of block 以字节为单位 - 与第一个字段相同(uint64)
- magic “APK Sig Block 42”(16字节)
通过首先查找ZIP中心目录的开始(通过在文件末尾找到中央目录的ZIP结束记录,然后从记录中读取中心目录的起始偏移)来解析APK。该 magic值提供了一种快速方法来确定中心目录之前可能是APK签名块。size of block然后该值有效地指向文件中块的开始。
在解释块时,应忽略具有未知ID的ID值对。
v2签名块
APK由一个或多个签名者/身份签名,每个由签名密钥表示。此信息存储为APK签名计划v2块。对于每个签名者,存储以下信息:
- (签名算法,摘要,签名)元组。存储摘要以将签名验证与APK内容的完整性检查去耦合。
- X.509证书链代表签名者的身份。
- 其他属性作为键值对。
对于每个签名者,使用提供的列表中支持的签名来验证APK。忽略具有未知签名算法的签名。当遇到多个支持的签名时,由每个实现来选择使用哪个签名。这使得能够以向后兼容的方式在将来引入更强的签名方法。建议的方法是验证最强的签名。
格式
APK签名方案v2块存储在ID签名的APK签名块内 0x7109871a。
APK签名方案v2块的格式如下(所有数值都是小端字节,所有长度前缀字段使用uint32作为长度):
长度前缀序列signer:
长度前缀signed data:
长度前缀序列digests:
- signature algorithm ID (uint32)
- (长度前缀)digest- 请参阅 完整性保护的内容
X.509的长度前缀序列certificates:
- 长度前缀X.509 certificate(ASN.1 DER形式)
长度前缀序列additional attributes:
- ID (uint32)
- value (可变长度:附加属性的长度 - 4字节)
长度前缀序列signatures:
+ signature algorithm ID (uint32) + 长度前缀signature过signed data
- 长度前缀public key(SubjectPublicKeyInfo,ASN.1 DER形式)
签名算法ID
- 0x0101-RSASSA-PSS with SHA2-256 digest,SHA2-256 MGF1,32 bytes of salt,trailer:0xbc
- 0x0102-RSASSA-PSS with SHA2-512 digest,SHA2-512 MGF1,64 bytes of salt,trailer:0xbc
- 0x0103-RSASSA-PKCS1-v1_5与SHA2-256摘要。这是为了构建需要确定性签名的系统。
- 0x0104-RSASSA-PKCS1-v1_5与SHA2-512摘要。这是为了构建需要确定性签名的系统。
- 0x0201-ECDSA与SHA2-256摘要
- 0x0202-ECDSA与SHA2-512摘要
- 0x0301-DSA与SHA2-256摘要
所有上述签名算法都是由Android平台支持的。签名工具可以支持算法的子集。
完整性保护的内容
为了保护APK内容,APK由四个部分组成:
- ZIP条目的内容(从偏移0到APK签名块的开始)
- APK签名块
- ZIP中心目录
- 中央目录结束标志
图2.签名后的APK部分
APK Signature Scheme v2保护第1,3,4节以及 signed data第2节中包含的APK签名方案v2块的完整性。
部分1,3和4的完整性由存储在signed data块中的其内容的一个或多个摘要来保护,块又被一个或多个签名保护。
部分1,3和4的摘要如下计算,类似于两级Merkle树。每个部分被分割成连续的1MB(2 20字节)块。每个部分中的最后一个块可以更短。每个块的摘要是在字节0xa5,块的字节长度(little-endian uint32)和块的内容的连接上计算的。顶层摘要是根据字节0x5a,块的数量(little-endian uint32)以及块中摘要的级联来计算的,以块中的大小顺序显示在APK中。以分块方式计算摘要,以便能够通过并行化来加速计算。
图3. APK摘要
第4节(中央目录的ZIP结束)的保护因包含ZIP中心目录的偏移的部分而变得复杂。当APK签名块的大小更改时(例如,添加新签名时),该偏移量会更改。因此,当计算中央目录的ZIP结束时的摘要时,包含ZIP中心目录的偏移的字段必须被视为包含APK签名块的偏移量。
回滚保护
攻击者可能会尝试在支持验证v2签名APK的Android平台上将v2签名的APK验证为v1签名的APK。为了减轻这种攻击,v2签名的APK也是v1签名的APK必须在他们的META-INF/ .SF文件的主要部分包含一个X-Android-APK-Signed属性。属性的值是以逗号分隔的一组APK签名方案ID(此方案的ID为2)。在验证v1签名时,需要APK验证者拒绝不具有验证者偏好于此集合的APK签名方案(例如,v2方案)的签名的APK。该保护依赖于内容META-INF/ .SF文件由v1签名保护的事实。请参阅有关JAR签名APK验证的部分 。
攻击者可以尝试从APK签名方案v2块中剥离更强的签名。为了减轻这种攻击,将被签名的签名算法ID的列表存储在signed data 由每个签名保护的块中。
验证
在Android 7.0中,APK可以根据APK签名计划v2(v2计划)或JAR签名(v1计划)进行验证。较旧的平台忽略v2签名,只验证v1签名。
图4. APK签名验证过程(新步骤为红色)
APK签名计划v2验证
找到APK签名块,并验证:
- APK Signing Block的两个大小字段包含相同的值。
- ZIP中心目录后紧跟着中央目录记录的ZIP结束。
- 中央目录的ZIP End后面没有更多数据。
- 在APK签名块中找到第一个APK签名计划v2块。如果存在v2块,则继续执行步骤3.否则,回退到使用v1方案验证APK 。
对于signerAPK Signature Scheme v2 Block中的每个:
- 选择最强的支持signature algorithm ID从 signatures。强度排序取决于每个实现/平台版本。
- 验证相应的signature从 signatures反对signed data使用public key。(现在可以安全地解析signed data。)
- 验证签名算法ID在digests和signatures中的有序列表 是否相同。(这是为了防止签名剥离/添加。)
- 使用与签名算法所使用的摘要算法相同的摘要算法来计算APK内容的摘要。
- 验证所计算的摘要是等同于相应 digest从digests。
- 验证第一个certificate的 certificatesSubjectPublicKeyInfo是否相同public key。
如果signer找到至少一个并且每个找到的步骤3 成功,则验证成功signer。
注意:如果第3步或第4步中发生失败,则不得使用v1方案验证APK。
《神级君主》短片剧高清在线免费观看:https://www.jgz518.com/xingkong/14735.html
《烽火木兰山》剧情片高清在线免费观看:https://www.jgz518.com/xingkong/113696.html
《徽娘宛心》国产剧高清在线免费观看:https://www.jgz518.com/xingkong/41441.html
《一击》日本剧高清在线免费观看:https://www.jgz518.com/xingkong/141808.html
文章结构紧凑,层次分明,逻辑严密,让人一读即懂。
实验数据可增加误差分析以提高严谨性。
内容的丰富性和深度让人仿佛置身于知识的海洋,受益匪浅。