Java 解析 apk 的签名


Java解析apk的签名,是表示这个apk的唯一作者的。里面涉及到很多什么 私钥 公钥 之类的东西,反正是涉及的很严密,在网上的相关文档也不是很少。 说白了,就是不能轻易的让其他人去修改的你的签名,不能去修改的apk。要是修改了,签名就会发生变化,知道不是原生作者。我们就是为了判断一个apk的包,是否是原来的作者,就写一个Java的自动解析apk的签名的东西。获取到之后,当下次软件升级更新的时候,判断签名是否匹配,否则,不予以升级、更新之类的。

网上写Java获取apk签名的方式主要有两种,

(1)、解压apk包,在里面找到一个.RSA文件,然后进行解析。

    import sun.security.pkcs.PKCS7; 
    import java.io.FileInputStream; 
    import java.io.FileNotFoundException; 
    import java.io.IOException; 
    import java.io.InputStream; 
    import java.security.GeneralSecurityException; 
    import java.security.cert.X509Certificate; 
    public class SignApk { 
        public static X509Certificate readSignatureBlock(InputStream in) throws IOException, GeneralSecurityException { 
            PKCS7 pkcs7 = new PKCS7(in); 
            return pkcs7.getCertificates()[0]; 
        } 
        public static void main(String[] args) throws FileNotFoundException, IOException, GeneralSecurityException { 
            X509Certificate publicKey = readSignatureBlock(new FileInputStream("./CERT.RSA")); 
            System.out.println("issuer:" + publicKey.getIssuerDN()); 
            System.out.println("subject:" + publicKey.getSubjectDN()); 
            System.out.println(publicKey.getPublicKey()); 
        } 
    } 

如下:

issuer:CN=Sodino 
subject:CN=SodinoChen 
Sun RSA public key, 1024 bits 
  modulus: 154308594144468705348294760484396264219304223307125368116140288659005422830114898674784044956357283073098453132761265419031547660249768235885852151387544779929680291539693130807734777897342583741160281523340554669518353638961667015615312475350767041053961957188628650343640790505255765999004862716823611888529 
  public exponent: 65537

 (2)、就是利用cmd指令,也就是 jarsigner  指令获取。

jarsigner -verify -verbose -certs <your_apk_path.apk> 

由于是我们上传apk,如果解压解析的话,就有点过分了,破坏了apk不说,还要删除解压之后的文件,有些繁琐,而且操作复杂,不适合我们。所以,决定使用第二种方法,就是cmd指令, 然后,让java去调用 cmd的指令,然后打印返回信息进行解析。获取自己想要的信息。

现在是贴出来最主要的方法:

package test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;

 


public class newtest3 {
 public static void main(String[] arg)
  { 
  String apkUrl = "C:\\Users\\Administrator\\Desktop\\com.taobao.taobao_淘宝.apk";
  String apkUrl1 = "C:\\Users\\Administrator\\Desktop\\sign.apk";
  String result = getSingle(apkUrl);
  String result2 = getSingle(apkUrl1);
  System.out.println(result+"~"+result2);
  } 
 
 
 public static String getSingle(String apkUrl){
        Process p; 
        //test.bat中的命令是ipconfig/all
        String cmd = "jarsigner -verify -verbose -certs " + apkUrl;
//        String cmd="jarsigner -verify -verbose -certs C:\\Users\\Administrator\\Desktop\\PandaClient.apk"; 
        String resultstr = null;
        try 
        { 
            //执行命令 
            p = Runtime.getRuntime().exec(cmd); 
            //取得命令结果的输出流 
            InputStream fis=p.getInputStream(); 
            //用一个读输出流类去读 
            //用缓冲器读行 
            BufferedReader br=new BufferedReader( new InputStreamReader(fis,"GB2312")); 
            String line=null; 
            //直到读完为止 
            int i = 0;
            while((line=br.readLine())!=null) 
            { 
             if(line.contains("X.509")){  //解析符合自己需要的內容,获取之后,直接返回。
//                  System.out.println(line);
              resultstr = line;
                  break;
             }
                i++;
            } 
        } 
        catch (IOException e) 
        { 
            e.printStackTrace(); 
        } 
        return resultstr.replace("      X.509, ", "");
 }
}

以上主要的代码是, 边界一个在cmd 要执行的 一个字符串,路径别忘了转移字符啊。 然后让java去执行cmd,获取返回的内容。 匹配,当获得自己想要的 我的字符串开头是

X.509为开头的。当获取到之后,就立刻跳出循环。处理获取到的字符串,然后直接返回就好了。

就是这些了,希望这些代码对读者有帮助哈。

相关内容