天天看點

[轉]Android APK簽名原理及方法

準備知識:資料摘要

這個知識點很好了解,百度百科即可,其實他也是一種算法,就是對一個資料源進行一個算法之後得到一個摘要,也叫作資料指紋,不同的資料源,資料指紋肯定不一樣,就和人一樣。

消息摘要算法(Message Digest Algorithm)是一種能産生特殊輸出格式的算法,其原理是根據一定的運算規則對原始資料進行某種形式的資訊提取,被提取出的資訊就被稱作原始資料的消息摘要。

著名的摘要算法有RSA公司的MD5算法和SHA-1算法及其大量的變體。

消息摘要的主要特點有:

1)無論輸入的消息有多長,計算出來的消息摘要的長度總是固定的。例如應用MD5算法摘要的消息有128個比特位,用SHA-1算法摘要的消息最終有160比特位的輸出。

2)一般來說(不考慮碰撞的情況下),隻要輸入的原始資料不同,對其進行摘要以後産生的消息摘要也必不相同,即使原始資料稍有改變,輸出的消息摘要便完全不同。但是,相同的輸入必會産生相同的輸出。

3)具有不可逆性,即隻能進行正向的資訊摘要,而無法從摘要中恢複出任何的原始消息。

一 Android簽名機制及原理

Android系統在安裝APK的時候,首先會檢驗APK的簽名,如果發現簽名檔案不存在或者校驗簽名失敗,則會拒絕安裝,是以應用程式在釋出之前一定要進行簽名。給APK簽名可以帶來以下好處:

應用程式更新

如果想無縫更新一個應用,Android系統要求應用程式的新版本與老版本具有相同的簽名與包名。若包名相同而簽名不同,系統會拒絕安裝新版應用。

應用程式子產品化

Android系統可以允許同一個證書簽名的多個應用程式在一個程序裡運作,系統實際把他們作為一個單個的應用程式。此時就可以把我們的應用程式以子產品的方式進行部署,而使用者可以獨立的更新其中的一個子產品。

代碼或資料共享

Android提供了基于簽名的權限機制,一個應用程式可以為另一個以相同證書簽名的應用程式公開自己的功能與資料,同時其它具有不同簽名的應用程式不可通路相應的功能與資料。

應用程式的可認定性

簽名資訊中包含有開發者資訊,在一定程度上可以防止應用被僞造。例如網易雲加密對Android APK加殼保護中使用的“校驗簽名(防二次打包)”功能就是利用了這一點。

簽名原理

對一個APK檔案簽名之後,APK檔案根目錄下會增加META-INF目錄,該目錄下增加三個檔案:

MANIFEST.MF

NETEASE.RSA

NETEASE.SF

其中.RSA檔案還可能是.DSA檔案,RSA與SF檔案的檔案名可以更改,但是它們的命名必須一樣。

MANIFEST.MF中儲存了APK裡所有檔案的SHA1校驗值的BASE64編碼,格式如下(一個檔案對應一條記錄):

Name: res/anim/abc_fade_in.xml

SHA1-Digest: ohPEA4mboaFUu9LZMUwk7FmjbPI=

Name: res/anim/abc_fade_out.xml

SHA1-Digest: MTJWZc22b5LNeBboqBhxcQh5xHQ=

SF檔案裡儲存了MANIFEST.MF檔案的SHA1校驗值的BASE64編碼,同時還儲存了MANIFEST.MF中每一條記錄的SHA1檢驗值BASE64編碼,格式如下:

SHA1-Digest-Manifest: ZRhh1HuaoEKMn6o21W1as0sMlaU=

Name: res/anim/abc_fade_in.xml

SHA1-Digest: wE1QEZhFkLBWMw4TRtxPdsiMRtA=

Name: res/anim/abc_fade_out.xml

SHA1-Digest: MfCV1efdxSKtesRMF81I08Zyvvo=

RSA檔案則包含了簽名的公鑰、簽名所有者等資訊,還儲存了http://my.oschina.net/u/816213/blog/685762?fromerr=RSS3IhKo用SHA1withRSA簽名算法對SF檔案的簽名結果資訊。

Android系統就是根據這三個檔案的内容對APK檔案進行簽名檢驗的。

二 Android 簽名方法

1、apksign、jarsinger

一般的簽名過程可以由apksign.jar或者jarsinger.jar完成。apksign.jar由Android SDK提供,使用方法如下:

java -jar signapk.jar testkey.x509.pem testkey.pk8 update.apk update_signed.apk

它接受一個PEM公鑰檔案,PK8私鑰檔案,對update.apk進行簽名,簽名後的檔案儲存到update_signed.apk。

jarsinger是由JDK提供,使用方法如下:

jarsigner -verbose -keystore d:\\debug.keystore -signedjar update_signed.apk update.apk androiddebugkey -digestalg SHA1 -sigalg MD5withRSA -keypass android -storepass android

其中:

-keystore表示keystore檔案的路徑

androiddebugkey 表示keystore中的一個别名

-digestalg表示摘要算法

-sigalg 表示簽名算法

-keypass 表示别名密碼

-storepass表示keystore密碼

經過測試,發現以上兩個傳統的簽名工具存在以下缺點:

1)、jarsigner在對一個已經有META-INF目錄的APK進行簽名的時候,有可能會報錯:

jarsigner: 無法對 jar 進行簽名: java.util.zip.ZipException: invalid entry compressed size (expected 1368 but got 1379 bytes)

2)、如果APK中已經有簽名檔案且簽名檔案中的RSA(或DSA)、SF檔案的命名不是CERT的時候,用這兩個簽名工具進行簽名後,會出現:

META-INF目錄下會有兩個RSA/SF檔案,會導緻APK在安裝的時候失敗。

3)、簽名花費時間長。這兩個簽名工具在生成簽名後的APK時,是按Zip中一個entry接一個entry 依次拷貝的,效率十分低。因為遊戲類型APK類檔案數量一般比較多,是以這一缺陷在簽名遊戲類型APK時,展現得尤為明顯。

2、極速簽名工具(ApkSinger)

極速簽名工具克服了signapk.jar與jarsigner在簽名過程的缺點,使用方法:

java -jar ApkSigner.jar [-appname test] -keystore keystorePath -alias alias [-pswd password] [-aliaspswd aliasPassword] apkPath(or directory)

-appname 待簽名的應用程式名,可選,但建議不同的APP填上對應的app名

-keystore 後跟.keystore簽名檔案

-alias 後跟簽名别名

-pswd 後跟對應簽名的密碼,可選,如果不填,則簽名的時候需要手動輸入

-aliaspswd 對應别名alias的密碼,如果沒有則預設使用keystore Password

最後跟待簽名的APK路徑或者目錄路徑 ,如果跟的是目錄則是批量簽名.

三、為何要這麼來簽名

上面我們就介紹了簽名apk之後的三個檔案的詳細内容,那麼下面來總結一下,Android中為何要用這種方式進行加密簽名,這種方加密是不是最安全的呢?下面我們來分析一下,如果apk檔案被篡改後會發生什麼。

首先,如果你改變了apk包中的任何檔案,那麼在apk安裝校驗時,改變後的檔案摘要資訊與MANIFEST.MF的檢驗資訊不同,于是驗證失敗,程式就不能成功安裝。

其次,如果你對更改的過的檔案相應的算出新的摘要值,然後更改MANIFEST.MF檔案裡面對應的屬性值,那麼必定與CERT.SF檔案中算出的摘要值不一樣,照樣驗證失敗。

最後,如果你還不死心,繼續計算MANIFEST.MF的摘要值,相應的更改CERT.SF裡面的值,那麼數字簽名值必定與CERT.RSA檔案中記錄的不一樣,還是失敗。

那麼能不能繼續僞造數字簽名呢?不可能,因為沒有數字證書對應的私鑰。

是以,如果要重新打包後的應用程式能再Android裝置上安裝,必須對其進行重簽名。

從上面的分析可以得出,隻要修改了Apk中的任何内容,就必須重新簽名,不然會提示安裝失敗,當然這裡不會分析,後面一篇文章會注重分析為何會提示安裝失敗。

[轉]Android APK簽名原理及方法