Android打包、簽名與混淆

Android打包、簽名與混淆

前幾天實習上要打包出一個apk,而後上頭就發了我一個.keystore文件,叫我打包的時候用這個簽名。當時我在想啊,原來我只是在學習計算機網絡的時候瞭解公鑰、密鑰的區別,在複習https後又加深瞭解了一下,但總之這些都不是我直接接觸的,都是些理論知識瞭解而過,如今遇到了,我就在想Android的這個打包時爲啥要簽名?簽名不是應該存在於網絡傳輸中的嗎?java

原來才學習Android的時候作了個音樂的app,使用的是喜馬拉雅的SDK,其中引入後就叫你必須使用混淆,當時第一次接觸了混淆。後來反編譯過一些軟件,發現有些包名爲a,b...這樣的,才瞭解了下混淆的做用。android

這兩個知識點呢都是保證了咱們應用的安全,並且都是在打包的時候使用到的,我就把他們總結在了一塊兒去學習。c++

最後真的感謝我選擇了Android,咱們大學快結束了才學習了編譯原理、c++,當時我認爲這兩門課對咱們軟件的學生可能用處不大,由於大部分同窗走的方向都是java方向,當我開始作Android直播方向的畢設的時候,我感受學校開的全部課程都能聯繫起來了git

Android打包流程

在這裏插入圖片描述

圖爲典型的Android應用模塊的編譯流程 Android編譯流程的步驟:github

  1. 打包資源文件Resource Files,生成R.java文件(AAPT:Android Asset Packaging Tool)
  2. 處理AIDL文件,生成java代碼(AIDL:Android Interface Definition Language,實現進程間的通訊)
  3. 編譯代碼文件(Source code),生成對應的.class文件
  4. .class文件轉化爲dex文件
  5. 將dex文件和編譯的資源文件組合成成apk(apk-builder)
  6. 使用調試或發佈密鑰庫簽名(jarsigner)
  7. 應用優化,減小運行時佔用的內存(zipslign:歸檔對其工具 —> mmap內存映射 —> 減小運行時消耗的內存)

ps:算法

  • 若是您使用的是 apksigner,則只能在爲 APK 文件簽名以前執行 zipalign。若是您在使用 apksigner 爲 APK 簽名以後對 APK 進行進一步更改,則簽名將會失效。
  • 若是您使用的是 jarsigner,則只能在爲 APK 文件簽名以後執行 zipalign。

ps2:緩存

  • 咱們常常直接解壓一些apk的時候會發現有不少的classes.dex文件,默認的dex文件應該是一個的,可是每一個dex文件的方法數不能超過65535。咱們只要在glide下配置multiDexEnabled true就行了
    某解壓後的apk

簽名

平時呢咱們對這種初級開發者,一個應用誕生後,真的就是一個屬於本身的app了,通常就調試運行在本身的手機上,有些時候甚至還作不到多機型適配,出於炫耀等緣由,你可能會將你的app打包成apk,而後呢丟在一個服務器上,生成一個二維碼,發個朋友圈(別問我爲啥這麼清楚,問就是我有個朋友)。這種時候咱們徹底沒接觸到簽名啊。安全

當時的我認爲只要不發佈到各類應用商店就能夠不用簽名的,我上官方文檔查了下,發現了下面這段話:服務器

Android 系統要求全部 APK 必須先使用證書進行數字簽名,而後才能安裝到設備上或進行更新。網絡

咱們通常調試build出的apk都是app-debug.apk,按照上文的說法呢!系統應該是自動幫咱們進行了簽名,但簽名的文件呢?沒想到那麼好找,我一點開.android文件夾就看到了debug.keystore,沒錯這就是本機默認的數字簽名。

您首次在 Android Studio 中運行或調試項目時,IDE 會自動在 $HOME/.android/debug.keystore 中建立調試密鑰庫和證書,並設置密鑰庫和密鑰密碼。

官文中也能找到對應的解釋(並且還告訴了咱們在首次運行和調試的時候自動建立的,這就意味着你安裝IDE的時候是不存在的,也就是說每臺機器產生的調試密鑰庫和證書應該是不一樣的)

咱們查看下這裏面的內容:

嗯好,看完就到了解決最初問題的時候了。

簽名有什麼用?

官文中的簽名注意事項明確的告訴了咱們簽名的做用。

主要有如下三點:

  • 應用升級:當安裝應用的更新時,系統會比較新版本和現有版本中的證書。若是證書匹配,則系統容許更新。若是使用不一樣的證書爲新版本簽名,您必須爲應用分配另外一個軟件包名稱 - 在此狀況下,用戶會將新版本做爲全新應用進行安裝。
  • 應用模塊化:Android 容許經過同一證書籤名的多個 APK 在同一個進程中運行(若是應用請求這樣作),以便系統將其視爲單個應用。這樣一來,您即可以按模塊部署您的應用,而且用戶能夠獨立更新每一個模塊。
  • 經過權限共享代碼/數據:Android 提供了基於簽名的權限執行機制,以便一個應用能夠將功能提供給使用指定證書籤名的另外一個應用。經過使用同一個證書爲多個 APK 簽名並使用基於簽名的權限檢查功能,您的應用能夠採用安全的方式共享代碼和數據。

在實際的應用中呢,我遇到了這種狀況,當前的設備上已經安裝該應用的apk,但公司叫我從新開發了,我開發完成後直接使用app-debug.apk在設備上進行安裝,就出現了該錯誤。(解決方法一,卸載了原程序,再安裝,但這就將緩存的數據給清空了。這讓我想到了「明日方舟」,每次大的版本更新都要將原程序卸載了,安裝新的apk,安裝後得從新登陸)(解決方法二,將簽名一塊兒發給程序猿——咱們,打包的時候使用相同的簽名)

這就體現出了簽名最經常使用的做用之一「應用升級」。這也是我想了解簽名與寫下這篇博客的導火索之一。

簽名能保障apk的安全嗎?

回答這個問題呢,就須要去了解幾個名詞:

證書 公鑰證書(.der 或 .pem 文件,也稱爲數字證書或身份證書)包含公鑰/私鑰對中的公鑰,以及能夠標識持有對應私鑰的全部者的一些其餘元數據(例如名稱和位置)。

在爲您的應用簽名時,簽名工具會將該證書附加到應用。該證書會將 APK 或 app bundle 與您和您對應的私鑰相關聯。這有助於 Android 確保您應用往後的全部更新都真實可靠,而且來自原始做者。用於建立此證書的密鑰稱爲應用簽名密鑰

您能夠從 Play 管理中心的「應用簽名」頁面下載您的應用簽名密鑰和上傳密鑰的證書,以便向 API 提供商註冊您的密鑰。您能夠與任何人共享該證書。它不包含您的私鑰。

每一個應用在其整個生命週期內必須使用同一證書,以便用戶可以以應用更新的形式安裝新版本。要詳細瞭解讓全部應用在其整個生命週期內使用同一證書的好處,請參閱上面的簽名注意事項

證書指紋是證書獨一無二的簡短表示形式,一般 API 提供商會要求同時提供證書指紋和軟件包名稱,以註冊使用其服務的應用。您能夠在 Play 管理中心的「應用簽名」頁面上找到上傳證書和應用簽名證書的 MD五、SHA-1 和 SHA-256 指紋。您還能夠從同一頁面下載原始證書 (.der) 來計算其餘指紋。

如下是您應該瞭解的不一樣類型的密鑰和密鑰庫:

  • 應用簽名密鑰:用於爲用戶設備上安裝的 APK 簽名的密鑰。做爲 Android 安全更新模型的一部分,應用簽名密鑰在應用的整個生命週期內保持不變。應用簽名密鑰屬於私鑰,所以必須保密。不過,您能夠與他人共享使用應用簽名密鑰生成的證書。

  • 上傳密鑰:在爲 Google Play 應用簽名計劃上傳 app bundle 或 APK 以前用於爲其簽名的密鑰。您必須爲上傳密鑰保密。不過,您能夠與他人共享使用上傳密鑰生成的證書。您能夠經過如下某種方式生成上傳密鑰:

    • 若是要讓 Google 在您選擇加入計劃時爲您生成應用簽名密鑰,則您用於爲應用簽名以進行發佈的密鑰將被指定爲上傳密鑰。
    • 若是您在將新應用或現有應用加入計劃時向 Google 提供應用簽名密鑰,則能夠在選擇加入計劃的過程當中或以後生成新的上傳密鑰,以提升安全性。
    • 若是您沒有生成新的上傳密鑰,則繼續將您的應用簽名密鑰用做上傳密鑰來爲每一個版本簽名。
    • 提示:爲了讓您的密鑰安全無虞,最好確保應用簽名密鑰和上傳密鑰不一樣。
  • Java 密鑰庫(.jks 或 .keystore):一個二進制文件,用做證書和私鑰的存儲區。

  • Play Encrypt Private Key (PEPK) 工具:使用此工具可從 Java 密鑰庫中導出私鑰,並對私鑰加密以便傳輸到 Google Play。在提供應用簽名密鑰以供 Google 使用時,請選擇從 Java 密鑰庫導出並上傳密鑰選項,並按說明下載和使用此工具。或者,您也能夠選擇導出並上傳密鑰(不使用 Java 密鑰庫)選項,如下載、查看和使用 PEPK 工具的開放源代碼。

(以上都是官文對應用簽名要掌握的知識點的概述——原文引用來自密鑰、證書和密鑰庫

經過上文能夠總結出:Android簽名機制不能阻止APK包被修改,但修改後的再簽名沒法與原先的簽名保持一致(除非你擁有私鑰)。也就是說若是你的軟件仍是會被反編譯的,但其餘人反編譯後再打包的話實際上是另外一個應用。(好比咱們原來玩的諾基亞小遊戲的時候常常會有些是漢化版,而後咱們下下來是不會替換掉原來的程序,我就想起當時玩一個叫「上古2」的網遊,下了個雙開的版本,如今才知道原來那個被破解了而後從新打包的應用啊)

綜上所述:簽名機制實際上是對APK包完整性和發佈機構惟一性的一種校驗機制。能簡單的保證apk的安全,但頗有限,應該說是一個軟件最基本的防護。咱們能夠適當的提高下安全係數,在程序運行的時候進行簽名對比,但被破解後,讓程序跳過簽名對比的部分,就能破壞了這最基本的防護。

簽名的原理:咱們能夠看debug.keystore中寫了簽名算法名稱:SHA1withRSA。 能夠得出該apk是使用SHA1-RSA算法,用私鑰進行簽名的。

SHA-1:是一種密碼散列函數,雖然該密碼如今已經不夠安全了,但還在被普遍的使用。它把任意長度的輸入,經過散列算法變成固定長度的輸出。

RSA:是一種非對稱加密算法。用私鑰經過RSA算法對SHA-1的輸出信息進行加密。

在安裝時只能使用公鑰才能解密RSA加密後的信息。解密以後,將它與SHA-1的輸出信息進行對比,若是相符,則代表內容沒有被異常修改。

混淆

混淆處理:縮短類和成員的名稱,從而減少 DEX 文件的大小。

混淆處理的目的是經過縮短應用的類、方法和字段的名稱來減少應用的大小。

雖然混淆處理不會從應用中移除代碼,但若是應用的 DEX 文件將許多類、方法和字段編入索引,那麼混淆處理將能夠顯著縮減應用的大小。 不過,因爲混淆處理會對代碼的不一樣部分進行重命名,所以在執行某些任務(如檢查堆棧軌跡)時須要用到額外的工具。

此外,若是您的代碼依賴於應用的方法和類的可預測命名( 例如,使用反射時),您應該將相應簽名視爲入口點併爲其指定保留規則。

能夠獲得混淆的目的就是縮小應用的大小,但不少地方都說混淆能夠保護代碼的安全,由於他下降了代碼的可讀性,讓反編譯後的破解得花費一些時間。這雖然可能不是混淆出現的目的之一,但人們將他活學活用了,發現了它另外的價值。

混淆是不可逆的,在混淆的過程當中一些不影響正常運行的信息將永久丟失,這些信息的丟失使程序變得更加難以理解。

我曾經由於以爲某app的某功能實現效果特別好,而後將其反編譯後,發現混淆真的頗有用,可能應爲我看小說就幾個名字看了一半後都除了主角,其餘人都對不上號吧,常常還倒回去找下這我的是誰?(要是他是英文的名字,我更加記不住了,可能都不會回去找,這種狀況就須要一張紙寫下相應名字間的關係一塊兒夾在書裏了,這可能也算「混淆」吧)

總結

最後呢!就是市面上應該沒有一款軟件是100%安全的,只是他們的加密手段複雜可能還會隨時間修改,破解它多是成本問題。

再最後呢!PC上的反編譯軟件你們都很熟悉(apktool + dex2jar + jd-gui)

手機上呢我挺喜歡一款叫「開發助手」的軟件的(好像是某滴滴大佬開發的),能看應用佈局、屏幕取色、app用的什麼加密軟件等等,功能性我的認爲比「MT管理器」要好吧。

Android studio 中咱們可使用 build -> Analyze APK... 去分析apk,而後去進一步優化咱們apk的大小。

相關文章
相關標籤/搜索