用apksigner进行批量签名的脚本

用apksigner进行批量签名的脚本

https://blog.csdn.net/lxlmycsdnfree/article/details/80801719?utm_term=apksigner%E9%AA%8C%E8%AF%81%E7%AD%BE%E5%90%8D&utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~sobaiduweb~default-0-80801719&spm=3001.4430

对APK进行签名,正常情况下使用Gradle进行签名或者第三方开源签名工具或插件进行签名及ADB命名,这样需要给测试或运维人员进行讲解,解释半天他们会问你有批量工具吗?那作为程序员得你,只能说有。那我给大家一个用python写的基于apksigner进行批量签名的脚本,双击就OK了。

1. V1&V2签名

在给大家放出大招之前,先卖个萌,来一起了解一下Android的签名。在Android 7.0以下版本,一直使用的是Oracle提供的V1 scheme (JAR signing)签名方案。自从9行代码引发的88亿$官司之后,Google逐渐想法摆脱对Java的依赖。于是乎也就有了V2签名,从Android 7.0开始, 谷歌增加新签名方案 V2 Scheme (APK Signature),更安全的签名方式。

为了兼容之前的签名,默认是先进行了V1签名,然后再使用V2对其进行签名。

在 Android 7.0 以后,可以根据 APK 签名方案 v2(v2 方案)或 JAR 签名(v1 方案)验证 APK。更低版本的平台会忽略 v2 签名,仅验证 v1 签名。

 

 

1.1 V1签名

来自JDK(jarsigner), 是JDK提供的针对jar包签名的通用工具,位于JDK/bin/jarsigner.exe

对zip压缩包的每个文件进行验证, 签名后还能对压缩包修改(移动/重新压缩文件)

对V1签名的apk/jar解压,在META-INF存放签名文件(MANIFEST.MF, CERT.SF, CERT.RSA), 其中MANIFEST.MF文件保存所有文件的SHA1指纹(除了META-INF文件)

由此可知: V1签名是对压缩包中单个文件签名验证。

1.2 V2签名

来自Google(apksigner), 对zip压缩包的整个文件验证, 签名后不能修改压缩包(包括zipalign),对V2签名的apk解压,没有发现签名文件,重新压缩后V2签名就失效, 由此可知: V2签名是对整个APK签名验证。

为了保护 APK 内容,APK 包含以下 4 个部分:

  1. ZIP 条目的内容(从偏移量 0 处开始一直到“APK 签名分块”的起始位置)
  2. APK 签名分块
  3. ZIP 中央目录
  4. ZIP 中央目录结尾

 

APK 签名方案 v2 负责保护第 1、3、4 部分的完整性,以及第 2 部分包含的“APK 签名方案 v2 分块”中的 signed data 分块的完整性。

第 1、3 和 4 部分的完整性通过其内容的一个或多个摘要来保护,这些摘要存储在 signed data 分块中,而这些分块则通过一个或多个签名来保护。

第 1、3 和 4 部分的摘要采用以下计算方式,类似于两级 Merkle 树。 每个部分都会被拆分成多个大小为 1 MB(220 个字节)的连续块。每个部分的最后一个块可能会短一些。每个块的摘要均通过字节 0xa5 的连接、块的长度(采用小端字节序的 uint32 值,以字节数计)和块的内容进行计算。顶级摘要通过字节 0x5a 的连接、块数(采用小端字节序的 uint32 值)以及块的摘要的连接(按照块在 APK 中显示的顺序)进行计算。摘要以分块方式计算,以便通过并行处理来加快计算速度。

 

由于第 4 部分(ZIP 中央目录结尾)包含“ZIP 中央目录”的偏移量,因此该部分的保护比较复杂。当“APK 签名分块”的大小发生变化(例如,添加了新签名)时,偏移量也会随之改变。因此,在通过“ZIP 中央目录结尾”计算摘要时,必须将包含“ZIP 中央目录”偏移量的字段视为包含“APK 签名分块”的偏移量。

V2签名优点很明显:

1). 签名更安全(不能修改压缩包)

2). 签名验证时间更短(不需要解压验证),因而安装速度加快

2. apksigner

在 Android 7.0 Nougat 中引入了全新的 APK Signature Scheme v2签名方式。如果要对已经打包好的apk进行v2签名,这时我们就必须借助 Android SDK提供的apksigner工具。

这个工具位于SDK目录的build-tools目录下。必须说明的是,v2签名方式时在Android7.0后才推出的,所以只有 版本>25的SDK\build-tools\中才能找到apksigner.jar。

 

上面lib目录里面有apksigner.jar,这里路径最好配置到环境变量里。

apksigner对apk签名的各个参数

apksigner sign                 //执行签名操作
--ks 你的jks路径               //jks签名证书路径
--ks-key-alias 你的alias          //生成jks时指定的alias
--ks-pass pass:你的密码           //KeyStore密码
--key-pass pass:你的密码          //签署者的密码,即生成jks时指定alias对应的密码
--out output.apk               //输出路径
input.apk                   //需要签名的APK

apksigner sign –ks aoaoyi.jks –ks-key-alias aoaoyi –ks-pass pass:aoaoyi.com –key-pass pass:aoaoyi.com –out output.apk input.apk签名示例:

apksigner检查apk是否已经签名:

apksigner verify -v --print-certs xxx.apk
参数:
 -v, --verbose 显示详情(显示是否使用V1和V2签名)
--print-certs 显示签名证书信息
 
例如:
apksigner verify -v aoaoyi.apk
 
Verifies
Verified using v1 scheme (JAR signing): true
Verified using v2 scheme (APK Signature Scheme v2): true
Number of signers: 1

3. 批量签名

有上面大家已经对Android签名有了大致了解,由于V1逐渐被遗忘,我也没有细说,如果想知道V1签名的使用方法请看 apk反编译及重新打包,里面有介绍。

接下来真是切入主题->使用Python、apksigner实现对APK进行批量签名。

3.1 我们先来看MultiSigner.py代码

 

#!/usr/bin/python
#coding:UTF-8
import shutil
import os
"""
1.安装Python27,配置环境变量。
2.配置apksinger的环境变量。
3.把xxx.jks、xxx.apk(支持多个)放入和MultiSigner.py同目录下。
4.双击MultiSigner.py,出现命令行窗体,等待。
5.按任意键结束。
6.查看output目录下已签好的apk文件。
"""
#jks签名证书(放在当前目录中)
jksFile = 'aoaoyi.jks'
#KeyStore密码
storePassword = 'aoaoyi.com'
#生成jks时指定的alias
keyAlias = 'aoaoyi'
#签署者的密码,即生成jks时指定alias对应的密码
keyPassword = 'aoaoyi.com@gmail'
 
# 获取当前目录中所有的apk源包
src_apks = []
# python3 : os.listdir()即可,这里使用兼容Python2的os.listdir('.')
for file in os.listdir('.'):
    if os.path.isfile(file):
        extension = os.path.splitext(file)[1][1:]
        if extension in 'apk':
            src_apks.append(file)
try:
	for src_apk in src_apks:
		# file name (with extension)
		src_apk_file_name = os.path.basename(src_apk)
		# 分割文件名与后缀
		temp_list = os.path.splitext(src_apk_file_name)
		# name without extension
		src_apk_name = temp_list[0]
		# 后缀名,包含.   例如: ".apk "
		src_apk_extension = temp_list[1]
		# 创建生成目录
		output_dir = 'output/'
		# 目录不存在则创建
		if not os.path.exists(output_dir):
			os.mkdir(output_dir)
		#目标文件路径
		target_apk = output_dir + src_apk_name + src_apk_extension
		#签名后的文件路径
		signer_apk = output_dir + src_apk_name + '_signer' + src_apk_extension
		#拼装签名命令
		signer_str = 'cmd.exe /k apksigner sign --ks ' + jksFile + ' --ks-pass pass:' + storePassword + ' --ks-key-alias ' + keyAlias + ' --key-pass pass:' + keyPassword + ' --out ' + signer_apk + ' ' + src_apk
		#执行签名命令
		signer_result = os.popen(signer_str)
		#输出签名命令执行结果
		if(signer_result.read() != ''):
			print 'signer_result:\t', 'success'
		else:
			print 'signer_result:\t', 'fail'
		#拼装验证签名命令
		verify_str = 'apksigner verify -v --print-certs ' + signer_apk
		#执行对签过的apk进行签名验证
		verify_result = os.popen(verify_str)
		#输出验证签名命令执行结果
		print 'verify_result:\t', verify_result.read()
		#os.remove(target_apk)
except Exception, e:
	print 'Exception:\t', repr(e)
print '请输入任意键退出'.decode('UTF-8').encode('GBK')
#等待输入
raw_input()

3.2. 目录文件

 

3.2. 运行后,命令展示信息

 

你把这个脚本甩给测试或运维,你就再也不受他们打扰了。如果考虑到安全的话,你在代码服务器上构建个GO界面直接调用这个脚本,把生成的apk包生成一个下载地址供下载就可以了。这样就节约了自己很多时间。

 

参考:

https://source.android.com/security/apksigning/v2#v1-verification

https://developer.android.com/studio/command-line/apksigner

ADB的常用命令

apk反编译及重新打包

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值