iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >给Android的APK程序签名和重新签名的方法
  • 516
分享到

给Android的APK程序签名和重新签名的方法

方法apkAndroid 2022-06-06 08:06:53 516人浏览 薄情痞子
摘要

签名工具的使用 Android源码编译出来的signapk.jar既可给apk签名,也可给rom签名的。使用格式: java –jar signapk.jar [-w] p

签名工具的使用
Android源码编译出来的signapk.jar既可给apk签名,也可给rom签名的。使用格式:


java –jar signapk.jar [-w] publickey.x509[.pem] privatekey.pk8 input.jar output.jar
-w 是指对ROM签名时需使用的参数 publickey.x509[.pem] 是公钥文件 privatekey.pk8 是指 私钥文件 input.jar 要签名的apk或者rom output.jar 签名后生成的apk或者rom

signapk.java

1) main函数
main函数会生成公钥对象和私钥对象,并调用aDDDigestsToManifest函数生成清单对象Manifest后,再调用signFile签名。


 public static void main(String[] args) {
 //...
 boolean signWholeFile = false;
 int argstart = 0;
 
 if (args[0].equals("-w")) { 
  signWholeFile = true;
  argstart = 1;
 } 
 // ...
 try {
  File publicKeyFile = new File(args[argstart+0]);
  X509Certificate publicKey = readPublicKey(publicKeyFile);
  PrivateKey privateKey = readPrivateKey(new File(args[argstart+1]));
  inputJar = new JarFile(new File(args[argstart+2]), false); 
  outputFile = new FileOutputStream(args[argstart+3]);
  
  if (signWholeFile) {
   SignApk.signWholeFile(inputJar, publicKeyFile, publicKey, 
    privateKey, outputFile);
  }
  else {
   JarOutputStream outputJar = new JarOutputStream(outputFile);
   outputJar.setLevel(9);
   
   signFile(addDigestsToManifest(inputJar), inputJar, 
   publicKeyFile, publicKey, privateKey, outputJar);
   outputJar.close();
  }
 } catch (Exception e) {
  e.printStackTrace();
  System.exit(1);
 } finally {
  //...
 }
}

2) addDigestsToManifest
首先我们得理解Manifest文件的结构,Manifest文件里用空行分割成多个段,每个段由多个属性组成,第一个段的属性集合称为主属性集合,其它段称为普通属性集合,普通属性集合一般会有Name属性,作为该属性集合所在段的名字。Android的manifeset文件会为zip的所有文件各自建立一个段,这个段的Name属性的值就是该文件的path+文件名,另外还有一个SHA1-Digest的属性,该属性的值是对文件的sha1摘要用base64编码得到的字符串
Manifest示例:


Manifest-Version: 1.0
Created-By: 1.6.0-rc (Sun Microsystems Inc.)
Name: res/drawable-hdpi/user_loGout.png
SHA1-Digest: zkQSZbt3Tqc9myEVuxc1dzMDPCs=
Name: res/drawable-hdpi/contacts_cancel_btn_pressed.png
SHA1-Digest: mSVZvKpvKpmgUJ9oXDJaTWzhdic=
Name: res/drawable/main_head_backgroud.png
SHA1-Digest: fe1yzADfDGZvr0cyIdNpGf/ySio=

Manifest-Version属性和Created-By所在的段就是主属性集合,其它属性集合就是普通属性集合,这些普通属性集合都有Name属性,作为该段的名字。
addDigestsToManifest源代码:


private static Manifest addDigestsToManifest(JarFile jar)
   throws IOException, GeneralSecurityException {
 Manifest input = jar.getManifest();
 Manifest output = new Manifest();
 Attributes main = output.getMainAttributes();
 if (input != null) {
  main.putAll(input.getMainAttributes());
 } else {
  main.putValue("Manifest-Version", "1.0");
  main.putValue("Created-By", "1.0 (Android SignApk)");
 } 
 MessageDigest md = MessageDigest.getInstance("SHA1");
 byte[] buffer = new byte[4096];
 int num; 
 // We sort the input entries by name, and add them to the
 // output manifest in sorted order. We expect that the output
 // map will be deterministic. 
 TreeMap<String, JarEntry> byName = new TreeMap<String, JarEntry>();
 for (Enumeration<JarEntry> e = jar.entries(); e.hasMoreElements(); ) {
  JarEntry entry = e.nextElement();
  byName.put(entry.getName(), entry);
 }
 for (JarEntry entry: byName.values()) {
  String name = entry.getName();
  if (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) &&
   !name.equals(CERT_SF_NAME) && !name.equals(CERT_RSA_NAME) &&
   !name.equals(OTACERT_NAME) &&
   (stripPattern == null ||
    !stripPattern.matcher(name).matches())) {
   InputStream data = jar.getInputStream(entry);
   
   while ((num = data.read(buffer)) > 0) {
    md.update(buffer, 0, num);
   }
   Attributes attr = null;
   if (input != null) attr = input.getAttributes(name);
   attr = attr != null ? new Attributes(attr) : new Attributes();
   
   attr.putValue("SHA1-Digest",
       new String(Base64.encode(md.digest()), "ASCII"));
   output.getEntries().put(name, attr);
  }
 } 
 return output;
}

3) signFile
先将inputjar的所有文件拷贝至outputjar,然后生成Manifest.MF,CERT.SF和CERT.RSA


public static void signFile(Manifest manifest, JarFile inputJar, 
File publicKeyFile, X509Certificate publicKey, PrivateKey privateKey,
 JarOutputStream outputJar) throws Exception {
 // Assume the certificate is valid for at least an hour.
 long timestamp = publicKey.getNotBefore().getTime() + 3600L * 1000;
 JarEntry je;
 // 拷贝文件
 copyFiles(manifest, inputJar, outputJar, timestamp);
 // 生成MANIFEST.MF
 je = new JarEntry(JarFile.MANIFEST_NAME);
 je.setTime(timestamp);
 outputJar.putNextEntry(je);
 manifest.write(outputJar);
 // 调用writeSignatureFile 生成CERT.SF
 je = new JarEntry(CERT_SF_NAME);
 je.setTime(timestamp);
 outputJar.putNextEntry(je);
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 writeSignatureFile(manifest, baos);
 byte[] signedData = baos.toByteArray();
 outputJar.write(signedData); 
 // 非常关键的一步 生成 CERT.RSA
 je = new JarEntry(CERT_RSA_NAME);
 je.setTime(timestamp);
 outputJar.putNextEntry(je);
 writeSignatureBlock(new CMSProcessableByteArray(signedData),
      publicKey, privateKey, outputJar);
}

4) writeSignatureFile
生成CERT.SF,其实是对MANIFEST.MF的各个段再次计算Sha1摘要得到CERT.SF。


private static void writeSignatureFile(Manifest manifest, OutputStream out)
  throws IOException, GeneralSecurityException {
 Manifest sf = new Manifest();
 Attributes main = sf.getMainAttributes();
 //添加属性
 main.putValue("Signature-Version", "1.0");
 main.putValue("Created-By", "1.0 (Android SignApk)"); 
 MessageDigest md = MessageDigest.getInstance("SHA1");
 PrintStream print = new PrintStream(
   new DigestOutputStream(new ByteArrayOutputStream(), md),
   true, "UTF-8"); 
 // 添加Manifest.mf的sha1摘要
 manifest.write(print);
 print.flush();
 main.putValue("SHA1-Digest-Manifest",
     new String(Base64.encode(md.digest()), "ASCII")); 
 //对MANIFEST.MF的各个段计算sha1摘要
 Map<String, Attributes> entries = manifest.getEntries();
 for (Map.Entry<String, Attributes> entry : entries.entrySet()) {
  // Digest of the manifest stanza for this entry.
  print.print("Name: " + entry.geTKEy() + "\r\n");
  for (Map.Entry<Object, Object> att : entry.getValue().entrySet()) {
   print.print(att.getKey() + ": " + att.getValue() + "\r\n");
  }
  print.print("\r\n");
  print.flush();
  Attributes sfAttr = new Attributes();
  sfAttr.putValue("SHA1-Digest",
      new String(Base64.encode(md.digest()), "ASCII"));
  sf.getEntries().put(entry.getKey(), sfAttr);
 } 
 CountOutputStream cout = new CountOutputStream(out);
 sf.write(cout); 
 // A bug in the java.util.jar implementation of Android platfORMs
 // up to version 1.6 will cause a spurious IOException to be thrown
 // if the length of the signature file is a multiple of 1024 bytes.
 // As a workaround, add an extra CRLF in this case.
 if ((cout.size() % 1024) == 0) {
  cout.write('\r');
  cout.write('\n');
 }
}

5) writeSignatureBlock
采用SHA1withRSA算法对CERT.SF计算摘要并加密得到数字签名,使用的私钥是privateKey,然后将数字签名和公钥一起存入CERT.RSA。这里使用了开源库bouncycastle来签名。


private static void writeSignatureBlock(
 CMSTypedData data, X509Certificate publicKey, PrivateKey privateKey,
 OutputStream out)
 throws IOException,
   CertificateEncodingException,
   OperatorCreationException,
   CMSException {
 ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>(1);
 certList.add(publicKey);
 JcaCertStore certs = new JcaCertStore(certList); 
 CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
 //签名算法是SHA1withRSA
 ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA")
  .setProvider(sBouncyCastleProvider)
  .build(privateKey);
 gen.addSignerInfoGenerator(
  new JcaSignerInfoGeneratorBuilder(
   new JcaDigestCalculatorProviderBuilder()
   .setProvider(sBouncyCastleProvider)
   .build())
  .setDirectSignature(true)
  .build(sha1Signer, publicKey));
 gen.addCertificates(certs);
 CMSSignedData sigData = gen.generate(data, false);
 ASN1InputStream asn1 = new ASN1InputStream(sigData.getEncoded());
 DEROutputStream dos = new DEROutputStream(out);
 dos.writeObject(asn1.readObject());
}

采用命令行重新签名APK
重新签名apk,其实也有最简单的方法,即下载一个重新签名的工具re-sign.jar,将apk拖进此工具的窗口就生成了重新签名的apk了。下面我就来讲讲复杂的重新签名的方式:采用命令行方法。
一、配置环境,需安装jdk,sdk
二、在已成功安装jdk的目录中找到jarsigner.exe文件,本机的目录如下:C:\Program Files\Java\jdk1.8.0_20\bin
三、去除准备重新签名的apk本身的签名(fantongyo.apk)
将apk以Winrar方式打开,删除META-INF文件夹即可,并将此Apk文件拷贝至C:\Program Files\Java\jdk1.8.0_20\bin目录中
Apk压缩包内容解析:
1.META-INF目录:存放签名后的CERT和MANIFEST文件,用于识别软件的签名及版本信息
2.rest目录:存放各种Android原始资源,包括:动画anim、图片drawable、布局layout、菜单、xml等等
3.AndroidManifest.xml编码后的Android项目描述文件,包括了Android项目的名称、版限、程序组件描述等等
4.Classes.dex编译后Class被dx程序转换成Dalvik虚拟机的可执行字节码文件
5.Resources.arsc所有文本资源的编译产物,里面包含了各Location对应的字符串资源
四、重新签名Apk文件
方法一:通过命令重新生成AndroidApk包签名证书后再重新签名Apk文件
1.在cmd中切换到jdk的bin目录中:cd C:\Program Files\Java\jdk1.8.0_20\bin 回车
2.再输入以下的命令:


Keytool -genkey -alias fantongyo.keystore -keyalg RSA -validity 20000 -keystore fantongyo.keystore

输入完回车后屏幕显示:
输入keystore密码:[密码不回显](一般建议使用20位,最好记下来后面还要用)
再次输入新密码:[密码不回显]( o' ^$ _( F( K& I0
您的名字与姓氏是什么?
[Unknown]:fantongyo
您的组织单位名称是什么?
[Unknown]:fantong
您的组织名称是什么?
[Unknown]:life
您所在的城市或区域名称是什么?) L# V' |. E0 f; {
[Unknown]:shenzhen
您所在的州或省份名称是什么?
[Unknown]:guangdong
该单位的两字母国家代码是什么
[Unknown]:CN
CN=fantongyo, U=fantong, O=fantong team, L=shenzhen, ST=guangdong, C=CN正确吗?
[否]:Y
输入< mine.keystore>的主密码
(如果和keystore密码相同,按回车):
查看C:\Program Files\Java\jdk1.8.0_20\bin目录下,生成了一个签名用的证书文件 fantongyo.keystore
3.重新签名Apk文件
在cmd中输入:jarsigner –verbose –keystore fantongyo.keystore –signedjar fantongyo_signed.apk fantongyo.apk fantongyo.keystore

输入完回车后屏幕显示:
jar已签名。

2016223143743819.jpg (681×380)

在C:\Program Files\Java\jdk1.8.0_20\bin目录下已重新生成fantongyo_signed.apk文件

方法二、以android自带的debug.keystore重新签名Apk文件
1.打开eclipse,菜单栏Window—>Preferences—>Android—>Build—>Default debug keystore目录(我的编辑器显示:C:\Users\Administrator\.android\debug.keystore)
2.将debug.keystore文件拷贝至C:\Program Files\Java\jdk1.8.0_20\bin目录下
3.在cmd中切换到jdk的bin目录中:cd C:\Program Files\Java\jdk1.8.0_20\bin 回车
4.再输入以下的命令: 代码如下:jarsigner -digestalg SHA1 -sigalg MD5withRSA -keystore debug.keystore -storepass android -keypass android fantongyo.apk androiddebugkey回车
5.在sdk中找到zipalign文件,我电脑的目录为:E:\SoftWare\adt-bundle-windows-x86-20140702\sdk\build-tools\android-4.4W
在cmd中切换到sdk的存放zipalign.exe文件的目录中:


cd E:\SoftWare\adt-bundle-windows-x86-20140702\sdk\build-tools\android-4.4W

6.再输入:zipalign 4 fantongyo.apk fantongyo_signed.apk即可(fantongyo_signed.apk是   重新签名后的apk文件)

您可能感兴趣的文章:Android签名机制介绍:生成keystore、签名、查看签名信息等方法android应用签名详细步骤Android获取apk程序签名信息代码示例Android APK使用Debug签名重新打包 Eclipse更改默认Debug签名Android Apk去掉签名以及重新签名的方法iOS 基于AFNetworking下自签名证书配置的方法iOS中的ipa重签名(逆向必备)iOS之https自签名证书认证及数据请求的封装原理IOS 签名错误codesign failed with exit code 1解决方法Android和iOS包批量重签名


--结束END--

本文标题: 给Android的APK程序签名和重新签名的方法

本文链接: https://www.lsjlt.com/news/25629.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 给APK签名—两种方式(flutter android 安装包)
    前提:给未签名的apk签名,可以先检查下apk有没有签名 通过命令行查看:打开终端或命令行界面,导入包含APK文件的目录,并执行以下命令: keytool -printcert -jarfile your_app.apk 将...
    99+
    2023-09-30
    flutter android
  • Android App系统签名的方法
    Android App系统签名的方法 Android应用程序系统签名是确保应用程序安全性和完整性的重要步骤。通过对应用进行系统签名,可以验证应用来源,并防止任何未经授权的修改。在本文中,我们将介绍An...
    99+
    2023-09-29
    android Android
  • 获取Android签名MD5的方式
    形而上者谓之道,形而下者谓之器 我们在申请百度云/腾讯云等第三方的各种服务时,经常会遇到需要提供包名和签名MD5的情况。这里特地总结一下: 1. 获取MD5的一般方式 1.1 有签名文件(.keystore)的情况下: keytoo...
    99+
    2023-08-21
    android
  • 微信小程序api签名验证的方法
    这篇文章主要讲解了“微信小程序api签名验证的方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“微信小程序api签名验证的方法”吧!用户数据的签名验证和加解密数据签名校验为了确保 开放接口 ...
    99+
    2023-06-26
  • Android生成签名文件的方法是什么
    生成Android签名文件的方法如下:1. 首先,确保安装了Java Development Kit(JDK)。2. 打开终端或命令...
    99+
    2023-09-22
    Android
  • Android APK 签名打包原理分析(三)【静默安装的实现方案】
    背景 小编目前从事的系统定制类工作,有客户提出了,需要后台“静默安装”他们的app,也就是悄无声息的安装,而且特别强调,不可以跳出任何安装引导页面,他们的app下载完成之后,后台调用公开的androi...
    99+
    2023-09-06
    android java 开发语言
  • Java 给PDF签名时添加可信时间戳的方法
    一、程序运行环境 编译环境:IntelliJ IDEA 所需测试文件:PDF、.pfx数字证书及密钥、PDF Jar包(Free Spire.PDF for Jav...
    99+
    2024-04-02
  • Android 系统签名实现的三种方式
    Android 系统签名可以通过以下三种方式实现:1. 使用 Android Studio 自带的签名工具:Android Stud...
    99+
    2023-10-12
    Android
  • Golang编写签名请求的方法
    随着互联网行业的持续发展,越来越多的应用程序需要向用户提供数据交互功能。为了保证数据安全性,许多应用程序在数据传输过程中加入了签名机制。签名机制可以防止数据被篡改、伪造或注入恶意代码,从而保证数据的完整性和安全性。本文将介绍使用Golang...
    99+
    2023-05-14
  • Android在Gradle中更改APK文件名的方法
    这篇文章将为大家详细讲解有关Android在Gradle中更改APK文件名的方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。前言本文主要给大家介绍了关于Android在Gradle中更改APK文件名的相...
    99+
    2023-05-30
    android gradle apk文件名
  • 获取Android签名MD5的方式实例详解
    目录1. 获取MD5的一般方式1.1 有签名文件(.keystore)的情况下:1.2 有apk包的情况下:1.3 解压apk包,拿到META-INF/CERT.RSA文件:2. 获...
    99+
    2023-02-09
    Android 获取签名 android md5 安卓获取md5
  • Android系统签名实现的方式有哪几种
    Android系统签名实现的方式有以下几种: 使用自签名证书:开发者可以使用自己生成的私钥和证书进行签名,这种方式比较简单,但可...
    99+
    2023-10-26
    Android
  • Java基于BC包的实现SM2签名验签方案,以及SM2签名中bc包冲突的部分解决方法
    信创改造也有一段时间了,这里记录和总结一些关于SM2算法的知识点。 1. pom.xml org.bouncycastle bcprov-jdk15on 1.57 或 or...
    99+
    2023-08-19
    java 算法
  • 微信小程序实现简单手写签名组件的方法实例
    目录背景:需求:效果一、思路 二、实现 1. 页面与样式 2. 初始化 3. 点击时 4. 签名时 三、总结 背景: 在做项目过程中,需要在微信小程序中实现手写签名组件。在网上找了微...
    99+
    2024-04-02
  • Java实现APIsign签名校验的方法详解
    目录1. 前言2. 签名生成策略3. API 签名算法 Java 实现4. 测试一下1. 前言 目的:为防止中间人攻击。 场景: 项目内部前后端调用,这种场景只需要做普通参数的签名校...
    99+
    2024-04-02
  • Linux给文件重命名的方法有哪些
    1. 使用mv命令进行重命名。例如,要将文件old_file.txt重命名为new_file.txt,可以使用以下命令:```mv ...
    99+
    2023-08-21
    Linux
  • Java 方法(方法的定义,可变参数,参数的传递问题,方法重载,方法签名)
    目录一、方法(Method)概念二、可变参数(Variable)三、方法的参数传递问题1. 基本数据类型2. 引用数据类型四、方法签名(Method Signature)五、方法的重...
    99+
    2024-04-02
  • win7如何安装没有数字签名的驱动程序
    今天小编给大家分享一下win7如何安装没有数字签名的驱动程序的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。点击左下角的开始 ...
    99+
    2023-06-28
  • 微信小程序实现手写签名的示例代码
    目录1.效果图2.相关代码canvas代码js相关在微信小程序上实现手写签名,获取canvascontext新版本和旧版本有点坑,新版本在获取canvas后如果页面有滑动,则签名坐标...
    99+
    2024-04-02
  • 签名一个使用插件1.3版的Java小程序(转)
    为了签署一个小程序,有下面几件事情需要完成:1。签名工具2。一个RAS keypair 和一个公钥的证书链。3。把小程序用到的所有类文件打包成一个JAR文件。签名工具现在有两种工具支持签署使用插件的小程序1。Jarsigner --可以在j...
    99+
    2023-06-03
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作