據(jù)存儲與加載完整指南)
6 步讀懂 Apktool 的 ApkInfo 類APK 元數(shù)據(jù)存儲與加載完整指南【免費下載鏈接】ApktoolA tool for reverse engineering Android apk files項目地址: https://gitcode.com/GitHub_Trending/ap/Apktool當(dāng)您用 Apktool 反編譯一個 APK 后輸出目錄里總會靜靜躺著一個apktool.yml——它就是 ApkInfo 類的序列化產(chǎn)物。讀懂這套 APK 元數(shù)據(jù)的存儲與加載機制您就能解釋重新打包為什么能成功還能安全地手工修改 APK 的關(guān)鍵屬性。本文帶您在 6 步內(nèi)走完概念、原理、實戰(zhàn)與避坑全流程。一張 apktool.yml 管住了 APK 的什么ApkInfo 是 Apktool 中負(fù)責(zé)承載 APK 應(yīng)用元數(shù)據(jù)Metadata即描述應(yīng)用本身的信息如版本、SDK 要求、框架依賴等的核心類源碼位于 ApkInfo.java。它實現(xiàn)了項目自研的YamlSerializable接口定義在 brut.j.yaml 模塊因此可以自由地對象 ? YAML 文本雙向轉(zhuǎn)換。打個比方ApkInfo 就像一棟樓竣工時的檔案袋記錄了樓高幾層、電梯幾部、承重多少。將來要按圖紙翻修重新打包時施工隊靠的就是這個檔案袋而不是憑記憶。回到技術(shù)本身解碼時 Apktool 把 APK 的各項關(guān)鍵信息寫入apktool.yml編碼時再讀回來指導(dǎo)構(gòu)建。它具體管理這幾類信息身份信息生成該檔案的 Apktool 版本號、原始 APK 文件名框架與庫依賴APK 依賴的系統(tǒng)框架uses-framework和第三方庫SDK 范圍minSdk / targetSdk / maxSdk 三個版本號應(yīng)用版本versionCode 與 versionName資源包信息packageId、packageName、稀疏/緊湊條目標(biāo)志功能開關(guān)featureFlags 鍵值對壓縮策略doNotCompress 不壓縮文件清單數(shù)據(jù)從哪來又流向哪里理解 ApkInfo 的運行機制關(guān)鍵是看寫入和讀取兩個方向的調(diào)用鏈。寫入方向解碼階段ApkDecoder 在decode()過程中創(chuàng)建ApkInfo實例ResDecoder解析resources.arsc時填充資源包信息ManifestPullEventHandler解析清單時填充 SDK 與版本信息。最后writeApkInfo()會額外做兩件事若未解析清單如--no-res模式用 smali 反編譯推斷出的 dex 指令集 API 級別兜底填入minSdkVersion掃描原 APK 中壓縮級別為 0 的文件按擴展名優(yōu)先、文件名兜底的原則匯總進(jìn)doNotCompress列表然后調(diào)用mApkInfo.save(outDir)落盤為apktool.yml。讀取方向編碼階段ApkBuilder 的build()一上來就執(zhí)行ApkInfo.load(mApkDir)隨后把minSdkVersion傳給 smali 匯編保證 dex 字節(jié)碼指令集與 SDK 匹配把AaptInvoker掛上 ApkInfo構(gòu)建資源時讀取 packageId、versionName、featureFlags、框架依賴等并在最終打 zip 包時應(yīng)用doNotCompress清單。一個真實的apktool.yml長這樣按write()方法的實際輸出順序排列version: 2.9.3 apkFileName: sample.apk usesFramework: ids: - 1 sdkInfo: minSdkVersion: 25 targetSdkVersion: 30 versionInfo: versionCode: 71 versionName: 1.0.70 resourcesInfo: packageId: 127 packageName: com.example.sample sparseEntries: true doNotCompress: - arsc - png注意各段是有內(nèi)容才寫出的UsesFramework、SdkInfo等對象內(nèi)部都實現(xiàn)了isEmpty()檢查空對象不會出現(xiàn)在 YAML 里所以您看到的文件總是精簡的。實戰(zhàn)加載、修改、保存的完整調(diào)用流程下面是一段可直接運行的 Java 調(diào)用示例演示如何以編程方式操作 ApkInfo依賴 apktool-lib 模塊import brut.androlib.meta.ApkInfo; import brut.androlib.meta.SdkInfo; import java.io.File; // 從反編譯目錄加載 apktool.yml ApkInfo apkInfo ApkInfo.load(new File(sample-decoded)); // 查看并修改 SDK 目標(biāo)版本 SdkInfo sdk apkInfo.getSdkInfo(); System.out.println(原 targetSdk: sdk.getTargetSdkVersion()); sdk.setTargetSdkVersion(33); // 修改后保存回 apktool.yml apkInfo.save(new File(sample-decoded));更常見的其實是命令行操作。修改apktool.yml后重新打包只需兩步# 在反編譯目錄中手工編輯 apktool.yml 后執(zhí)行 apktool b sample-decoded -o sample-modified.apkapktool b內(nèi)部走的就是上面ApkBuilder.build()的加載鏈路您改的每一個字段都會真實影響構(gòu)建結(jié)果。逐個組件看7 個字段各自管什么以下按apktool.yml中的出現(xiàn)順序逐條講透每個組成部分。1. version 與 apkFileNameversion記錄生成檔案的 Apktool 版本apkFileName是原始 APK 文件名編碼時若未指定輸出名它會作為dist/下產(chǎn)物文件名。源碼中有一處值得注意的安全校驗apkFileName的值若為.、..或包含路徑分隔符直接拋出SecurityException防止惡意 YAML 誘導(dǎo)文件寫出目錄相關(guān)防御測試見 MaliciousYamlTest.java。2. usesFrameworkUsesFramework 記錄 APK 依附的 Android 框架字段含義ids框架 ID 列表普通應(yīng)用依賴 Android 本身時即[1]定制 ROM 應(yīng)用可能依賴其他 IDtag框架版本標(biāo)簽用于匹配apktool if安裝的多個同 ID 框架構(gòu)建時AaptInvoker會據(jù)此拼出aapt2 --framework參數(shù)保證編譯資源時引用的系統(tǒng)資源正確。3. usesLibrary字符串列表對應(yīng)清單里uses-library聲明的共享庫如org.apache.http.legacy。源碼中該列表是ListStringYAML 里就是普通的字符串?dāng)?shù)組。4. sdkInfoSdkInfo 持有minSdkVersion、targetSdkVersion、maxSdkVersion三個字符串。亮點在于parseSdkInt()既接受數(shù)字30也接受字母代號M、O、Q……直到最新的Baklava、Cinnamon Bun并映射為 ResConfig 中的常量。另有g(shù)etTargetSdkVersionBounded()會把 target 收斂到[min, max]區(qū)間內(nèi)供資源編譯的 API 級別判定使用。5. versionInfoVersionInfo 保存versionCode整數(shù)與versionName字符串來自AndroidManifest.xml的application標(biāo)簽。注意getVersionCode()在未設(shè)置時返回-1而非 0這是未知的哨兵值。6. resourcesInfoResourcesInfo 包含五個字段packageId資源包 ID絕大多數(shù)應(yīng)用為127十六進(jìn)制0x7f若被其他框架合并過可能不是 127packageName資源包名通常與應(yīng)用包名一致sparseEntries是否使用稀疏資源條目Android O 引入的資源壓縮機制compactEntriesAndroid 9 起的緊湊資源條目keepRawValues是否保留原始資源值這三個布爾開關(guān)決定了重建resources.arsc時的二進(jìn)制結(jié)構(gòu)直接影響新系統(tǒng)上資源能否被正確讀取。7. featureFlags 與 doNotCompressfeatureFlags是MapString, Boolean對應(yīng) aapt2 的--feature-flag編譯選項doNotCompress是字符串列表條目可以是擴展名png、arsc也可以是具體文件路徑編碼時這些文件將以存儲不壓縮模式寫入 APK保證系統(tǒng)能按偏移量直接讀取resources.arsc。三個真實場景它替您解決了什么場景一只改文案、不動代碼。您把 APK 反編譯后只修改了res/values/strings.xml和一個布局apktool b能一次成功靠的就是apktool.yml里保存的 packageId、minSdk 和 doNotCompress 清單——框架選擇、字節(jié)碼指令集、壓縮方式全部原樣還原。場景二給應(yīng)用抬高 targetSdk。商店要求更高 API 時您無需觸碰任何 Java 代碼解碼、把sdkInfo.targetSdkVersion改為目標(biāo)值、重新打包即可。smali 匯編級別和 aapt2 編譯選項會自動跟著這份元數(shù)據(jù)走。場景三批量分析腳本。在 CI 中寫一段 Java 程序?qū)σ慌?APK 解碼后只讀ApkInfo不關(guān)心資源與 smali用getVersionInfo()、getSdkInfo()、getUsesLibrary()匯總成一份版本 / SDK / 依賴庫報表。避坑指南4 個容易踩的雷別丟或手撕apktool.yml。它是ApkBuilder的強制輸入文件缺失會直接報InFileNotFoundException手工編輯時保持 YAML 縮進(jìn)正確鍵與列表項的縮進(jìn)層級解析器是基于 YamlLine 的逐行結(jié)構(gòu)解析縮進(jìn)錯亂會導(dǎo)致字段丟失或解析失敗健壯性驗證可參考 meta 測試目錄。改 packageId 是高危操作。資源引用0x7f08xxxx形式的數(shù)值 ID與 packageId 綁定隨意改成非 127 的值會導(dǎo)致大量資源引用失效除非您明確在做什么否則保持原值。doNotCompress 不是可有可無的裝飾。移除arsc條目會讓resources.arsc被壓縮部分系統(tǒng)版本上應(yīng)用會因無法按偏移讀取資源而啟動即崩潰新增大文件不壓縮又會顯著增大 APK 體積??绨姹旧壸⒁庾侄渭嫒荨Ef版 Apktool 生成的apktool.yml可能缺少compactEntries、featureFlags等新字段加載時這些字段為 nullgetter 有默認(rèn)值兜底一般能正常重建但若您在極舊文件上手工添加新字段建議先用當(dāng)前版本重新 decode 一遍讓工具自己重寫檔案。寫在最后apktool.yml是反編譯目錄的重建藍(lán)圖由 ApkInfo 類以 YamlSerializable 協(xié)議生成與讀取。解碼時它被填充與落盤編碼時被ApkBuilder消費SDK、版本、資源、壓縮策略全部以它為準(zhǔn)。記住改 APK 前先讀懂它的檔案袋藍(lán)圖在手重建不愁。【免費下載鏈接】ApktoolA tool for reverse engineering Android apk files項目地址: https://gitcode.com/GitHub_Trending/ap/Apktool創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考