[Android Security] DEX檔案格式分析

來源:互聯網
上載者:User

標籤:長度   script   校正   comm   method   注釋   結構   catch   device   

copy from : 11900000076529370x00 前言

分析 dex 檔案格式最好的方式是找個介紹文檔,自己再寫一個簡單的 demo 然後用 010Editor 對照著分析。文檔可以參考官方文檔http://source.android.com/devices/tech/dalvik/dex-format.html,英文差的也可以找個中文的,比如說我。。。。。。

010Editor 這個工具比較好用,之前分析 elf 檔案也是用的它。其實只要裝了模板,可以分析很多檔案。雖然是收費軟體,有30天免費試用。但是如果你用的是 mac ?? 試用期到了, 刪一下這個檔案 ?? ~/.config/SweetScape/010 Editor.ini

0x01 檔案布局

dex 檔案可以分為3個模組,標頭檔(header)、索引區(xxxx_ids)、資料區(data)。標頭檔概況的描述了整個 dex 檔案的分布,包括每一個索引區的大小跟位移。索引區的ids 是 identifiers 的縮寫,表示每個資料的標識,索引區主要是指向資料區的位移。

010Editor 中除了資料區(data)沒有顯示出來,其他區段都有顯示,另外 link_data 在模板中被定為 map_list

0x02 header

header 描述了 dex 檔案資訊,和其他各個區的索引。010Editor(寫010Editor 有點麻煩下面直接寫010)中用結構體 struct header_item 來描述 header。

其中用到了兩種資料類型char、uint。這裡的 char 是 C/C++ 中的char 占 8-bit, java 中的 char 是占 16-bit 有點區別,但是我們可以他來表示 short/ushort 這個以後介紹最近寫的工具會介紹。官方文檔是用 ubyte來定義的,那還是按官方的來吧。
結構體描述:

ubyte 8-bit unsinged intuint  32-bit unsigned int, little-endianstruct header_item {    ubyte[8]  magic;    unit      checksum;     ubyte[20] signature;     uint      file_size;     uint      header_size;     unit      endian_tag;     uint      link_size;     uint      link_off;     uint      map_off;    uint      string_ids_size;     uint      string_ids_off;     uint      type_ids_size;     uint      type_ids_off;     uint      proto_ids_size;     uint      proto_ids_off;     uint      method_ids_size;     uint      method_ids_off;     uint      class_defs_size;     uint      class_defs_off;     uint      data_size;    uint      data_off; }

除了 magic、checksum、signature、file_size、endian_tag、map_off 其他元素都是成對出現的。_off 表示元素的位移量,_size 表示元素的個數。其餘的6個描述主要是 dex 檔案的資訊。

  • magic: 這個是固定值,用於識別 dex 檔案。轉化為字串為:

{0x64, 0x65, 0x78, 0x0A, 0x30, 0x33, 0x35, 0x00} = "dex\n035\0"

中間是一個換行,後面035是版本號碼。

  • checksum: 檔案校正碼,使用 alder32 演算法校正檔案除去 maigc、checksum 外餘下的所有檔案地區,用於檢 查檔案錯誤。

  • signature: 使用 SHA-1 演算法 hash 除去 magic、checksum 和 signature 外餘下的所有檔案地區, 用於唯一識別本檔案 。

  • file_size: dex 檔案大小

  • header_size: header 地區的大小,目前是固定為 0x70

  • endian_tag: 大小端標籤,dex 檔案格式為小端,固定值為 0x12345678 常量

  • map_off: map_item 的位移地址,該 item 屬於 data 區裡的內容,值要大於等於 data_off 的大小,處於 dex 檔案的末端。

0x03 string_ids

string_ids 區段描述了 dex 檔案中所有的字串。格式很簡單只有一個位移量,位移量指向了 string_data 區段的一個字串:

上述描述裡提到了 LEB128 ( little endian base 128 ) 格式,是基於 1 個 byte 的一種不定長度的編碼方式。若第一個 byte 的最高位為1,則表示還需要下一個 byte 來描述,直至最後一個 byte 的最高位為 0。每個 byte 的其餘 bit 用來表示資料,如下表所示。實際中 LEB128 最大隻能達到 32-bit 可以閱讀 dalvik 中的Leb128.h源碼看出來。

資料結構為:

ubyte    8-bit unsinged intuint     32-bit unsigned int, little-endianuleb128  unsigned LEB128, valriable lengthstruct string_ids_item{    uint string_data_off;}struct string_data_item {    uleb128 utf16_size;    ubyte   data; }

其中 data 儲存的就是字串的值。string_ids 是比較關鍵的,後續的區段很多都是直接指向 string_ids 的 index。在寫工具進行比較的時候也需要提取到 string_ids。

0x04 type_ids

type_ids 區索引了 dex 檔案裡的所有資料類型,包括 class 類型,數群組類型(array types)和基本類型
(primitive types)。區段裡的元素格式為 type_ids_item,結構描述如下 :

uint 32-bit unsigned int, little-endianstruct type_ids_item{    uint descriptor_idx;  //-->string_ids}

type_ids_item 裡面 descriptor_idx 的值的意思,是 string_ids 裡的 index 序號,是用來描述此 type 的字串。

0x05 proto_ids

proto 的意思是 method prototype 代表 java 語言裡的一個 method 的原型 。proto_ids 裡的元素為 proto_id_item,結構如下:

uint 32-bit unsigned int, little-endian struct proto_id_item{    uint shorty_idx;        //-->string_ids    uint return_type_idx;    //-->type_ids    uint parameters_off;}
  • shorty_idx: 跟 type_ids 一樣,它的值是一個 string_ids 的 index 號 ,最終是一個簡短的字串描述,用來說明該 method 原型。

  • return_type_idx: 它的值是一個 type_ids 的 index 號 ,表示該 method 原型的傳回值類型。

  • parameters_off: 指向 method 原型的參數列表 type_list,若 method 沒有參數,值為0。參數列表的格式是 type_list,下面會有描述。

0x06 field_ids

filed_ids 區裡面有 dex 檔案引用的所有的 field。區段的元素格式是 field_id_item,結構如下:

ushort 16-bit unsigned int, little-endian uint   32-bit unsigned int, little-endian struct filed_id_item{    ushort class_idx;  //-->type_ids    ushort type_idx;   //-->type_ids    uint   name_idx;   //-->string_ids}
  • class_idx: 表示 field 所屬的 class 類型,class_idx 的值是 type_ids 的一個 index,並且必須指向一個 class 類型。

  • type_idx: 表示本 field 的類型,它的值也是 type_ids 的一個 index 。

  • name_idx: 表示本 field 的名稱,它的值是 string_ids 的一個 index 。

0x07 method_ids

method_ids 是索引區的最後一個條目,描述了 dex 檔案裡的所有的 method。method_ids 的元素格式是 method_id_item,結構跟 fields_ids 很相似:

ushort 16-bit unsigned int, little-endian uint   32-bit unsigned int, little-endian struct filed_id_item{    ushort class_idx;  //-->type_ids    ushort proto_idx;   //-->proto_ids    uint   name_idx;   //-->string_ids}
  • class_idx: 表示 method 所屬的 class 類型,class_idx 的值是 type_ids 的一個 index,並且必須指向一個 class 類型。<font color=red>ushort類型也是為什麼我們說一個 dex 只能有 65535 個方法的原因,多了必須分包</font>。

  • proto_idx: 表示 method 的類型,它的值也是 type_ids 的一個 index。

  • name_idx: 表示 method 的名稱,它的值是 string_ids 的一個 index。

0x08 class_defs

class_def 區段主要是對 class 的定義,它的結構很複雜,看的我有點暈,一層套一層。先看一張 010 的結構圖:

看著都暈,別說解析的時候了。

class_def_item

class_def_item 結構描述如下:

uint   32-bit unsigned int, little-endianstruct class_def_item{    uint class_idx;         //-->type_ids       uint access_flags;            uint superclass_idx;    //-->type_ids    uint interface_off;     //-->type_list    uint source_file_idx;    //-->string_ids    uint annotations_off;    //-->annotation_directory_item    uint class_data_off;    //-->class_data_item    uint static_value_off;    //-->encoded_array_item}
  • class_idx: 描述具體的 class 類型,值是 type_ids 的一個 index 。值必須是一個 class 類型,不能是數群組類型或者基本類型。

  • access_flags: 描述 class 的訪問類型,諸如 public , final , static 等。在 dex-format.html 裡 "access_flags Definitions" 有具體的描述 。

  • superclass_idx: 描述 supperclass 的類型,值的形式跟 class_idx 一樣 。

  • interfaces_off: 值為位移地址,指向 class 的 interfaces,被指向的資料結構為 type_list 。class 若沒有 interfaces 值為 0。

  • source_file_idx: 表示原始碼檔案的資訊,值是 string_ids 的一個 index。若此項資訊缺失,此項值賦值為 NO_INDEX=0xffff ffff。

  • annotions_off: 值是一個位移地址,指向的內容是該 class 的注釋,位置在 data 區,格式為 annotations_direcotry_item。若沒有此項內容,值為 0 。

  • class_data_off: 值是一個位移地址,指向的內容是該 class 的使用到的資料,位置在 data 區,格式為 class_data_item。若沒有此項內容值為 0。該結構裡有很多內容,詳細描述該 class 的 field、method, method 裡的執行代碼等資訊,後面會介紹 class_data_item

  • static_value_off: 值是一個位移地址 ,指向 data 區裡的一個列表 (list),格式為 encoded_array_item。若沒有此項內容值為 0。

type_list

type_list 在 data 區段,class_def_item->interface_off 就是指的這裡的資料。資料結構如下:

uint   32-bit unsigned int, little-endianstruct type_list{    uint       size;    type_item  list [size] }struct type_item{    ushort type_idx   //-->type_ids}
  • size: 表示類型個數

  • type_idx: 對應一個 type_ids 的 index

annotations_directory_item

class_def_item->annotations_off 指向的資料區段,定義了 annotation 相關的資料描述,資料結構如下:

uint   32-bit unsigned int, little-endianstruct annotation_directory_item{    uint class_annotations_off;        //-->annotation_set_item    uint fields_size;    uint annotated_methods_size;    uint annotated_parameters_size;        field_annotation field_annotations[fields_size];    method_annotation method_annotations[annotated_methods_size];    parameter_annotation parameter_annotations[annotated_parameters_size];}struct field_annotation{    uint field_idx;    uint annotations_off;    //-->annotation_set_item}struct method_annotation{    uint method_idx;    uint annotations_off;    //-->annotation_set_item}struct parameter_annotation{    uint method_idx;    uint annotations_off;    //-->annotation_set_ref_list}
  • class_annotations_off: 這個位移指向了 annotation_set_item 具體的可以看 dex-format.html 上的介紹。

  • fields_size: 表示屬性的個數

  • annotated_methods_size: 表示方法的個數

  • annotated_parameters_size: 表示參數的個數

class_data_item

class_data_off 指向 data 區裡的 class_data_item 結構,class_data_item 裡存放著本 class 使用到的各種資料,下面是 class_data_item 的結構 :

uleb128 unsigned little-endian base 128 struct class_data_item{    uleb128 static_fields_size;    uleb128 instance_fields_size;    uleb128 direct_methods_size;    uleb128 virtual_methods_size;    encoded_field  static_fields[static_fields_size];    encoded_field  instance_fields[instance_fields_size];    encoded_method direct_methods[direct_methods_size];    encoded_method virtual_methods[virtual_methods_size];}struct encoded_field{    uleb128 filed_idx_diff;     uleb128 access_flags;  }struct encoded_method{    uleb128 method_idx_diff;     uleb128 access_flags;     uleb128 code_off;}

class_data_item

  • static_fields_size: 靜態成員變數的個數

  • instance_fields_size: 執行個體成員變數個數

  • direct_methods_size: 直接函數個數

  • virtual_methods_size: 虛函數個數

下面幾個就是對於的描述

encoded_field

  • method_idx_diff: 首碼 methd_idx 表示它的值是 method_ids 的一個 index ,尾碼 _diff 表示它是於另 外一個 method_idx 的一個差值 ,就是相對於 encodeed_method [] 數組裡上一個元素的 method_idx 的差值 。 其實 encoded_filed - > field_idx_diff 表示的也是相同的意思 ,只是編譯出來的 Hello.dex 檔案裡沒有使用到 class filed 所以沒有仔細講 ,詳細的參考 dex_format.html 的官網文檔。

  • access_flags: 存取權限,比如 public、private、static、final 等。

  • code_off: 一個指向 data 區的位移地址,目標是本 method 的代碼實現。被指向的結構是code_item,有近 10 項元素。

code_item

code_item 結構裡描述著某個 method 的具體實現,它的結構描述如下:

struct code_item {    ushort                         registers_size;    ushort                         ins_size;    ushort                         outs_size;    ushort                         tries_size;    uint                         debug_info_off;    uint                         insns_size;    ushort                         insns [insns_size];     ushort                         paddding;             // optional    try_item                     tries [tyies_size]; // optional    encoded_catch_handler_list  handlers;             // optional}

末尾的 3 項標誌為 optional , 表示可能有 ,也可能沒有 ,根據具體的代碼來。

  • registers_size: 本段代碼使用到的寄存器數目。

  • ins_size: method 傳入參數的數目 。

  • outs_size: 本段代碼調用其它 method 時需要的參數個數 。

  • tries_size: try_item 結構的個數 。

  • debug_off: 位移地址,指向本段代碼的 debug 資訊存放位置,是一個 debug_info_item 結構。

  • insns_size: 指令列表的大小,以 16-bit 為單位。 insns 是 instructions 的縮寫 。

  • padding: 值為 0,用於對齊位元組 。

  • tries 和 handlers: 用於處理 java 中的 exception,常見的文法有 try catch。

encoded_array_item

class_def_item->static_value_off 位移指向該區段資料。

uleb128  unsigned LEB128, valriable lengthstruct encoded_array_item{    encoded_array value;}struct encoded_array{        uleb128 size;    encoded_value values[size];}
  • size : 表示encoded_value 個數

  • encoded_value: 這個我也沒分析出來怎麼搞得??

0x09 map_list

map_list 中大部分 item 跟 header 中的相應描述相同,都是介紹了各個區的位移和大小,但是 map_list 中描述的更加全面,包括了 HEADER_ITEM 、TYPE_LIST、STRING_DATA_ITEM、DEBUG_INFO_ITEM 等資訊。

010 中map_list 表示為:

資料結構為:

ushort 16-bit unsigned int, little-endianuint   32-bit unsigned int, little-endianstruct map_list {    uint     size;    map_item list [size]; }struct map_item {    ushort type;     ushort unuse;     uint   size;     uint   offset;}

map_list 裡先用一個 uint 描述後面有 size 個 map_item,後續就是對應的 size 個 map_item 描述。 map_item 結構有 4 個元素: type 表示該 map_item 的類型,Dalvik Executable Format 裡 Type Code 的定義; size 表示再細分此 item,該類型的個數;offset 是第一個元素的針對檔案初始位置的位移量; unuse 是用對齊位元組的,無實際用處。

[Android Security] DEX檔案格式分析

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.