- 防止APK被除錯
- 加殼
- 程式碼混淆:
- 檢測偵錯程式:
- 使用反除錯技術:
- 環境檢測:
- 使用Native程式碼:
- 多層防護:
- 防止APK被篡改
- 簽名校驗:
- V1 簽名機制
- V2 簽名機制
- V3 簽名機制
- 動態完整性校驗:
- 簽名校驗:
想要保護APK應用內的程式碼邏輯安全,需要做一定的APK加固操作。加固的常見操作有:
- 混淆
- 加密
- 隱藏
- 檢測
- ...
如果採用第三方的加固服務,如360加固、騰訊樂固等,廠商無非是把一系列的混淆、加密、隱藏、檢測等技術組合起來,封裝好給你使用。
防止APK被除錯
加殼
APK包加殼是一種常見的應用保護方法,透過在APK包外層新增一層保護殼,以防止逆向工程和除錯。這種技術主要用於保護應用的程式碼和資源不被輕易破解和篡改。以下是APK包加殼的基本原理:
-
殼程式碼注入:
加殼工具會在原始APK包中注入殼程式碼。這個殼程式碼通常是一個啟動器,它在應用啟動時首先執行,負責初始化和解密真正的應用程式碼。 -
加密原始程式碼和資源:
原始APK包中的程式碼和資原始檔會被加密。加密演算法可以是對稱加密(如AES)或非對稱加密(如RSA),以確保只有殼程式碼能解密這些資源。 -
殼程式碼載入和解密:
當使用者啟動應用時,殼程式碼首先執行,它會解密原始APK包中的程式碼和資源,然後將解密後的程式碼載入到記憶體中執行。 -
動態載入:
解密後的程式碼通常不會寫回到磁碟上,而是直接載入到記憶體中執行。這種動態載入的方式可以防止靜態分析工具從磁碟上讀取解密後的程式碼。
程式碼混淆:
使用ProGuard
或R8
等工具對程式碼進行混淆,使反編譯後的程式碼難以理解。
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
檢測偵錯程式:
在執行時檢測偵錯程式的存在。如果檢測到偵錯程式,應用可以採取相應的操作,如退出或顯示警告。
public boolean isDebuggerConnected() {
return android.os.Debug.isDebuggerConnected();
}
if (isDebuggerConnected()) {
// Exit or handle the detection
System.exit(0);
}
使用反除錯技術:
利用各種反除錯技術,如檢測除錯埠、除錯標誌等。
public boolean isBeingDebugged() {
return (android.os.Debug.isDebuggerConnected() ||
android.os.Debug.waitingForDebugger());
}
if (isBeingDebugged()) {
// Exit or handle the detection
System.exit(0);
}
環境檢測:
檢測應用執行的環境是否正常,如判斷是否執行在模擬器上。
public boolean isEmulator() {
String brand = Build.BRAND;
String device = Build.DEVICE;
String model = Build.MODEL;
String product = Build.PRODUCT;
return (brand.startsWith("generic") || device.startsWith("generic") ||
model.contains("google_sdk") || model.contains("Emulator") ||
product.equals("sdk") || product.equals("sdk_google"));
}
if (isEmulator()) {
// Exit or handle the emulator detection
System.exit(0);
}
使用Native程式碼:
將關鍵程式碼移到本地(native)層,用C/C++編寫,並使用NDK編譯。這樣可以增加逆向工程的難度。
多層防護:
結合以上多種方法,建立多層次的防護體系,增加破解和除錯的難度。
防止APK被篡改
簽名校驗:
簽名就是給APK內的各個檔案Hash,達到被人二次打包的時候能發現,那麼原理是什麼?
Android應用的簽名機制經歷了多次演變,主要包括V1、V2和V3簽名方案。每一種簽名方式都有不同的特點和應用場景:
V1 簽名機制
已經被破解,是個不安全的簽名。
V1簽名(基於JAR簽名,全版本都相容)方式存在一些固有的缺陷,使得其在現代應用中被認為不夠安全。以下是V1簽名不安全的主要原因:
V1簽名工作原理:
V1簽名方式對APK包內的每個檔案進行單獨簽名,並將這些簽名資訊儲存在META-INF/MANIFEST.MF和META-INF/CERT.SF檔案中。
- MANIFEST.MF:包含每個檔案的雜湊值。
- CERT.SF:包含MANIFEST.MF檔案的雜湊值,並由開發者的私鑰簽名。
- CERT.RSA或CERT.DSA:包含簽名證書和簽名資訊。
安全問題
-
無法保證整體完整性:
V1簽名只對單個檔案進行簽名,而不是對整個APK檔案進行簽名。因此,攻擊者可以透過新增、刪除或替換APK中的檔案(如資原始檔或DEX檔案),而不會影響其他檔案的簽名完整性。
例如,攻擊者可以新增一個新的檔案到APK中,而這個檔案不會在MANIFEST.MF中被引用,從而繞過簽名驗證。 -
容易被重新打包:
攻擊者可以將APK檔案解包、修改內容(如替換某些檔案或新增惡意程式碼),然後重新打包並生成新的簽名。這種方式可以完全替換原始簽名,使使用者難以發現APK已被篡改。V1簽名方式的簽名資訊儲存在 CERT.SF 和 CERT.RSA 檔案中,這些檔案本身也可以被攻擊者修改或替換。
簽名檔案篡改:
如果簽名檔案(如CERT.SF和CERT.RSA)本身被錯誤地包含在簽名範圍內,那麼攻擊者可以透過篡改這些檔案,生成新的簽名資訊並替換原始簽名,從而使得原始簽名失效。
例如,攻擊者可以生成新的簽名證書和簽名資訊,替換CERT.RSA檔案,使得整個簽名驗證過程基於攻擊者的證書和簽名資訊。
V2 簽名機制
V2簽名(僅支援Android 7.0及以上版本)方案透過對整個APK檔案進行簽名,從而防止替換和篡改。它的工作原理如下:
-
整體簽名
V2簽名方案對整個APK檔案(除了簽名塊)進行簽名,確保APK的完整性。具體步驟如下:1.1 生成APK簽名塊:
- 建立一個簽名塊,包含APK中所有檔案的雜湊值及其他簽名資訊。簽名塊位於APK檔案的ZIP Central Directory
之前,且不包括在簽名計算範圍內。1.2. 計算APK主體的雜湊值:
- 計算APK主體(不包括簽名塊)的雜湊值。此雜湊值確保APK的內容在簽名後不能被篡改。1.3. 簽名資訊:
- 使用開發者的私鑰對上述雜湊值進行簽名,生成簽名資訊。該簽名資訊也儲存在簽名塊中。1.4. 簽名塊結構:
- 簽名塊包含簽名資訊、證書、公鑰等,保證簽名的完整性和可驗證性。 -
驗證過程
當裝置安裝APK檔案時,系統會進行以下驗證步驟:-
讀取簽名塊:
- 系統讀取APK檔案中的簽名塊,從簽名塊中提取簽名資訊、證書和公鑰。
-
驗證簽名:
- 使用簽名塊中的公鑰對簽名資訊進行驗證,確保簽名資訊是由對應的私鑰生成的。
-
驗證雜湊值:
- 計算APK主體(不包括簽名塊)的雜湊值,並與簽名塊中儲存的雜湊值進行比較,確保APK主體未被篡改。
-
驗證證書:
- 檢查簽名塊中的證書是否有效,並與應用商店或預期的證書進行比對,確保簽名的合法性。
-
防止替換和篡改的機制
V2簽名方案透過以下機制防止APK被替換或篡改:
-
整體雜湊值校驗:
- 由於V2簽名對整個APK檔案(不包括簽名塊)進行雜湊計算和簽名,任何對APK檔案的修改(例如增加、刪除或替換檔案)都會改變雜湊值,導致簽名驗證失敗。
-
簽名塊保護:
- 簽名塊位於APK檔案的
ZIP Central Directory
之前,且不包括在簽名計算範圍內,因此簽名塊本身不會被篡改。任何對簽名塊之外部分的修改都會破壞簽名完整性。
- 簽名塊位於APK檔案的
-
不可替換性:
- 簽名塊中的簽名資訊是由開發者的私鑰生成的,只有擁有對應私鑰的人才能生成有效的簽名。篡改者無法生成與原始簽名匹配的簽名資訊。
-
證書驗證:
- 簽名塊中的證書可以用來驗證簽名的合法性,確保簽名是由可信的開發者生成的。
V3 簽名機制
在V2的基礎上增加了版本控制和金鑰輪換功能,進一步增強了安全性,但僅支援Android 9.0及以上版本。
動態完整性校驗:
定期對程式碼和資料進行校驗,確保它們沒有被篡改。