1. 程式人生 > >Android-專案中採用的混淆加固多渠道打包方案

Android-專案中採用的混淆加固多渠道打包方案

前言

當我們萬分努力將專案開發完成之後,提交最後一行程式碼後,會怎麼樣?
長舒一口氣,終於完成了,給自己放一天假,休息一下吧?

不,還沒完,作為一個 Android 開發者,我們接下來做的事情還有不少呢。

第一步 :混淆和加固應用

實不相瞞,我之前從未對我的應用加固過,因為我感覺使用者量不是太大,也不會有人有興趣來反編譯或者攻擊。直到我看到這一句話:

當用戶使用你的應用的那一刻起,作為開發者,你就有責任去保證應用使用整個過程中的使用者裝置和資訊的安全。

回想之前,覺得自己真的好爛,從現在開始,我想成為一個負責任的開發者。

第二步:打各種渠道包,看吶,這百花齊放的應用市場。

因為偉大的牆,沒有了 Google Play ,但是我們收穫了一大片森林,多少個渠道包,取決於我們的運營是有多大的野心,一般情況下,幾十個是少不了的。

混淆和加固的區別

首先要明確的,混淆和加固是兩個非常不同的概念。(明確的原因,在於我之前就傻傻的以為混淆和加固是一回事,掩面羞愧逃~ )

混淆,是一種類似障眼法的作用,讓反編譯後的程式碼閱讀難度增加,本質上來說,並非是防止了反編譯,而是增加了閱讀難度。例如將要混淆類名和函式名,替換為無意義的短名稱,(OrderUtils. createOrder() -> A.b() )。

加固,可以理解為,將APK的外層加了一層殼,如果想反編譯,必須突破這層殼的保護。加固後的APK,反編譯出來,看到的只是外面那層殼的程式碼。加固涉及到的技術手段就很多了,同時也非常的深奧,例如dex 檔案加密和位元組碼變形等。

混淆

開啟混淆很簡單

說到混淆吧,沒用過混淆的人,看到混淆的那些關鍵字,估計都和我之前一樣,簡直一臉懵,但是混淆過的我,告訴你們,完全不要害怕,混淆的道理真的很簡單。

混淆,主要包括三個部分,資源壓縮,程式碼混淆和程式碼壓縮。

  • 資源壓縮
    主要壓縮的是物件是專案 res 和 asset 檔案下未被引用的資原始檔。這個工作是通過 Gradle 的 Android 外掛去實現,預設資源壓縮是關閉的,我們在 build.gradle 中可以通過 shrinkResources true 來開啟。

  • 程式碼壓縮和程式碼混淆
    上面針對的是資源,這個針對的就是程式碼檔案了。這個方面,有一個在專門做 Java 位元組碼混淆的工具 ProGuard ,使用起來非常方便,是不是很開心?更開心的是 Android Studio 2.0 之後已經整合 ProGuard,我們再次可以通過在 build.gradle 中通過 minifyEnabled true

    就可以開啟混淆了。

所以 build.gradle 中新增短短的三行程式碼,專案打包 release 包就已經是混淆後的包了。

buildTypes {
        release {
            minifyEnabled true  //開啟混淆和程式碼壓縮
            shrinkResources true //開啟資源壓縮
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

這裡注意 shrinkResources true 在 minifyEnabled true 的前提下,才會生效。因為需要程式碼壓縮,釋放掉無用資源的引用,資源壓縮才能正常工作。

思考->為什麼需要自定義規則,不能自動混淆好嗎?

這是上面混淆三行程式碼的中最長的一句:

//混淆規則的檔案
 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

上面程式碼中有涉及到兩個檔案,其中
proguard-android.txt 是 Android SDK 提供的預設混淆檔案,裡面有 Android 應用通用的一些混淆規則,位置在 sdk/tools/proguard/ 中,這個檔案不需要我們修改,預設就好。

proguard-rules.pro 是專案的混淆檔案,提供給開發者,用來編寫自定義的混淆規則,這個檔案,才是我們做混淆工作的主戰場。

寫之前,需要明確的是,我們為什麼要在 proguard-rules.pro中自定義規則?

這個需要明白兩個問題

1.ProGuard 是怎麼做到混淆的?

壓縮: 移除無效的類、屬性、方法等
優化: 優化位元組碼,並刪除未使用的結構
混淆: 將類名、屬性名、方法名混淆為難以讀懂的字母,比如a,b,c

2.ProGuard 混淆的範圍?是全部的類嗎?

ProGuard 是一個優化 Java 位元組碼的工具,也就是說,只要是Java檔案都會被混淆。
但是這並不是我們想要的結果,因為有些類,如果被混淆就會出現問題,舉個例子,佈局中有一個 button 的 android: onClick 引用了 Activity MainActivity 中的方法 buttonClick()。混淆之後,佈局檔案是 .xml 檔案不會被混淆,保持不變,Activity類是 .java 檔案,會被混淆 ,MainActivity 被混淆成 A,buttonClick()被混淆成 b()。然後,讓我們點選 button ,觸發 onClick ,找不到 MainActivity.buttonClick(),是不是就會報錯了,乾脆利落地 Crash 了。

造成這個結果的原因是,ProGuard 並不是專門用來優化 Android 應用的一個工具,所以它並不知道什麼該混淆,什麼不該混淆。

混淆規則的制訂,更多的是一種保護,告訴 ProGuard 某些類某些方法不用混淆。

proguard-android.txt 中預設的一些規則,就是針對所有的 Android 專案都適用的混淆規則。

例如:

#包名不混合大小寫
-dontusemixedcaseclassnames

#不跳過非公共的庫的類
-dontskipnonpubliclibraryclasses

#混淆時記錄日誌
-verbose

#關閉預校驗
-dontpreverify

#不優化輸入的類檔案
-dontoptimize

#保護註解
-keepattributes *Annotation*

//等等,全部內容請自己去看sdk/tools/proguard/proguard-android.txt

由於每個專案的情況都不一樣,所以 專案中 proguard-rules.pro 的檔案,就是留給開發者根據自身專案情況,去設定混淆規則的。可謂是非常人性化。

混淆的99%工作->編寫自定義混淆規則

自定義混淆規則檔案 proguard-rules.pro 的內容可以分為三個部分:

  • 一些前輩們總結的,一般專案都會用到的混淆規則
  • 第三方庫的混淆規則 ,這個第三方文件上都有。
  • 如果有使用ORM型別的資料庫,例如greenDao,需要保護對映資料表的實體類不被混淆
  • 保護 JNI 中呼叫的類不被混淆。
  • 保護 WebView 中 JavaScript 呼叫的方法不被混淆
  • 保護 Layout 佈局使用的View建構函式、android:onClick等不被混淆。

關於怎麼保護,這個按照 ProGuard 制訂規則去保護了,關鍵詞很多,而且視專案不同,混淆檔案一般也不一樣,我也沒法給你提供一個模板什麼。

你可以看這篇文章 寫給 Android 開發者的混淆使用手冊,寫的超級詳細超級棒,我就是看這個學會的混淆。

加固

加固這方面的技術要求太高了,沒有特別的安全需求的話,都會選擇第三方加固平臺,公司專案採用的是梆梆加固

梆梆加固的使用方式很簡單,上傳 apk 包,點選加固,等待加固完畢,當加固成功後,會得到一個評估報告,要仔細閱讀一下,檢視是否由程式碼上可修改的漏洞等,如果有,修改後再加固,然後,下載加固後的加固包即可。

多渠道打包

只要是需要分發到各大市場的應用,多渠道的統計必不可少,因此多渠道打包必不可少,公司專案採用多渠道打包工具是 PackerNg。

PackerNgV2 提供 gradle 整合打包和指令碼打包,因為我們需要加固,所以選擇指令碼打包方式。具體步驟可以看 PackerNg的文件

完整打包流程

基本的打包流程如下:

這裡寫圖片描述

注意看,除了上面介紹的部分,多了一個重新簽名的步驟。

因為當加固之後的 Apk 沒有簽名,需要我們重新簽名。自動簽名的工具有很多,包括梆梆加固都有提供再簽名的工具,使用這些簽名之後PackerNg 指令碼打包後會出現 Error: Invalid Signature 錯誤。原因是現在提供的工具大多隻支援了 V1 簽名,而專案整合的 PackerNg 最新版本需要 V2 簽名,所以我們要給 Apk 重新籤 V2 簽名。

命令如下:

zipalign -v 4 <apk_path> <after_apk_path>//對齊
apksigner sign --ks <keystore_path> <after_apk_path> //重新簽名

//以下命令可用來驗證對齊和再簽名的結果
zipalign -c -v 4 <apk_path>//驗證是否對齊 
apksigner verify --verbose  <after_apk_path>  //檢視簽名信息,用來驗證是否是 V2 簽名

其中
apksigner 是Android SDK 自24.0.3開始提供的官方簽名工具,位於:Android SDK/build-tools/對應版本/apksigner。

zipalign 是 Android SDK 提供程式碼對齊工具, 位於 Android SDK/build-tools/對應版本/zipalign。

如果已經配置好 sdk/build-tools/的 Path,直接在 Terminal 中,任何路徑下就能使用,如果沒有可以選擇是配置一下路徑或者切換到 sdk/build-tools/ 對應版本/ 中操作。

最後

真的很感嘆,我也終於自己完整的走通了一個專案到釋出市場的一整套流程,現在做完之後,看起來一切都很簡單,步驟也不是很多,但是對於上週的我來說,因為對混淆和加固的知之甚少,真的膽戰心驚的去做這件事情,混淆之後安裝測試,簽名之後安裝測試等等,因為約了百度的首發,上線時間有限制,真的害怕搞出來自己短時間內無法解決的問題。

我仔細想想,當時的緊張,都是對未知的恐懼。例如,簽名遇到問題了,才知道 Android 7.0 新出了 V2 簽名機制等,因為沒用過,也測了又測,直到放心。

在這個知識的海洋裡,我知道的真是太少了,努力加油吧,為了以能夠自信多一點點。


歡迎關注博主的微信公眾號,快快加入哦,期待與你一起成長!