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

資訊專欄INFORMATION COLUMN

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

番茄西紅柿 / 2009人閱讀

摘要:文件結(jié)構(gòu)思維導(dǎo)圖及解析源碼見文末。用于標(biāo)記文件是大端表示還是小端表示。是一個(gè)偏移量數(shù)組,表示每個(gè)字符串在區(qū)的偏移量。表示的是類型信息,指向中元素。

DEX 文件結(jié)構(gòu)思維導(dǎo)圖及解析源碼見文末。

往期目錄:

Class 文件格式詳解

Smali 語法解析——Hello World

Smali —— 數(shù)學(xué)運(yùn)算,條件判斷,循環(huán)

Smali 語法解析 —— 類

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

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

對(duì)于學(xué)習(xí)熱修復(fù)框架,加固和逆向相關(guān)知識(shí),了解 DEX 文件結(jié)構(gòu)是很有必要的。再之前解析過 Class 文件和 AndroidManifest.xml 文件結(jié)構(gòu)之后,發(fā)現(xiàn)看二進(jìn)制文件看上癮了。。后面會(huì)繼續(xù)對(duì) Apk 文件中的其他文件結(jié)構(gòu)進(jìn)行分析,例如 so 文件,resources.arsc 文件等。

DEX 文件的生成

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

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 目錄下,可添加至環(huán)境變量方便調(diào)用。dx 也支持多 Class 文件生成 dex。

DEX 文件結(jié)構(gòu) 概覽

關(guān)于 DEX 文件結(jié)構(gòu)的學(xué)習(xí),給大家推薦兩個(gè)資料。

第一個(gè)是看雪神圖,出自非蟲,

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

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

我們可以一目了然的看到 DEX 的文件結(jié)構(gòu),著實(shí)是一個(gè)利器。在詳細(xì)解析之前,我們先來大概給 DEX 文件分個(gè)層,如下圖所示:

文末我放了一張?jiān)敿?xì)的思維導(dǎo)圖,也可以對(duì)著思維導(dǎo)圖來閱讀文章。

依次解釋一下:

header : DEX 文件頭,記錄了一些當(dāng)前文件的信息以及其他數(shù)據(jù)結(jié)構(gòu)在文件中的偏移量

string_ids : 字符串的偏移量

type_ids : 類型信息的偏移量

proto_ids : 方法聲明的偏移量

field_ids : 字段信息的偏移量

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

class_def : 類信息的偏移量

data : : 數(shù)據(jù)區(qū)

link_data : 靜態(tài)鏈接數(shù)據(jù)區(qū)

headerdata 之間都是偏移量數(shù)組,并不存儲(chǔ)真實(shí)數(shù)據(jù),所有數(shù)據(jù)都存在 data 數(shù)據(jù)區(qū),根據(jù)其偏移量區(qū)查找。對(duì) DEX 文件有了一個(gè)大概的認(rèn)識(shí)之后,我們就來詳細(xì)分析一下各個(gè)部分。

header

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

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

其中的 u 表示無符號(hào)數(shù),u1 就是 8 位無符號(hào)數(shù),u4 就是 32 位無符號(hào)數(shù)。

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

文件標(biāo)識(shí) dex + 換行符 + DEX 版本 + 0

字符串格式為 dex 035