V2签名分析
简单过一下V1签名多渠道方案
V1签名原理
v1 签名方案重要的原理就是对 apk 中所有的文件计算摘要 保存到 MANIFEST.MF 文件中;然后计算 MANIFEST.MF 中每个条目的摘要以及 MANIFEST.MF 本身的摘要,保存到 CERT.SF 文件中;最后用私钥对 CERT.SF 文件加密,然后保存到 CERT.RSA 文件中(这个文件还包含了签名算法、公钥信息)
(1) .MF文件
apk当中的原始文件信息用摘要算法如SHA1计算得到的摘要信息并用base64编码保存,以及对应采用的摘要算法如SHA1(这个算法的特性是不管多大的文件内容都能够得到长度相同的摘要信息但是不同的文件内容信息得到的摘要信息肯定不同)
(2) .SF文件
.MF文件的摘要信息以及.MF文件当中每个条目在用摘要算法计算得到的摘要信息并用base64编码保存
(3) .RSA文件
存放证书信息,公钥信息,以及用私钥对.SF文件的加密数据即签名信息,这段数据是无法伪造的,除非有私钥,另外.RSA文件还记录了所用的签名算法等信息。
Apk包在安装的时候,是按照从(3)到(1)的顺序依次校验的,先用公钥还原签名信息,然后和.SF文件中的信息比对,然后用同样的摘要算法对.MF文件里面的每一个条目计算对应的摘要信息,然后比对.MF文件是否一致
V1多渠道方案(1)
向META-INF目录中创建文件写入渠道信息,因为在v1签名验证时候,并不会验证META-INF的除了.MF文件的其它文件
V1多渠道方案(2)
在APK的任意位置填写空文件夹(注意是空文件夹),在apk签名过程中,只会对apk中的所有文件进行摘要+签名的,不会对文件夹进行这样的操作(文件夹无法计算摘要),所以也不会验证这个文件夹
V1多渠道方案(3)
这个就要了解下APK结构(其实就是ZIP的结构)了,看下面的图
从图中我们能看出,有一个End of Central Directory的数据块,这块是什么呢?其实这块就是结尾信息,里面记录了部分信息,简称EOCD
我们主要看最后有一个注释长度的标识,那我们是不是可以通过这个加入渠道呢?当然可以,这个只是zip文件的一个注释字段,所以并不影响ZIP里面的文件,所以更不会影响APK的签名,Apk安装的前提是要把Zip解压,在进行验签名等过程,所以想要多渠道修改APK第一点就是保证Zip结构的正确,第二点才是不违背签名
只需要在Zip结尾处增加一个注释即可
逻辑代码:
/**
* 读取渠道信息
* @throws IOException
*/
private static void readCannel() throws IOException {
File in = new File("/Users/wenyingzhi/Desktop/Study/apksign/app-out.apk");
RandomAccessFile inR = new RandomAccessFile(in, "r");
// 读取渠道长度(读取后4个字节)
inR.seek(inR.length() - 4);
ByteBuffer commentLengthBytes = ByteBuffer.allocate(4);
commentLengthBytes.order(ByteOrder.LITTLE_ENDIAN);
inR.readFully(commentLengthBytes.array(), commentLengthBytes.arrayOffset(), commentLengthBytes.capacity());
// 得到注释长度了
int commentLength = commentLengthBytes.getInt();
System.out.println("当前注释长度:" + commentLength);
// 移动文件指针,读取备注 文件长度 - 存储注释长度的int(占4位) -注释长度
inR.seek(inR.length() - 4 - commentLength);
// 读取注释内容
ByteBuffer commentBytes = ByteBuffer.allocate(commentLength);
commentBytes.order(ByteOrder.LITTLE_ENDIAN);
inR.readFully(commentBytes.array(), commentBytes.arrayOffset(), commentBytes.capacity());
S