APK文件分析
一、把apk擴展名改成zip,打開,在META-INF目錄可以看到3個文件:
MANIFEST.MF、CERT.SF、CERT.RSA。這3個文件就和APK的簽名有關。
二、簽名文件分析
1 MANIFEST.MF的產生
打開MANIFEST.MF,可以看到內容大概爲:
“
Manifest-Version: 1.0
Created-By: 1.0 (Android)
Name: res/drawable/btnekeycerts450175.jpg
SHA1-Digest: mjAWDn2kuvJugGF2g5DkISanOl4=
......
”
顯然,這是對APK裏面各文件的SHA1摘要值的Base64編碼
2 CERT.SF的產生
打開CERT.SF,可以看到內容大概爲:
“
Signature-Version: 1.0
Created-By: 1.0 (Android)
SHA1-Digest-Manifest: fLuBqqpSsgenbDtSvYbTdNOyweE=
Name: res/drawable/btnekeycerts450175.jpg
SHA1-Digest: CfJH/VtLPO66phWxguWDg9YlKVQ=
......
”
其中第三行摘要值是對文件MANIFEST.MF進行摘要的結果。
第6行的摘要值,是對MANIFEST.MF中,
“
Name: res/drawable/btnekeycerts450175.jpg
SHA1-Digest: mjAWDn2kuvJugGF2g5DkISanOl4=
”
這3行文本的摘要結果。即
SHA1("Name: res/drawable/btnekeycerts450175.jpg"+CR+LF+"SHA1-Digest: CfJH/VtLPO66phWxguWDg9YlKVQ="+CR+LF+CR+LF)
顯然,CERT.SF是對MANIFEST.MF進行了第二次摘要。
3 CERT.RSA的產生
CERT.RSA文件是個二進制文件,是DER格式的PKCS#7 SignedData結構。
裏面包含:
ContentInfo裏面並不包括原文,其實原文就是CERT.SF;
簽名者證書(不包含證書鏈);
SignerInfo簽名值,裏面沒有其他屬性(比如時間戳)
CERT.RSA產生代碼:
private static void writeSignatureBlock(
Signature signature, X509Certificate publicKey, OutputStream out)
throws IOException, GeneralSecurityException {
SignerInfo signerInfo = new SignerInfo(
new X500Name(publicKey.getIssuerX500Principal().getName()),
publicKey.getSerialNumber(),
AlgorithmId.get("SHA1"),
AlgorithmId.get("RSA"),
signature.sign());
PKCS7 pkcs7 = new PKCS7(
new AlgorithmId[] { AlgorithmId.get("SHA1") },
new ContentInfo(ContentInfo.DATA_OID, null),
new X509Certificate[] { publicKey },
new SignerInfo[] { signerInfo });
pkcs7.encodeSignedData(out);
}
以上過程可以通過查看代碼 /android-2.2-froyo/src/com/android/signapk/SignApk.java 得到驗證。
APK安裝與簽名驗證
查看代碼 /android-2.2-froyo/src/com/android/server/PackageManagerService.java:installPackage()->verifySignaturesLP()
再調用到 /android-2.2-froyo/src/android/content/pm/PackageParser.java:parsePackage()
最後調用到 org.apache.harmony.security.utils.JarUtils的verifySignature()方法得到簽名證書
一些特殊的代碼簽名證書
瀏覽器插件簽名證書
參見代碼android.webkit.PluginManager.java的第75行:
private static final String SIGNATURE_1 = "308204c......
這是一個“Adobe Systems Incorporated”的代碼簽名證書,只有經過此證書私鑰簽名過的瀏覽器插件APK,才能正常安裝到Android自帶的瀏覽器中
平臺簽名證書
在Android源碼的“build\target\product\security”目錄下,有platform.pk8和platform.x509.pem兩個文件,分別是私鑰和證書文件。在APK中聲明android:sharedUserId="android.uid.system",並用platform證書私鑰簽名此APK,可以取得系統級權限。當然,手機廠家在定製系統時,可能會用自己生成的平臺簽名證書,這樣你就無法通過這2個文件的簽名得到系統權限了。
總結
Android通過對APK的代碼簽名,達到了以下目的:
1 保證了APK數據包的完整性
2 通過比對簽名證書,避免有害程序仿冒已安裝的程序,進行惡意更新替換
3 通過簽名證書,識別開發者的身份,並賦予特定的權限