I'm using Java (J2SE) to create a desktop application. It has a function that check if two unknown .apk files (for ex app1.apk and app2.apk) are same application or not. My idea is comparing the fingerprint (in file META-INF/CERT.RSA) and names of the two apps.
In addition, I also want to get the android app name which is defined in the file strings.xml. In particular, I read the AndroidManifest.xml first, in tag application I get the value of attribute android:label="@string/app_name". Then i get the value of attribute app_name in file strings.xml. However the file is compiled in file resources.arsc which is an unreadable binary file.
Any solution for this idea or any other ideas for checking if two unknown .apk files are same app? I really appreciate your help.
Thanks
The package name serves as a unique identifier for the application.
So basically 2 apk which refer to he same app will have same package name.
Then maybe one of these apk is corrupted somehow eg :
If you want to be sure that one of this app has not been modified by 3rd part, you will have to do all these check above.
Then to sum up the whole thing of determining if 2 apks are the same official app :
CERT.SF are not necesserally the same if apk refer to the same app with different version (files added or deleted) but public key/private key pair must remained untouched to enable update of this app (unless it will result in "signature conflict" or "existing package already exist" errors)
Check signature verification
You can use JarSigner source code for this : http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/security/tools/JarSigner.java#JarSigner.signatureRelated%28java.lang.String%29
with external jar lib sun-security-tool : http://www.java2s.com/Code/Jar/a/Downloadandroidsunjarsignsupport11jar.htm
Check public keys are the same
Compare the extracted public key. Here is the method I made for extracting PKCS7 certificate and public key from it :
/**
* Retrieve public key from PKCS7 certificate
*
* @param certPath
* @return
* @throws IOException
* @throws InvalidKeySpecException
* @throws NoSuchAlgorithmException
*/
public static String getPublicKey(String certPath) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
File f = new File(certPath);
FileInputStream is = new FileInputStream(f);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
PKCS7 test = new PKCS7(buffer.toByteArray());
X509Certificate[] certs = test.getCertificates();
for (int i = 0; i < certs.length; i++) {
if (certs[i] != null && certs[i].getPublicKey() != null) {
return new BASE64Encoder().encode(certs[i].getPublicKey().getEncoded());
}
}
return "";
}
Read package-name from Android Manifest
Here you have to parse Android binary XML for extracting these information. with this link, you have a lot of tools you can use (and snippet code) :
How to parse the AndroidManifest.xml file inside an .apk package
To get your app-name this is a bit different, this is an Android compiled resource. apktool can decode that kind of file but if you want to do this in java you'll have to decode it yourself. Here is apktool decoder https://github.com/iBotPeaches/Apktool/blob/master/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java. But if you want the app name it is not necessary in string.xml so this is rather something specific you want to do.
I have made a Java tool that makes jar verification / public key comparison : https://github.com/bertrandmartel/apk-checker
With command line, you can test your output much faster and easier :
Check signature verification
jarsigner -verbose -verify <your_apk_file_name>.apk | grep "jar verified"
Check public keys are the same
unzip -p <your_apk_file_name1>.apk META-INF/CERT.RSA | keytool -printcert
check package-name are the same
aapt d xmltree <your_apk_file_name1>.apk AndroidManifest.xml | grep "package=" | sed -e "s/.*=//g" | sed -e "s/ .*//g"
A gist for Bash scripts is available at https://gist.github.com/bertrandmartel/374564b950e8a577550b