Vdex Extractor:從Vdex檔案反編譯和提取Android Dex位元組碼的工具
Vdex Extractor
一款命令列工具,用於從Vdex檔案反編譯和提取Android Dex位元組碼的工具。
編譯
克隆此儲存庫
如果要為Android裝置進行交叉編譯,請安裝Android NDK
make.sh使用所需的構建目標呼叫bash指令碼$ ./make.sh
- 如果CC未從env定義,則預設使用gcc$ ./make.sh gcc
– 用gcc編譯$ ./make.sh clang
– 用clang編譯$ ./make.sh cross-android
– 使用NDK交叉編譯(armeabi-v7a,arm64-v8a,x86和x86_64)可執行檔案複製到bin目錄下,對於除錯版本使用$ DEBUG=true ./make.sh
依賴關係
主機系統中應安裝以下外部庫:
zlib
macos:brew install zlib-devel
帶macports的macOS:port install zlib
Linux:apt install libz-dev
其他Linux / Unix系統:檢查可用的包管理器或從原始碼編譯使用cygwin的Windows:zlib-devel從cygwin安裝程式安裝
用法
$ bin/vdexExtractor -h vdexExtractor ver. 0.5.2 Anestis Bechtsoudis Copyright 2017 - 2018 by CENSUS S.A. All Rights Reserved. -i, --input=: 輸入目錄(遞迴搜尋)或單個檔案 -o, --output=: 輸出路徑(預設與輸入相同) -f, --file-override: 如果檔案已經存在允許覆蓋(預設:false) --no-unquicken: 禁用unquicken位元組碼反編譯器 (don't de-odex) --deps: 轉儲經過驗證的依賴資訊 --dis: 啟用位元組碼反彙編器 --ignore-crc-error: 反編譯Dex 忽略CRC錯誤 --new-crc=: 提取Apk或Dex檔案位置校驗和文字檔案 --get-api: 基於Vdex版本獲取Android API級別 -v, --debug=LEVEL: 日誌級別 預設: '3' (INFO) -l, --log-file=: 儲存反彙編器或驗證依賴項輸出到日誌檔案 -h, --help: 幫助資訊
位元組碼Unquickening解碼器
Vdex檔案包含所有quick_info資料(舊vtable),用於恢復位元組碼優化過程中應用的dexto -dex轉換。這裡是建立一個能夠快速恢復優化位元組碼的獨立工具,不需要從AOSP構建整個libart。Vdex完全unquicken功能也作為AOSP oatdump libart工具的一部分實現。可在此處獲得。如果你想在Oreo版本中使用oatdump,你可以在這裡使用相應的補丁,或者在oatdump ++工具的fork和build(內部和AOSP_SRC_ROOT工作空間)中使用oreo-release分支。谷歌已經發布了提供的補丁以及ART執行時的AndroidPie版本。
驗證迭代器的依賴關係
當第一次編譯(優化)Dex位元組碼檔案時,dex2oat將執行驗證依賴項收集器,作為方法學驗證者的一部分。驗證依賴項收集器類用於記錄解析結果和類路徑中定義的類/方法/欄位的型別可賦值測試。編譯驅動程式初始化類並註冊正在編譯的所有Dex檔案。在這個集合之外的Dex檔案中定義的類(或者沒有關聯的Dex檔案的合成類)被認為在類路徑中。所有記錄的依賴關係都儲存在生成的Vdex檔案中,以及來自OatWriter類的相應Oat檔案。vdexExtractor工具集成了一個Vdex依賴項walker函式,該函式能夠迭代所有依賴項資訊並以人類可讀的格式轉儲它們。以下程式碼段演示了示例Vdex檔案的依賴項轉儲示例。
$ bin/vdexExtractor -i /tmp/BasicDreams.vdex -o /tmp --deps -f [INFO] Processing 1 file(s) from /tmp/BasicDreams.vdex ------- Vdex Deps Info ------- dex file #0 extra strings: number_of_strings=2 0000: 'Ljava/lang/Thread;' 0001: 'Ljava/lang/Throwable;' assignable type sets: number_of_sets=8 0000: 'Landroid/service/dreams/DreamService;' must be assignable to 'Landroid/content/Context;' 0001: 'Landroid/view/TextureView;' must be assignable to 'Landroid/view/View;' 0002: 'Ljava/nio/FloatBuffer;' must be assignable to 'Ljava/nio/Buffer;' ... unassignable type sets: number_of_sets=0 class dependencies: number_of_classes=34 0000: 'Landroid/graphics/Color;' 'must' be resolved with access flags '1' 0001: 'Landroid/graphics/SurfaceTexture;' 'must' be resolved with access flags '1' ... 0024: 'Ljavax/microedition/khronos/egl/EGL10;' 'must' be resolved with access flags '513' ... field dependencies: number_of_fields=4 0000: 'Ljavax/microedition/khronos/egl/EGL10;'->'EGL_DEFAULT_DISPLAY':'Ljava/lang/Object;' is expected to be in class 'Ljavax/microedition/khronos/egl/EGL10;' and have the access flags '9' 0001: 'Ljavax/microedition/khronos/egl/EGL10;'->'EGL_NO_CONTEXT':'Ljavax/microedition/khronos/egl/EGLContext;' is expected to be in class 'Ljavax/microedition/khronos/egl/EGL10;' and have the access flags '9' 0002: 'Ljavax/microedition/khronos/egl/EGL10;'->'EGL_NO_DISPLAY':'Ljavax/microedition/khronos/egl/EGLDisplay;' is expected to be in class 'Ljavax/microedition/khronos/egl/EGL10;' and have the access flags '9' 0003: 'Ljavax/microedition/khronos/egl/EGL10;'->'EGL_NO_SURFACE':'Ljavax/microedition/khronos/egl/EGLSurface;' is expected to be in class 'Ljavax/microedition/khronos/egl/EGL10;' and have the access flags '9' method dependencies: number_of_methods=84 0000: 'Landroid/graphics/Color;'->'HSVToColor':'([F)I' is expected to be in class 'Landroid/graphics/Color;', have the access flags '9 0001: 'Landroid/opengl/GLES20;'->'glAttachShader':'(II)V' is expected to be in class 'Landroid/opengl/GLES20;', have the access flags '9 0002: 'Landroid/opengl/GLES20;'->'glClear':'(I)V' is expected to be in class 'Landroid/opengl/GLES20;', have the access flags '9 ... unverified classes: number_of_classes=0 ----- EOF Vdex Deps Info ----- [INFO] 1 out of 1 Vdex files have been processed [INFO] 1 Dex files have been extracted in total [INFO] Extracted Dex files are available in '/tmp'
整合反彙編程式
為了除錯反編譯器並協助Dex位元組碼調查任務,實現了一個輕型反彙編程式。反彙編輸出非常類似於platform/art專案的AOSP dexdump2實用程式提供的輸出。反彙編程式可以獨立於unquickening反編譯器使用。以下程式碼段中說明了示例輸出。字首的行[new]說明了位於該偏移量中的反編譯指令(前一行)的輸出。請注意,所有加速的偏移和vtable引用都已恢復為原始簽名和原型。
$ bin/vdexExtractor -i /tmp/Videos.vdex -o /tmp -f --dis -l /tmp/dis.log [INFO] Processing 1 file(s) from /tmp/Videos.vdex [INFO] 1 out of 1 Vdex files have been processed [INFO] 2 Dex files have been extracted in total [INFO] Extracted Dex files are available in '/tmp' $ head -90 /tmp/dis.log ------ Dex Header Info ------ magic: dex-035 checksum: e14de163 (3779977571) signature: 9a91f8e5f2afe2c6b5c2b4853832d3c5ed01aef8 fileSize: 8ca638 (9217592) headerSize: 70 (112) endianTag: 12345678 (305419896) linkSize: 0 (0) linkOff: 0 (0) mapOff: 8ca568 (9217384) stringIdsSize: ef06 (61190) stringIdsOff : 70 (112) typeIdsSize: 29f4 (10740) typeIdsOff: 3bc88 (244872) protoIdsSize : 3df9 (15865) protoIdsOff: 46458 (287832) fieldIdsSize : a79d (42909) fieldIdsOff: 74c04 (478212) methodIdsSize: fed7 (65239) methodIdsOff : c88ec (821484) classDefsSize: 2288 (8840) classDefsOff : 147fa4 (1343396) dataSize: 73d594 (7591316) dataOff: 18d0a4 (1626276) ----------------------------- file #0: classDefsSize=8840 class #0: a.a ('La$a;') access=0601 (PUBLIC INTERFACE ABSTRACT) source_file=SourceFile, class_data_off=851907 (8722695) static_fields=0, instance_fields=0, direct_methods=0, virtual_methods=2 virtual_method #0: onMenuItemSelected (La;Landroid/view/MenuItem;)Z access=0401 (PUBLIC ABSTRACT) codeOff=0 (0) virtual_method #1: invokeItem (Landroid/support/v7/view/menu/MenuItemImpl;)Z access=0401 (PUBLIC ABSTRACT) codeOff=0 (0) class #1: a.b ('La$b;') access=0601 (PUBLIC INTERFACE ABSTRACT) source_file=SourceFile, class_data_off=851913 (8722707) static_fields=0, instance_fields=0, direct_methods=0, virtual_methods=1 virtual_method #0: invokeItem (Landroid/support/v7/view/menu/MenuItemImpl;)Z access=0401 (PUBLIC ABSTRACT) codeOff=0 (0) class #2: SupportMenu ('Landroid/support/v4/internal/view/SupportMenu;') access=0601 (PUBLIC INTERFACE ABSTRACT) source_file=SourceFile, class_data_off=0 (0) class #3: a ('La;') access=0001 (PUBLIC) source_file=SourceFile, class_data_off=85191b (8722715) static_fields=1, instance_fields=25, direct_methods=12, virtual_methods=74 direct_method #0: <clinit> ()V access=10008 (STATIC CONSTRUCTOR) codeOff=1abb50 (1751888) quickening_size=4 (4) 1abb60: 1260|0000: const/4 v0, #int 6 // #6 1abb62: 2300 e426|0001: new-array v0, v0, [I // type@26e4 1abb66: 2600 0700 0000|0003: fill-array-data v0, 0000000a // +00000000 1abb6c: 6900 1900|0006: sput-object v0, La;.sCategoryToOrder:[I // field@0019 1abb70: 7300|0008: return-void-no-barrier [new] 1abb70: 0e00|0008: return-void 1abb72: 0000|0009: nop // spacer 1abb74: 0003 0400 0600 0000 0100 0000 0400 ... |000a: array-data (16 units) direct_method #1: invokeItem (Landroid/support/v7/view/menu/MenuItemImpl;)Z access=10001 (PUBLIC CONSTRUCTOR) codeOff=1abb94 (1751956) quickening_size=22 (34) 1abba4: 1211|0000: const/4 v1, #int 1 // #1 1abba6: 1200|0001: const/4 v0, #int 0 // #0 1abba8: 7010 dbf9 0200|0002: invoke-direct {v2}, Ljava/lang/Object;.<init>:()V // method@f9db 1abbae: e620 4000|0005: iput-quick v0, v2, [obj+0040] [new] 1abbae: 5920 0400|0005: iput v0, v2, La;.mDefaultShowAsAction:I // field@0004 1abbb2: eb20 4a00|0007: iput-boolean-quick v0, v2, [obj+004a] [new] 1abbb2: 5c20 1200|0007: iput-boolean v0, v2, La;.mPreventDispatchingItemsChanged:Z // field@0012 1abbb6: eb20 4700|0009: iput-boolean-quick v0, v2, [obj+0047] [new] 1abbb6: 5c20 0d00|0009: iput-boolean v0, v2, La;.mItemsChangedWhileDispatchPrevented:Z // field@000d 1abbba: eb20 4d00|000b: iput-boolean-quick v0, v2, [obj+004d] [new] 1abbba: 5c20 1600|000b: iput-boolean v0, v2, La;.mStructureChangedWhileDispatchPrevented:Z // field@0016 1abbbe: eb20 4800|000d: iput-boolean-quick v0, v2, [obj+0048] [new] 1abbbe: 5c20 0f00|000d: iput-boolean v0, v2, La;.mOptionalIconsVisible:Z // field@000f 1abbc2: eb20 4500|000f: iput-boolean-quick v0, v2, [obj+0045] [new] 1abbc2: 5c20 0a00|000f: iput-boolean v0, v2, La;.mIsClosing:Z // field@000a 1abbc6: 2200 fe25|0011: new-instance v0, Ljava/util/ArrayList; // type@25fe 1abbca: 7010 6bfb 0000|0013: invoke-direct {v0}, Ljava/util/ArrayList;.<init>:()V // method@fb6b 1abbd0: e820 3800|0016: iput-object-quick v0, v2, [obj+0038] [new] 1abbd0: 5b20 1700|0016: iput-object v0, v2, La;.mTempShortcutItemList:Ljava/util/ArrayList; // field@0017 1abbd4: 2200 2c26|0018: new-instance v0, Ljava/util/concurrent/CopyOnWriteArrayList; // type@262c 1abbd8: 7010 cdfc 0000|001a: invoke-direct {v0}, Ljava/util/concurrent/CopyOnWriteArrayList;.<init>:()V // method@fccd 1abbde: e820 3000|001d: iput-object-quick v0, v2, [obj+0030] [new] 1abbde: 5b20 1100|001d: iput-object v0, v2, La;.mPresenters:Ljava/util/concurrent/CopyOnWriteArrayList; // field@0011 1abbe2: e823 1000|001f: iput-object-quick v3, v2, [obj+0010]
Dex轉換器
Android 9(Pie)版本推出了一種新型的Dex檔案,即Compact Dex(Cdex)。Cdex是一種ART內部檔案格式,它壓縮各種Dex資料結構(例如方法頭)並對多索引檔案中的常見資料blob(例如字串)進行重複資料刪除。來自輸入應用程式的Dex檔案的重複資料刪除資料儲存在Vdex容器的共享部分中。
現在由於Vdex容器儲存的是Cdex檔案而不是標準的Dex,因此vdexExtractor後端(從版本019開始)已經更新並支援它們。但是,由於該工具未實現Dex IR,因此無法在不使用外部工具的情況下將Cdex檔案轉換回標準Dex。為此,編寫了“compact_dex_converter”
工具,該工具使用來自AOSPart repo的libdexlayout(Dex IR)。該工具的原始碼可在此處獲得。編譯工具需要分配必要的AOSP回購並構建為AOSP模組。為方便起見,vdexExtractor正在實現一個幫助工具(請參閱下一節中的“tools / deodex”),該工具下載一組預編譯的二進位制檔案幷包裝所需的自動化。此外,可以從以下連結下載“compact_dex_converter”二進位制檔案:
Linux x86-64
使用共享庫:https://1drv.ms/u/s !ArDC4mvMyPrRhEsiuPjOF_ssIfOe
使用共享庫除錯:https://1drv.ms/u/s!ArDC4mvMyPrRhE3Z2jdBXJIhazjc
靜態編譯:https://1drv.ms/u/s !ArDC4mvMyPrRhEq96XX-LsCACF2s
靜態編譯除錯:https://1drv.ms/u/s!ArDC4mvMyPrRhEwmwM8–zdhoCB2
Linux x86-64舊CPU(沒有SSE4.2和沒有POPCNT #29)
使用共享庫:https://1drv.ms/u/s!ArDC4mvMyPrRhFP46IyBqOtihS9s
使用共享庫除錯:https://1drv.ms/u/s!ArrDC4mvMyPrRhFXEGW9vrlMlTKDJ
靜態編譯:https://1drv.ms/u/s!ArDC4mvMyPrRhFIFZCF9TtEHVooc
靜態編譯的除錯:https://1drv.ms/u/s!ArDC4mvMyPrRhFSMELB_H3w5Cdfe
ARM64(aarch64)
使用共享庫:https://1drv.ms/u/s!ArDC4mvMyPrRhEindMOf3aWCbQRr
使用共享庫除錯:https://1drv.ms/u/s!ArDC4mvMyPrRhEnU9Ei_3MeQipGr
靜態編譯:不支援
蘋果系統
使用共享庫:https://1drv.ms/u/s!ArDC4mvMyPrRhE45gEUNolEiZ50u
使用共享庫除錯:https://1drv.ms/u/s!ArDC4mvMyPrRhFG5WH_zNz0jNarZ
靜態編譯:不支援
二進位制名稱中的's'
字尾代表“靜態編譯”,而“d”
代表“debug”
構建。它們也可以組合在一起(例如'ds'
– 靜態編譯的除錯版本)。
實用指令碼
extract-apps-from-device.sh
從連線的Android裝置中提取安裝包(使用者和系統)的ART編譯器輸出資源(oat、ART、vdex)。還支援提取APK檔案的安裝包。由於應用了DAC許可權,一些系統應用程式資料在沒有根訪問的情況下可能無法提取。
$ scripts/extract-apps-from-device.sh -h Usage: extract-apps-from-device.sh [options] options: -o|--output <dir>: Output directory to save extracted data (default is '.') -d|--device <devID>: Device serial to use instead of default interactive selection --system-apps: Extract system apps too (default is user apps only) --apks: Extract apks (default is optimized files only) -h|--help: This help message $ scripts/extract-apps-from-device.sh --system-apps -o /tmp/art_data --apks [INFO]: Enumerating connected Android devices [INFO]: Trying to extract data from '163' packages [INFO]: Extracted data stored under '/tmp/art_data'
### update-vdex-location-checksums.sh使用從輸入Apk存檔檔案中提取的CRCs更新Vdex檔案位置校驗和。有關如何使用該特性欺騙ART和繞過SafetyNet應用程式完整性檢查的更多資訊,請參閱此處。
$ scripts/update-vdex-location-checksums.sh -h Usage: update-vdex-location-checksums.sh [options] options: -i|--input <file> : Input Vdex file to repair location checksum(s) within -a|--app <file>: Input Apk file to extract location checksum(s) from -o|--output <dir> : Directory to save updated Vdex file (default is '.') -h|--help: This help message
### tools/deodex/run.sh幫助工具,以批量方式將(deodex) Vdex資源反編譯回標準Dex檔案。該工具自動處理CompactDex檔案(如Android Pie中介紹的),並使用compact_dex_converter工具(更多資訊在這裡)轉換回StandardDex。由於轉換器是作為AOSP原始碼的一部分進行編譯的,為了方便起見,開發人員維護了一組用於Linux和maacOS的二進位制檔案。
$ tools/deodex/run.sh -h Usage: run.sh [options] options: -i|--input <path> : Directory with Vdex files or single file -o|--output <dir> : Directory to save deodex'ed resources (default is '.') -k|--keep: Keep intermediate files (default 'false') -h|--help: This help message $ tools/deodex/run.sh -i /tmp/vdex_samples -o /tmp/deodexed_samples [INFO]: Processing 140 input Vdex files [INFO]: 140 binaries have been successfully deodexed
*參考來源:github,由周大濤編譯,轉載請註明來自FreeBuf.COM