Last active
November 1, 2020 10:30
-
-
Save rwestergren/648cca2c91b1b42b7f40 to your computer and use it in GitHub Desktop.
GetAndroidSig
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.IOException; | |
import java.io.InputStream; | |
import java.lang.ref.WeakReference; | |
import java.security.cert.CertificateEncodingException; | |
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 final 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) { | |
final 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; | |
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 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; | |
} | |
} |
Awesome job ! I've done this manually once with a lot of pain.
Hello, I got the signature of an application thanks to the tools getandroidsig.
How to be able to put it in file .pk8 and .pem
thank you in advance
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
decent approach, I've had to use a similar approach myself to obtain the signature for an app I was attempting to reverse because they rolled their api to utilize the signature to ensure requests originated from their app