【Android 安全】DEX 加密 ( 代理 Application 开发 | 解压 apk 文件 | 判定是否是第一次启动 | 递归删除文件操作 | 解压 Zip 文件操作 )
文章目錄
- 一、判定是否是第一次啟動
- 二、遞歸刪除文件操作
- 三、解壓 Zip 文件操作
- 四、解壓操作相關代碼
參考博客 :
- 【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 加密 ( 支持多 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 文件 , 并準備解壓目錄 ;
本博客中主要講解 解壓 dex 文件操作 ;
一、判定是否是第一次啟動
應用啟動后 , 獲取 apk 文件 , 解壓該文件 , 并 解密其中的 dex 文件 , 然后進行 加載 ;
應用每次啟動前 , 都要執行上述操作 ;
現在討論解壓文件的細節操作 ;
如果應用是 第一次啟動 , 則需要解壓該 apk 文件 , 并進行解密 ;
如果應用 不是第一次啟動 , 則直接獲取之前已經 解壓 apk 并解密好的 dex 文件即可 ;
先獲取 dexDir 目錄中的文件 , 該目錄的作用是存 解壓后 并 解密 的 dex 文件 ;
// app 中存放的是解壓后的所有的 apk 文件// app 下創建 dexDir 目錄 , 將所有的 dex 目錄移動到該 deDir 目錄中// dexDir 目錄存放應用的所有 dex 文件// 這些 dex 文件都需要進行解密var dexDir : File = File(appDir, "dexDir")// 遍歷解壓后的 apk 文件 , 將需要加載的 dex 放入如下集合中var dexFiles : ArrayList<File> = ArrayList<File>()如果該 dexDir 目錄不存在 , 并且獲取的目錄子元素數組大小為 000 , 說明這是第一次啟動 ;
// 如果該 dexDir 存在 , 并且該目錄不為空 , 并進行 MD5 文件校驗if( !dexDir.exists() || dexDir.list().size == 0){// 將 apk 中的文件解壓到了 appDir 目錄}else{// 已經解密完成, 此時不需要解密, 直接獲取 dexDir 中的文件即可}}二、遞歸刪除文件操作
解壓的目標目錄 , 如果存在 , 則閃出去該目錄 , 注意 遞歸刪除 其 子目錄 中的文件 ; ( 該方法一般情況下不會調用 )
/*** 刪除文件, 如果有目錄, 則遞歸刪除*/private fun deleteFile(file: File) {if (file.isDirectory) {val files = file.listFiles()for (f in files) {deleteFile(f)}} else {file.delete()}}三、解壓 Zip 文件操作
解壓操作主要使用 java.util.zip 包下的 api ;
首先 創建 zip 文件 , 獲取 zip 文件中的條目 ;
在最后解壓完畢后 , 關閉該 zip 文件 ;
// 獲取 zip 壓縮包文件val zipFile = ZipFile(zip)// 獲取 zip 壓縮包中每一個文件條目val entries = zipFile.entries()...// 關閉 zip 文件zipFile.close()遍歷壓縮包中的文件 ,
如果 apk 壓縮包中含有以下文件 , 這些文件是 V1 簽名文件保存目錄 , 不需要解壓 , 跳過即可 ,
如果該文件條目 , 不是目錄 , 說明就是文件 ,
向剛才創建的目錄中寫出文件 ;
// 遍歷壓縮包中的文件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: Intwhile (inputStream.read(buffer).also { len = it } != -1) {fileOutputStream.write(buffer, 0, len)}inputStream.close()fileOutputStream.close()}}四、解壓操作相關代碼
/*** 解壓文件* @param zip 被解壓的壓縮包文件* @param dir 解壓后的文件存放目錄*/fun unZipApk(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: Intwhile (inputStream.read(buffer).also { len = it } != -1) {fileOutputStream.write(buffer, 0, len)}inputStream.close()fileOutputStream.close()}}zipFile.close()} catch (e: Exception) {e.printStackTrace()}}/*** 刪除文件, 如果有目錄, 則遞歸刪除*/private fun deleteFile(file: File) {if (file.isDirectory) {val files = file.listFiles()for (f in files) {deleteFile(f)}} else {file.delete()}}
總結
以上是生活随笔為你收集整理的【Android 安全】DEX 加密 ( 代理 Application 开发 | 解压 apk 文件 | 判定是否是第一次启动 | 递归删除文件操作 | 解压 Zip 文件操作 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 安全】DEX 加密 (
- 下一篇: 【Android 安全】DEX 加密 (