国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Android逆向筆記 —— DEX 文件格式解析

番茄西紅柿 / 1997人閱讀

摘要:文件結構思維導圖及解析源碼見文末。用于標記文件是大端表示還是小端表示。是一個偏移量數組,表示每個字符串在區的偏移量。表示的是類型信息,指向中元素。

DEX 文件結構思維導圖及解析源碼見文末。

往期目錄:

Class 文件格式詳解

Smali 語法解析——Hello World

Smali —— 數學運算,條件判斷,循環

Smali 語法解析 —— 類

Android逆向筆記 —— AndroidManifest.xml 文件格式解析

系列第一篇文章就分析過 Class 文件格式,我們都知道 .java 源文件經過編譯器編譯會生成 JVM 可識別的 .class 文件。在 Android 中,不管是 Dalvik 還是 Art,和 JVM 的區別還是很大的。Android 系統并不直接使用 Class 文件,而是將所有的 Class 文件聚合打包成 DEX 文件,DEX 文件相比單個單個的 Class 文件更加緊湊,可以直接在 Android Runtime 下執行。

對于學習熱修復框架,加固和逆向相關知識,了解 DEX 文件結構是很有必要的。再之前解析過 Class 文件和 AndroidManifest.xml 文件結構之后,發現看二進制文件看上癮了。。后面會繼續對 Apk 文件中的其他文件結構進行分析,例如 so 文件,resources.arsc 文件等。

DEX 文件的生成

在解析 DEX 文件結構之前,先來看看如何生成 DEX 文件。為了方便解析,本篇文章中就不從市場上的 App 里拿 DEX 文件過來解析了,而是手動生成一個最簡單的 DEX 文件。還是以 Class 文件解析時候用的例子:

public class Hello {

    private static String HELLO_WORLD = "Hello World!";

    public static void main(String[] args) {
        System.out.println(HELLO_WORLD);
    }
}

首先 javac 編譯成 Hello.class 文件,然后利用 Sdk 自帶的 dx 工具生成 DEX 文件:

dx --dex --output=Hello.dex  Hello.class

dx 工具位于 Sdk 的 build-tools 目錄下,可添加至環境變量方便調用。dx 也支持多 Class 文件生成 dex。

DEX 文件結構 概覽

關于 DEX 文件結構的學習,給大家推薦兩個資料。

第一個是看雪神圖,出自非蟲,

第二個是 Android 源碼中對 DEX 文件格式的定義,dalvik/libdex/DexFile.h,其中詳細定義了 DEX 文件中的各個部分。

第三個是 010 Editor,在之前解析 AndroidManifest.xml 文件格式解析 也介紹過,它提供了豐富的文件模板,支持常見文件格式的解析,可以很方便的查看文件結構中的各個部分及其對應的十六進制。一般我在代碼解析文件結構的時候都是對照著 010 Editor 來進行分析。下面貼一張 010 Editor 打開之前生成的 Hello.dex 文件的截圖:

我們可以一目了然的看到 DEX 的文件結構,著實是一個利器。在詳細解析之前,我們先來大概給 DEX 文件分個層,如下圖所示:

文末我放了一張詳細的思維導圖,也可以對著思維導圖來閱讀文章。

依次解釋一下:

header : DEX 文件頭,記錄了一些當前文件的信息以及其他數據結構在文件中的偏移量

string_ids : 字符串的偏移量

type_ids : 類型信息的偏移量

proto_ids : 方法聲明的偏移量

field_ids : 字段信息的偏移量

method_ids : 方法信息(所在類,方法聲明以及方法名)的偏移量

class_def : 類信息的偏移量

data : : 數據區

link_data : 靜態鏈接數據區

headerdata 之間都是偏移量數組,并不存儲真實數據,所有數據都存在 data 數據區,根據其偏移量區查找。對 DEX 文件有了一個大概的認識之后,我們就來詳細分析一下各個部分。

header

DEX 文件頭部分的具體格式可以參考 DexFile.h 中的定義:

struct DexHeader {
    u1  magic[8];           // 魔數
    u4  checksum;           // adler 校驗值
    u1  signature[kSHA1DigestLen]; // sha1 校驗值
    u4  fileSize;           // DEX 文件大小
    u4  headerSize;         // DEX 文件頭大小
    u4  endianTag;          // 字節序
    u4  linkSize;           // 鏈接段大小
    u4  linkOff;            // 鏈接段的偏移量
    u4  mapOff;             // DexMapList 偏移量
    u4  stringIdsSize;      // DexStringId 個數
    u4  stringIdsOff;       // DexStringId 偏移量
    u4  typeIdsSize;        // DexTypeId 個數
    u4  typeIdsOff;         // DexTypeId 偏移量
    u4  protoIdsSize;       // DexProtoId 個數
    u4  protoIdsOff;        // DexProtoId 偏移量
    u4  fieldIdsSize;       // DexFieldId 個數
    u4  fieldIdsOff;        // DexFieldId 偏移量
    u4  methodIdsSize;      // DexMethodId 個數
    u4  methodIdsOff;       // DexMethodId 偏移量
    u4  classDefsSize;      // DexCLassDef 個數
    u4  classDefsOff;       // DexClassDef 偏移量
    u4  dataSize;           // 數據段大小
    u4  dataOff;            // 數據段偏移量
};

其中的 u 表示無符號數,u1 就是 8 位無符號數,u4 就是 32 位無符號數。

magic 一般是常量,用來標記 DEX 文件,它可以分解為:

文件標識 dex + 換行符 + DEX 版本 + 0

字符串格式為 dex 035