【Android 安全】DEX 加密 ( 代理 Application 開發 | 加密解密演算法 API | 編譯代理 Application 依賴庫 | 解壓依賴庫 aar 檔案 )
參考部落格 :
- 【Android 安全】DEX 加密 ( 常用 Android 反編譯工具 | apktool | dex2jar | enjarify | jd-gui | jadx )
- 【Android 安全】DEX 加密 ( Proguard 簡介 | Proguard 相關網址 | Proguard 混淆配置 )
- 【Android 安全】DEX 加密 ( Proguard 簡介 | 預設 ProGuard 分析 )
- 【Android 安全】DEX 加密 ( Proguard keep 用法 | Proguard 預設混淆結果 | 保留類及成員混淆結果 | 保留註解以及被註解修飾的類/成員/方法 )
- 【Android 安全】DEX 加密 ( Proguard 混淆 | 混淆後的報錯資訊 | Proguard 混淆對映檔案 mapping.txt )
- 【Android 安全】DEX 加密 ( Proguard 混淆 | 將混淆後的報錯資訊轉為原始報錯資訊 | retrace.bat 命令執行目錄 | 暴露更少資訊 )
- 【Android 安全】DEX 加密 ( DEX 加密原理 | DEX 加密簡介 | APK 檔案分析 | DEX 分割 )
- 【Android 安全】DEX 加密 ( 多 DEX 載入 | 65535 方法數限制和 MultiDex 配置 | PathClassLoader 類載入原始碼分析 | DexPathList )
- 【Android 安全】DEX 加密 ( 不同 Android 版本的 DEX 載入 | Android 8.0 版本 DEX 載入分析 | Android 5.0 版本 DEX 載入分析 )
- 【Android 安全】DEX 加密 ( DEX 加密使用到的相關工具 | dx 工具 | zipalign 對齊工具 | apksigner 簽名工具 )
- 【Android 安全】DEX 加密 ( 支援多 DEX 的 Android 工程結構 )
- 【Android 安全】DEX 加密 ( 代理 Application 開發 | multiple-dex-core 依賴庫開發 | 配置後設資料 | 獲取 apk 檔案並準備相關目錄 )
- 【Android 安全】DEX 加密 ( 代理 Application 開發 | 解壓 apk 檔案 | 判定是否是第一次啟動 | 遞迴刪除檔案操作 | 解壓 Zip 檔案操作 )
- 【Android 安全】DEX 加密 ( 代理 Application 開發 | 載入 dex 檔案 | 反射獲取系統的 Element[] dexElements )
- 【Android 安全】DEX 加密 ( 代理 Application 開發 | 載入 dex 檔案 | 使用反射獲取方法建立本應用的 dexElements | 各版本建立 dex 陣列原始碼對比 )
- 【Android 安全】DEX 加密 ( 代理 Application 開發 | 載入 dex 檔案 | 將系統的 dexElements 與 應用的 dexElements 合併 | 替換操作 )
在 【Android 安全】DEX 加密 ( 支援多 DEX 的 Android 工程結構 ) 部落格中介紹了 DEX 加密工程的基本結構 ,
app 是主應用 , 其 Module 型別是 “Phone & Tablet Module” ,
multiple-dex-core 是 Android 依賴庫 , 其作用是解密並載入多 DEX 檔案 , 其 Module 型別是 “Android Library” ,
multiple-dex-tools 是 Java 依賴庫 , 其型別是 “Java or Kotlin Library” , 其作用是用於生成主 DEX ( 主 DEX 的作用就是用於解密與載入多 DEX ) , 並且還要為修改後的 APK 進行簽名 ;
在 【Android 安全】DEX 加密 ( 代理 Application 開發 | multiple-dex-core 依賴庫開發 | 配置後設資料 | 獲取 apk 檔案並準備相關目錄 ) 部落格中講解了 multiple-dex-core 依賴庫開發 , 每次啟動都要解密與載入 dex 檔案 , 在該部落格中講解到了 獲取 apk 檔案 , 並準備解壓目錄 ;
在 【Android 安全】DEX 加密 ( 代理 Application 開發 | 解壓 apk 檔案 | 判定是否是第一次啟動 | 遞迴刪除檔案操作 | 解壓 Zip 檔案操作 ) 部落格中講解了 apk 檔案解壓操作 ;
在 【Android 安全】DEX 加密 ( 代理 Application 開發 | 載入 dex 檔案 | 反射獲取系統的 Element[] dexElements )部落格中講解了 dex 檔案載入第一階段 , 獲取系統中的 Element[] dexElements ;
在 【Android 安全】DEX 加密 ( 代理 Application 開發 | 載入 dex 檔案 | 使用反射獲取方法建立本應用的 dexElements | 各版本建立 dex 陣列原始碼對比 ) 部落格中講解了講解 dex 檔案載入操作 第二階段 , 建立本應用的 dex 檔案陣列 Element[] dexElements ;
在 【Android 安全】DEX 加密 ( 代理 Application 開發 | 載入 dex 檔案 | 將系統的 dexElements 與 應用的 dexElements 合併 | 替換操作 ) 部落格中講解了剩餘的兩個操作 :
- 將 系統載入的 Element[] dexElements 陣列 與 我們 自己的 Element[] dexElements 陣列 進行合併操作 ;
- 替換 ClassLoader 載入過程中的 Element[] dexElements 陣列 ( 封裝在 DexPathList 中 )
本部落格中介紹 加密解密演算法 API , 編譯代理 Application 依賴庫 , 解壓依賴庫 aar 檔案 ;
一、加密解密演算法 API
先寫一個加密解密演算法 , 該演算法用於 dex 檔案的 加密 / 解密 操作 ;
初始化 加密 / 解密 演算法 : 根據演算法型別 , 初始化 加密 / 解密 演算法 ;
/**
* 加密解密演算法型別
*/
val algorithm = "AES/ECB/PKCS5Padding"
// 初始化加密演算法
encryptCipher = Cipher.getInstance(algorithm)
設定金鑰 : 獲取金鑰的 Byte 陣列型別 , 並建立 AES 金鑰 ;
// 將金鑰字串轉為位元組陣列
var keyByte = pwd.toByteArray()
// 建立金鑰
val key = SecretKeySpec(keyByte, "AES")
設定演算法型別及金鑰 : 加密演算法 , 傳入 Cipher.ENCRYPT_MODE 引數 , 解密演算法 , 傳入 Cipher.DECRYPT_MODE 引數 ;
// 設定演算法型別, 及金鑰
encryptCipher.init(Cipher.ENCRYPT_MODE, key);
// 設定演算法型別, 及金鑰
decryptCipher.init(Cipher.DECRYPT_MODE, key);
完整程式碼示例 :
class AES {
/**
* 加密金鑰, 16 位元組
*/
val DEFAULT_PWD = "kimhslmultiplede"
/**
* 加密解密演算法型別
*/
val algorithm = "AES/ECB/PKCS5Padding"
/**
* 加密演算法, 目前本應用中只需要加密, 不需要解密
*/
lateinit var encryptCipher: Cipher;
/**
* 解密演算法
*/
lateinit var decryptCipher: Cipher;
@ExperimentalStdlibApi
constructor(pwd: String){
// 初始化加密演算法
encryptCipher = Cipher.getInstance(algorithm)
// 初始化解密演算法
decryptCipher = Cipher.getInstance(algorithm)
// 將金鑰字串轉為位元組陣列
var keyByte = pwd.toByteArray()
// 建立金鑰
val key = SecretKeySpec(keyByte, "AES")
// 初始化加密演算法
encryptCipher.init(Cipher.ENCRYPT_MODE, key);
// 初始化解密演算法
decryptCipher.init(Cipher.DECRYPT_MODE, key);
}
/**
* 加密操作
*/
fun encrypt(contet : ByteArray) : ByteArray{
var result : ByteArray = encryptCipher.doFinal(contet)
return result
}
/**
* 解密操作
*/
fun decrypt(contet : ByteArray) : ByteArray{
var result : ByteArray = decryptCipher.doFinal(contet)
return result
}
}
二、編譯代理 Application 依賴庫
生成 dex 檔案 , 該 dex 檔案中只包含解密 其它 dex 的功能
編譯配置 : 在 選單欄 / File / Setting / Build, Execution, Deployment / Compiler 設定介面中 ,
勾選 Compile independent modules in parallel (may require larger ) 選項 ;
編譯工程 : 編譯工程時會生成 Android 依賴庫的 aar 檔案 , 生成目錄是 module/build/outputs/aar/ 目錄下
獲取 multiple-dex-core-debug.aar 檔案的另外一種方法 : 執行 Gradle 任務中的 Tasks/other/assembleDebug 任務 , 即可生成 multiple-dex-core-debug.aar 檔案 ;
解壓獲取檔案 ( 僅做參考 ) : 將
D:\002_Project\002_Android_Learn\DexEncryption\multiple-dex-core\build\outputs\aar
路徑下的 multiple-dex-core-debug.aar 檔案字尾修改為 .zip
解壓上述檔案 , 拿到 classes.jar 檔案即可 ;
該 classes.jar 就是 multiple-dex-core 的 Android 依賴庫中的 ProxyApplication.kt Kotlin 檔案 編譯出的 jar 包 ;
上述 解壓檔案僅做 參考 , 實際使用時 , 在程式中使用程式碼解壓 ;
三、解壓代理 Application 依賴庫 aar 檔案
獲取 multiple-dex-core-debug.aar 檔案物件
// 獲取 multiple-dex-core-debug.aar 檔案物件
var aarFile = File("multiple-dex-core/build/outputs/aar/multiple-dex-core-debug.aar")
解壓上述 multiple-dex-core-debug.aar 檔案到 aarUnzip 目錄中 , 先建立解壓目錄 ;
// 解壓上述 multiple-dex-core-debug.aar 檔案到 aarUnzip 目錄中
// 建立解壓目錄
var aarUnzip = File("multiple-dex-tools/aarUnzip")
正式解壓 , unZipAar 方法在下面完整程式碼中 ;
// 解壓操作
unZipAar(aarFile, aarUnzip)
拿到 multiple-dex-core-debug.aar 中解壓出來的 classes.jar 檔案
// 拿到 multiple-dex-core-debug.aar 中解壓出來的 classes.jar 檔案
var classesJarFile = File(aarUnzip, "classes.jar")
完整程式碼示例 :
fun main() {
/*
1 . 生成 dex 檔案 , 該 dex 檔案中只包含解密 其它 dex 的功能
編譯工程
會生成 Android 依賴庫的 aar 檔案
生成目錄是 module/build/outputs/aar/ 目錄下
前提是需要在 選單欄 / File / Setting / Build, Execution, Deployment / Compiler
設定介面中 , 勾選 Compile independent modules in parallel (may require larger )
將 D:\002_Project\002_Android_Learn\DexEncryption\multiple-dex-core\build\outputs\aar
路徑下的 multiple-dex-core-debug.aar 檔案字尾修改為 .zip
解壓上述檔案
拿到 classes.jar 檔案即可 ;
*/
// 獲取 multiple-dex-core-debug.aar 檔案物件
var aarFile = File("multiple-dex-core/build/outputs/aar/multiple-dex-core-debug.aar")
// 解壓上述 multiple-dex-core-debug.aar 檔案到 aarUnzip 目錄中
// 建立解壓目錄
var aarUnzip = File("multiple-dex-tools/aarUnzip")
// 解壓操作
unZipAar(aarFile, aarUnzip)
// 拿到 multiple-dex-core-debug.aar 中解壓出來的 classes.jar 檔案
var classesJarFile = File(aarUnzip, "classes.jar")
}
/**
* 刪除檔案, 如果有目錄, 則遞迴刪除
*/
private fun deleteFile(file: File) {
if (file.isDirectory) {
val files = file.listFiles()
for (f in files) {
deleteFile(f)
}
} else {
file.delete()
}
}
/**
* 解壓檔案
* @param zip 被解壓的壓縮包檔案
* @param dir 解壓後的檔案存放目錄
*/
fun unZipAar(zip: File, dir: File) {
try {
// 如果存放檔案目錄存在, 刪除該目錄
deleteFile(dir)
// 獲取 zip 壓縮包檔案
val zipFile = ZipFile(zip)
// 獲取 zip 壓縮包中每一個檔案條目
val entries = zipFile.entries()
// 遍歷壓縮包中的檔案
while (entries.hasMoreElements()) {
val zipEntry = entries.nextElement()
// zip 壓縮包中的檔名稱 或 目錄名稱
val name = zipEntry.name
// 如果 apk 壓縮包中含有以下檔案 , 這些檔案是 V1 簽名檔案儲存目錄 , 不需要解壓 , 跳過即可
if (name == "META-INF/CERT.RSA" || name == "META-INF/CERT.SF" || (name
== "META-INF/MANIFEST.MF")
) {
continue
}
// 如果該檔案條目 , 不是目錄 , 說明就是檔案
if (!zipEntry.isDirectory) {
val file = File(dir, name)
// 建立目錄
if (!file.parentFile.exists()) {
file.parentFile.mkdirs()
}
// 向剛才建立的目錄中寫出檔案
val fileOutputStream = FileOutputStream(file)
val inputStream = zipFile.getInputStream(zipEntry)
val buffer = ByteArray(1024)
var len: Int
while (inputStream.read(buffer).also { len = it } != -1) {
fileOutputStream.write(buffer, 0, len)
}
inputStream.close()
fileOutputStream.close()
}
}
// 關閉 zip 檔案
zipFile.close()
} catch (e: Exception) {
e.printStackTrace()
}
}
相關文章
- 交叉編譯庫依賴問題的解決方法編譯
- 快取依賴(檔案、資料庫)快取資料庫
- Android開發好用的依賴庫和工具收集Android
- rimraf 命令強制刪除依賴庫檔案
- Android studio 匯入依賴庫Android
- 不要依賴Mock庫 - ErwinMock
- Rustyinject是Rust的編譯時依賴注入DI庫Rust編譯依賴注入
- 反射,註解,動態代理,依賴注入控制反轉反射依賴注入
- 如何發現Python依賴庫漏洞Python
- 如何對 Android 庫進行依賴管理?Android
- [譯] 依賴注入?? 哈??依賴注入
- Android Gradle 依賴配置:implementation & apiAndroidGradleAPI
- 依賴管理和依賴範圍
- 依賴引入 | Android依賴引入史上最全攻略Android
- Yarn 的Application 的依賴檔案和包是如何上傳下載和使用的YarnAPP
- 依賴
- [KubernetesClient | 底層依賴庫]client
- 使用 Swift Package Manager 整合依賴庫SwiftPackage
- 【資料庫之函式依賴】資料庫函式
- requirements.txt 檔案宣告依賴UIREM
- 依賴倒置(DIP)與依賴注入(DI)依賴注入
- 在iOS專案中依賴Flutter Module-③本地podspec中轉依賴遠端Flutter編譯產物iOSFlutter編譯
- 依賴注入?依賴注入是如何實現解耦的?依賴注入解耦
- android引入依賴,合集Android
- 一個專案 兩個cgo依賴編譯不通過Go編譯
- Golang 依賴注入設計哲學|12.6K 🌟 的依賴注入庫 wireGolang依賴注入
- maven依賴jar包更新,業務jar需同步更新(業務jar依賴API)MavenJARAPI
- Leptonica在VS2010中的編譯一,編譯它依賴於庫編譯
- 編譯OpenVPN及解決相關依賴問題編譯
- Maven依賴管理:控制依賴的傳遞Maven
- Maven依賴範圍及依賴傳遞Maven
- 動態庫遞迴依賴專項遞迴
- [譯]javascript中的依賴注入JavaScript依賴注入
- 前端彙總系列:npm依賴(構建編譯)前端NPM編譯
- Android下檢視SO庫被依賴的情況Android
- iOS開發: CocoaPods遠端私有倉庫的維護-新增依賴庫iOS
- 文盤Rust -- 本地庫引發的依賴衝突Rust
- AI依賴算力,而算力依賴能源AI