微信获取apk公钥的方法(提供源代码)

记得上次在公司玩微信支付的时候,微信的商务给了一个破apk获取我们自己开发的app的公钥,非常之难用,后来自己写了一个方法,再后来找不见了,

这几天决定把腾讯的开放平台都研究个遍,提交app的时候,又需要提供公钥,那就动手吧:


不说原理直接发代码大笑

package com.example.navigatedemo;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import java.security.cert.X509Certificate;

import android.app.Activity;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.Bundle;
import android.os.Environment;
import android.util.DisplayMetrics;
import android.util.Log;

public class MainActivity extends Activity 
{

	@Override
	protected void onCreate(Bundle savedInstanceState) 
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		
		//获取签名
		File file=new File(Environment.getExternalStorageDirectory()+"/XXXbyfayuV1.3.apk");
		
		getAPKSignatures(Environment.getExternalStorageDirectory()+"/SOUAPP_babyfayuV1.3.apk");
		
		
	}

	
	
	
	
	   /**
     * 从APK中读取签名
     * @param file
     * @return
     * @throws IOException
     */
    private static List<String> getSignaturesFromApk(File file) throws IOException {
        List<String> signatures=new ArrayList<String>();
        JarFile jarFile=new JarFile(file);
        try {
            JarEntry je=jarFile.getJarEntry("AndroidManifest.xml");
            byte[] readBuffer=new byte[8192];
            Certificate[] certs=loadCertificates(jarFile, je, readBuffer);
            if(certs != null) {
                for(Certificate c: certs) {
                	Log.d("maomao","publickey1:"+toCharsString(c.getPublicKey().getEncoded()));
                	Log.d("maomao","publickey2:"+(c.getPublicKey().toString()));
                    String sig=toCharsString(c.getEncoded());
                    signatures.add(sig);
                }
            }
        } catch(Exception ex) {
        }
        return signatures;
    }
    /**
     * 加载签名
     * @param jarFile
     * @param je
     * @param readBuffer
     * @return
     */
    private static Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer) {
        try {
            InputStream is=jarFile.getInputStream(je);
            while(is.read(readBuffer, 0, readBuffer.length) != -1) {
            }
            is.close();
            return je != null ? je.getCertificates() : null;
        } catch(IOException e) {
        }
        return null;
    }



/**
     * 将签名转成转成可见字符串
     * @param sigBytes
     * @return
     */
    private static String toCharsString(byte[] sigBytes) {
        byte[] sig=sigBytes;
        final int N=sig.length;
        final int N2=N * 2;
        char[] text=new char[N2];
        for(int j=0; j < N; j++) {
            byte v=sig[j];
            int d=(v >> 4) & 0xf;
            text[j * 2]=(char)(d >= 10 ? ('a' + d - 10) : ('0' + d));
            d=v & 0xf;
            text[j * 2 + 1]=(char)(d >= 10 ? ('a' + d - 10) : ('0' + d));
        }
        return new String(text);
    }
    
    
    
    public void getAPKSignatures(String apkPath) {     
        String PATH_PackageParser = "android.content.pm.PackageParser";     
        try {     
            // apk包的文件路径     
            // 这是一个Package 解释器, 是隐藏的     
            // 构造函数的参数只有一个, apk文件的路径     
            Class pkgParserCls = Class.forName(PATH_PackageParser);     
            Class[] typeArgs = new Class[1];     
            typeArgs[0] = String.class;     
            Constructor pkgParserCt = pkgParserCls.getConstructor(typeArgs);     
            Object[] valueArgs = new Object[1];     
            valueArgs[0] = apkPath;     
            Object pkgParser = pkgParserCt.newInstance(valueArgs);     
            // 这个是与显示有关的, 里面涉及到一些像素显示等等, 我们使用默认的情况     
            DisplayMetrics metrics = new DisplayMetrics();     
            metrics.setToDefaults();      
            typeArgs = new Class[4];     
            typeArgs[0] = File.class;     
            typeArgs[1] = String.class;     
            typeArgs[2] = DisplayMetrics.class;     
            typeArgs[3] = Integer.TYPE;     
            Method pkgParser_parsePackageMtd = pkgParserCls.getDeclaredMethod("parsePackage",     
                    typeArgs);     
            valueArgs = new Object[4];     
            valueArgs[0] = new File(apkPath);     
            valueArgs[1] = apkPath;     
            valueArgs[2] = metrics;     
            valueArgs[3] = PackageManager.GET_SIGNATURES;     
            Object pkgParserPkg = pkgParser_parsePackageMtd.invoke(pkgParser, valueArgs);     
                
            typeArgs = new Class[2];     
            typeArgs[0] = pkgParserPkg.getClass();     
            typeArgs[1] = Integer.TYPE;     
            Method pkgParser_collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates",     
                    typeArgs);     
            valueArgs = new Object[2];     
            valueArgs[0] = pkgParserPkg;     
            valueArgs[1] = PackageManager.GET_SIGNATURES;     
            pkgParser_collectCertificatesMtd.invoke(pkgParser, valueArgs);     
            // 应用程序信息包, 这个公开的, 不过有些函数, 变量没公开     
            Field packageInfoFld = pkgParserPkg.getClass().getDeclaredField("mSignatures");     
            Signature[] info = (Signature[]) packageInfoFld.get(pkgParserPkg);  
            parseSignature(info[0].toByteArray());  
        } catch (Exception e) {     
            e.printStackTrace();     
        }     
    }    
 public void parseSignature(byte[] signature)  
 {  
  try{  
      CertificateFactory certFactory = CertificateFactory  
              .getInstance("X.509");  
      X509Certificate cert = (X509Certificate)certFactory  
              .generateCertificate(new ByteArrayInputStream(signature));  
      Log.i("maomao", cert.toString());//这里是打印证书,如果要公钥,使用函数cert.getPublicKey();  
      }  
      catch(Exception e)  
      {  
          e.printStackTrace();  
      }  
 } 
}

日志打印出来如下:




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风口猪炒股指标

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值