Android APK代碼簽名分析

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 通過簽名證書,識別開發者的身份,並賦予特定的權限



參考資料












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