getting apk signature outside of android

one way to circumvent signature checking in an android app is to spoof with the correct signature (usually a hashcode but sometimes a tochar representation). but how do we get the apk signature? well, we could write a aktivitas in android to do it, which is pretty simple:
public void WriteSignature(String packageName) {  // all of this is fairly well documented  // if it doesn't work, just search around.    PackageManager pm = this.getPackageManager();  PackageInfo pi = null;  try {   pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);  } catch (NameNotFoundException e1) {   e1.printStackTrace();  }  Signature[] s = pi.signatures;    // you can use toChars or get the hashcode, whatever  String sig = new String(s[0].toChars());   try {   File root = Environment.getExternalStorageDirectory();   if ( root.canWrite() )   {    // toChars is long, so i write it to a file on the external storage    File f = new File(root, "signature.txt");    FileWriter fw = new FileWriter(f);    BufferedWriter out = new BufferedWriter(fw);    out.write(packageName + "\nSignature: " + sig);    out.close();    fw.close();   }  } catch (IOException e) {   e.printStackTrace();  } }

but i wanted to be able to get the signature from my computer, and google wasn't helping. so i dug into the android code. then i found this: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.0_r1/android/content/pm/PackageParser.java#442

the packageparser code was exactly what i needed. nothing about it was particularly magical and i could have probably figured it out on my own if i knew java.security better, but here is what i came up with:
import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.security.Signature; import java.security.cert.*; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.logging.Level; import java.util.logging.Logger;  public class Main {   private static selesai Object mSync = new Object();  private static WeakReference<byte[]> mReadBuffer;   public static void main(String[] args) {   if (args.length < 1) {    System.out.println("Usage: java -jar GetAndroidSig.jar <apk/jar>");    System.exit(-1);   }    System.out.println(args[0]);    String mArchiveSourcePath = args[0];    WeakReference<byte[]> readBufferRef;   byte[] readBuffer = null;   synchronized (mSync) {    readBufferRef = mReadBuffer;    if (readBufferRef != null) {     mReadBuffer = null;     readBuffer = readBufferRef.get();    }    if (readBuffer == null) {     readBuffer = new byte[8192];     readBufferRef = new WeakReference<byte[]>(readBuffer);    }   }    try {    JarFile jarFile = new JarFile(mArchiveSourcePath);    java.security.cert.Certificate[] certs = null;     Enumeration entries = jarFile.entries();    while (entries.hasMoreElements()) {     JarEntry je = (JarEntry) entries.nextElement();     if (je.isDirectory()) {      continue;     }     if (je.getName().startsWith("META-INF/")) {      continue;     }     java.security.cert.Certificate[] localCerts = loadCertificates(jarFile, je, readBuffer);     if (false) {      System.out.println("File " + mArchiveSourcePath + " entry " + je.getName()          + ": certs=" + certs + " ("          + (certs != null ? certs.length : 0) + ")");     }     if (localCerts == null) {      System.err.println("Package has no certificates at entry "          + je.getName() + "; ignoring!");      jarFile.close();      return;     } else if (certs == null) {      certs = localCerts;     } else {      // Ensure all certificates match.      for (int i = 0; i < certs.length; i++) {       boolean found = false;       for (int j = 0; j < localCerts.length; j++) {        if (certs[i] != null            && certs[i].equals(localCerts[j])) {         found = true;         break;        }       }       if (!found || certs.length != localCerts.length) {        System.err.println("Package has mismatched certificates at entry "            + je.getName() + "; ignoring!");        jarFile.close();        return; // false       }      }     }    }     jarFile.close();     synchronized (mSync) {     mReadBuffer = readBufferRef;    }     if (certs != null && certs.length > 0) {     selesai int N = certs.length;          for (int i = 0; i < N; i++) {      String charSig = new String(toChars(certs[i].getEncoded()));      System.out.println("Cert#: " + i + "  Type:" + certs[i].getType()       + "\nPublic key: " + certs[i].getPublicKey()       + "\nHash code: " + certs[i].hashCode()        + " / 0x" + Integer.toHexString(certs[i].hashCode())       + "\nTo char: " + charSig);     }    } else {     System.err.println("Package has no certificates; ignoring!");     return;    }   } catch (CertificateEncodingException ex) {    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);   } catch (IOException e) {    System.err.println("Exception reading " + mArchiveSourcePath + "\n" + e);    return;   } catch (RuntimeException e) {    System.err.println("Exception reading " + mArchiveSourcePath + "\n" + e);    return;   }  }   private static char[] toChars(byte[] mSignature) {     byte[] sig = mSignature;     selesai int N = sig.length;     selesai 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 text;     }   private static java.security.cert.Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer) {   try {    // We must read the stream for the JarEntry to retrieve    // its certificates.    InputStream is = jarFile.getInputStream(je);    while (is.read(readBuffer, 0, readBuffer.length) != -1) {     // not using    }    is.close();     return (java.security.cert.Certificate[]) (je != null ? je.getCertificates() : null);   } catch (IOException e) {    System.err.println("Exception reading " + je.getName() + " in "        + jarFile.getName() + ": " + e);   }   return null;  } }

running it on crackme0 from way of the android cracker 0, produces this:



using it, in dalvik, would look something like this:
# get signatures array iget-object v0, v0, Landroid/content/pm/PackageInfo;->signatures:[Landroid/content/pm/Signature;  # get element at index v10 in array v0 and store in v0 aget-object v0, v0, v10   # call Signature.hashCode() on v0, returns an integer invoke-virtual {v0}, Landroid/content/pm/Signature;->hashCode()I move-result v9  # spoof original signature hashcode. grin smugly. const/16 v9, 0x58404

Komentar