微信獲取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();  
      }  
 } 
}

日誌打印出來如下:




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章