APK签名机制之——JAR签名机制详解

转载请注明出处:https://blog.csdn.net/zwjemperor/article/details/80877305
github:https://github.com/rushgit/zhongwenjun.github.com

APK签名机制原理详解中我们已经了解了APK签名和校验的基本过程,这一篇我们来分析JAR签名机制。JAR签名对对jar包进行签名的一种机制,由于jar包apk本质上都是zip包,所以可以应用到对apk的签名。本文从JAR签名结构、签名过程,再到签名校验的源码分析,全方面来分析Android中JAR签名及校验的机制。

1. 签名过程

meta_inf

通过解压工具打开apk文件,会发现有一个META-INF目录,该目录中有3个文件,这3个文件是签名以后生成的,显然与签名相关,我们依次看这几个文件中的内容。

1.1 文件内容解析

1.1.1 先看MANIFEST.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=

......

这个文件列出了apk中所有的文件,以及它们的摘要,摘要字符串是通过base64编码的,通过计算来验证下:

先计算出res/drawable-hdpi-v4/abc_list_longpressed_holo.9.png的sha1值。
这里写图片描述
计算出的sha1值是经过16进行编码的,再把它转成base64编码,可以通过在线工具进行转换:tomeko.net
这里写图片描述
可以看到转换过后的base64值和MANIFEST.MF文件中内容是一样的。

1.1. 2 再看CERT.SF

Signature-Version: 1.0
SHA1-Digest-Manifest: odZIAbrTVCfKGy6HEd5+gdBHw0I=
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=

......

SF文件的内容和MF比较相似,同样包含了apk所有文件的摘要,不同的是:

  1. SF文件在主属性中记录了整个MF文件的摘要(SHA1-Digest-Manifest)
  2. SF文件其余部分记录的是MF相应条目的摘要,也就说对MF文件相应条目再次进行了摘要计算。

我们再来验证下,首先计算出MANIFEST.MF文件的sha1值,再转换base64编码:
这里写图片描述
这里写图片描述
再来验证res/drawable-hdpi-v4/abc_list_longpressed_holo.9.png

这里要注意下,.MF文件是以空行分隔的。计算.MF各条目摘要时需要再加一个换行符,因为空行还有一个换行符(具体可参考apksigner源码)。我们把abc_list_longpressed_holo.9.png条目保存到一个新文件中,先计算这个条目的sha1值:
这里写图片描述
再把sha1值转为base64编码:
这里写图片描述

1.1.3 再看CERT.RSA

cert.rsa中的是二进行内容,里面保存了签名者的证书信息,以及对cert.sf文件的签名。具体证书包含的内容已经在APK签名机制原理详解中作了说明,这里不再重复介绍。

1.2 整体签名过程

具体签名过程如下:
这里写图片描述
具体过程可参考apksigner源码

public static void main(String[] args) {
    ......
    //生成MANIFEST.MF文件,遍历apk的所有文件,计算除META-INF目录下的
    //.SF/.RSA/.DSA文件外所有文件的摘要。
    JarEntry je;
    Manifest manifest = addDigestsToManifest(inputJar);
    // MANIFEST.MF
    je = new JarEntry(JarFile.MANIFEST_NAME);
    je.setTime(timestamp);
    outputJar.putNextEntry(je);
    manifest.write(outputJar);

    // 生成CERT.SF文件
    je = new JarEntry(CERT_SF_NAME);
    je.setTime(timestamp);
    outputJar.putNextEntry(je);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    //计算MF文件摘要,及MF相应条目的摘要
    writeSignatureFile(manifest, baos);
    //计算SF文件的摘要
    byte[] signedData = baos.toByteArray();
    outputJar.write(signedData);

    // 生成CERT.RSA
    // 对SF文件的摘要(signedData)进行签名,将证书信息一同写入RSA文件中
    je = new JarEntry(CERT_RSA_NAME);
    je.setTime(timestamp);
    outputJar.putNextEntry(je);
    writeSignatureBlock(new CMSProcessableByteArray(signedData),
    publicKey, privateKey, outputJar);
    outputJar.close();
    ......
}

2. 校验过程

上面说的是签名过程,接下来看apk安装过程是怎样进行签名校验的。校验过程和签名过程刚好相反:

  1. 首先校验cert.sf文件的签名

    计算cert.sf文件的摘要,与通过签名者公钥解密签名得到的摘要进行对比,如果一致则进入下一步;

  2. 校验manifest.mf文件的完整性

    计算manifest.mf文件的摘要,与cert.sf主属性中记录的摘要进行对比,如一致则逐一校验mf文件各个条目的完整性;

  3. 校验apk中每个文件的完整性

    逐一计算apk中每个文件(META-INF目录除外)的摘要,与mf中的记录进行对比,如全部一致,刚校验通过;

  4. 校验签名的一致性

    如果是升级安装,还需校验证书签名是否与已安装app一致。

以上步骤需要全部通过才算签名校验通过,任何一步失败都将导致校验失败。这个过程能保证apk不可被篡改吗?我们来看看篡改apk内容会发生什么:

  • 篡改apk内容

    校验apk中每个文件的完整性时失败;如果是添加新文件,因为此文件的hash值在.mf和.sf中无记录,同样校验失败;

  • 篡改apk内容,同时篡改manifest.mf文件相应的摘要

    校验manifest.mf文件的摘要会失败;

  • 篡改apk内容,同时篡改manifest.mf文件相应的摘要,以及cert.sf文件的内容

    校验cert.sf文件的签名会失败;

  • 把apk内容和签名信息一同全部篡改

    这相当于对apk进行了重新签名,在此apk没有安装到系统中的情况下,是可以正常安装的,这相当于是一个新的app;但如果进行覆盖安装,则证书不一证,安装失败。

从这里可以看出只要篡改了apk中的任何内容,都会使得签名校验失败。

3. 签名校验代码分析

前面介绍了签名和校验的整体流程,现在来看校验过程的代码实现。安装apk的入口在

  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值