1. 程式人生 > >通過dexdump來學習DEX檔案格式

通過dexdump來學習DEX檔案格式

一、dexdump簡介

dexdump是android提供的一個dex檔案檢視工具,在4.4之前的版本上,我們可以在dalvik的dexdump目錄找到原始碼。這個工具簡單而且全面。通過學習這個工具的原始碼,我們可以很快的對dex檔案有一個全面的瞭解。
首先看下dexdump的命令列引數:

dexdump: [-c] [-d] [-f] [-h] [-i] [-l layout] [-m] [-t tempfile]
dexfile…

-c : verify checksum and exit
-d : disassemble code sections
-f : display summary information from file header
-h : display file header details
-i : ignore checksum failures
-l : output layout, either ‘plain’ or ‘xml’
-m : dump register maps (and nothing else)
-t : temp file name (defaults to /sdcard/dex-temp-*)

引數都很淺顯易懂,沒有什麼好說的。因為dex檔案是多個class的集合,因此我們只要看每個class是怎樣定義的即可。下面這個例子是一個最簡單的class,沒有任何field,只要一個無程式碼的方法,dump出的結果如下:

Class #110            -
  Class descriptor  : 'Landroid/widget/Filterable;'
  Access flags      : 0x0601 (PUBLIC INTERFACE ABSTRACT)
  Superclass        : 'Ljava/lang/Object;'
  Interfaces        -
  Static
fields - Instance fields - Direct methods - Virtual methods - #0 : (in Landroid/widget/Filterable;) name : 'getFilter' type : '()Landroid/widget/Filter;' access : 0x0401 (PUBLIC ABSTRACT) code : (none) source_file_idx : 12206
(Filterable.java)

可以看到,dexdump按照類的定義,清晰的列出了其結構和內容。
下面看一個對field的dump(static和instance field的dump是一樣的)

    #1              : (in Landroid/app/Activity;)
      name          : 'DEFAULT_KEYS_DIALER'
      type          : 'I'
      access        : 0x0019 (PUBLIC STATIC FINAL)

給出了field的name, type, access這些定義。

在看method的定義

  #12              : (in Landroid/widget/ArrayAdapter;)
      name          : 'createViewFromResource'
      type          : '(ILandroid/view/View;Landroid/view/ViewGroup;I)Landroid/view/View;'
      access        : 0x0002 (PRIVATE)
      code          -
      registers     : 12
      ins           : 5
      outs          : 4
      insns size    : 66 16-bit code units
18abd4:                                        |[18abd4] android.widget.ArrayAdapter.createViewFromResource:(ILandroid/view/View;Landroid/view/ViewGroup;I)Landroid/view/View;
18abe4: 3909 1f00                              |0000: if-nez v9, 001f // +001f
....
18abec: 1206                                   |0004: const/4 v6, #int 0 // #0
.....
18ac60: 6e20 6bde 5300                         |003e: invoke-virtual {v3, v5}, Landroid/widget/TextView;.setText:(Ljava/lang/CharSequence;)V // [email protected]
18ac66: 28dd                                   |0041: goto 001e // -0023
      catches       : 2
        0x0009 - 0x0011
          Ljava/lang/ClassCastException; -> 0x002a
        0x0021 - 0x0029
          Ljava/lang/ClassCastException; -> 0x002a
      positions     : 
        0x0000 line=370
        0x0002 line=371
        0x0009 line=377
        0x000d line=379
....
        0x0032 line=386
        0x003a line=394
      locals        : 
        0x0000 - 0x0000 reg=7 this Landroid/widget/ArrayAdapter; 
        0x0015 - 0x001b reg=2 item Ljava/lang/Object; TT;
...
        0x0000 - 0x0042 reg=10 parent Landroid/view/ViewGroup; 
        0x0000 - 0x0042 reg=11 resource I 

因為例子很長,且我們關心的是method的格式,所以我省略了很多細節內容。可以清楚的看到,dump出的內容包括method的資訊頭(名字、型別、許可權)、程式碼段的資訊(大小、暫存器總數、引數個數等)、程式碼段內容、catch內容、原始碼與位元組碼的行對應關係、暫存器與變數的對應關係。
其中行號對應與變數對應關係是除錯、丟擲異常時必須的內容。這兩部分內容開始的位置都是基於本方法程式碼的開頭位置,通過位元組碼的偏移範圍來實現的。

如何在呼叫dexdump時加上-h選項,就會得到關於class header的資訊,這些資訊是更加原始的關於class定義的資訊。例如下面的例子

Class #0 header:
class_idx           : 6
access_flags        : 17 (0x0011)
superclass_idx      : 5731
interfaces_off      : 0 (0x000000)
source_file_idx     : 25093
annotations_off     : 5329644 (0x5152ec)
class_data_off      : 8673220 (0x8457c4)
static_fields_size  : 233
instance_fields_size: 0
direct_methods_size : 1
virtual_methods_size: 0

這些資訊對我們瞭解class在dex中的定義很有幫助。

二、dexdump的入口程式碼及頭部資訊

dexdump的全部實現是在dalvik/dexdump/DexDump.cpp檔案。當然,它大量使用了dalvik內部的標頭檔案和庫檔案,這樣即節省了很多程式碼,又能保證與dalvik同步。

入口函式是main,main函式之前處理引數部分很簡單,我們省略不看。在main函式結尾處,有如下程式碼:

    int result = 0;
    while (optind < argc) {
        result |= process(argv[optind++]);
    }

dexdump可同時dump多個檔案,主要的函式是process。
process函式呼叫dexOpenAndMap函式,開啟並將檔案對映到記憶體中,然後呼叫dexFileParse函式,得到一個DexFile物件,最後呼叫processDexFile來dump具體內容。

dexOpenAndMap函式可以接受以.zip/.jar/.apk為結尾的檔案。對於這些檔案,dexdump會先對他們進行解壓(通過dexUnzipToFile)將其中的classes.dex檔案提取出來後,在開啟並對映。

dexFileParse函式主要是將檔案內容載入到一個DexFile物件,這只是初步載入,將檔案頭及基本資訊載入即可。dexdump不僅可以處理dex檔案,也可以處理經過優化後的odex檔案。odex檔案的具體格式在下期內容詳細介紹,這裡我們只關注dex檔案。odex與dex的區別不在於檔案字尾名,而是檔案開頭的魔數。dex的魔數是DEX_MAGIC, 即”dex\n”,而odex的魔數是DEX_OPT_MAGIC,即”dey\n”。

關於DexFile的詳細內容,見下面小節dumpFileHeader.

processDexFile函式呼叫了幾個重要的函式:

  • dumpStrings: dump字串池
  • dumpRegisterMaps: dump 暫存器與物件的對應關係
  • dumpFileHeader: dump dex檔案頭
  • dumpOptDirectory: dump odex的相關內容
  • dumpClass: dump 一個類

dumpFileHeader

dexdump -f 引數可以dump出dex檔案的骨架。其中最開始的幾行就是檔案頭,就是dex檔案的頭部資訊。

下面的例子是dexdump -f framework.jar的結果(頭部部分)

Processing 'out/target/product/xxx/system/framework/framework.jar'...
Opened 'out/target/product/mocha/system/framework/framework.jar', DEX version '035'
DEX file header:
magic               : 'dex\n035\0'
checksum            : 2f03ef9e
signature           : bfb4...2303
file_size           : 9105424
header_size         : 112
link_size           : 0
link_off            : 0 (0x000000)
string_ids_size     : 85794
string_ids_off      : 112 (0x000070)
type_ids_size       : 6685
type_ids_off        : 343288 (0x053cf8)
proto_ids_size       : 12195
proto_ids_off        : 370028 (0x05a56c)
field_ids_size      : 39764
field_ids_off       : 516368 (0x07e110)
method_ids_size     : 60182
method_ids_off      : 834480 (0x0cbbb0)
class_defs_size     : 5454
class_defs_off      : 1315936 (0x141460)
data_size           : 7614960
data_off            : 1490464 (0x16be20)

下面我們來解釋下每個部分的內容:
magic 部分表示這是一個dex檔案,版本為035。
從string_ids_size, string_ids_off開始到最後method_ids_size和method_ids_off都是各個常量池的大小和偏移。

為了更清楚瞭解個部分的內容,我們看DexFile的結構:

struct DexFile {
    /* directly-mapped "opt" header */
    const DexOptHeader* pOptHeader;

    /* pointers to directly-mapped structs and arrays in base DEX */
    const DexHeader*    pHeader;
    const DexStringId*  pStringIds;
    const DexTypeId*    pTypeIds;
    const DexFieldId*   pFieldIds;
    const DexMethodId*  pMethodIds;
    const DexProtoId*   pProtoIds;
    const DexClassDef*  pClassDefs;
    const DexLink*      pLinkData;

    /*
     * These are mapped out of the "auxillary" section, and may not be
     * included in the file.
     */
    const DexClassLookup* pClassLookup;
    const void*         pRegisterMapPool;       // RegisterMapClassPool

    /* points to start of DEX file data */
    const u1*           baseAddr;

    /* track memory overhead for auxillary structures */
    int                 overhead;

    /* additional app-specific data structures associated with the DEX */
    //void*               auxData;
};

其中baseAddr的地址是對映後dex檔案的開始位置。baseAddr加上上面提到的各種偏移,就是對應資料(pStringIds, pTypeIds等)的地址了。DexHeader的資料結構與dex檔案結構是一致的,下面是它的定義:

struct DexHeader {
    u1  magic[8];           /* includes version number */
    u4  checksum;           /* adler32 checksum */
    u1  signature[kSHA1DigestLen]; /* SHA-1 hash */
    u4  fileSize;           /* length of entire file */
    u4  headerSize;         /* offset to start of next section */
    u4  endianTag;
    u4  linkSize;
    u4  linkOff;
    u4  mapOff;
    u4  stringIdsSize;
    u4  stringIdsOff;
    u4  typeIdsSize;
    u4  typeIdsOff;
    u4  protoIdsSize;
    u4  protoIdsOff;
    u4  fieldIdsSize;
    u4  fieldIdsOff;
    u4  methodIdsSize;
    u4  methodIdsOff;
    u4  classDefsSize;
    u4  classDefsOff;
    u4  dataSize;
    u4  dataOff;
};

下面用一個表詳細說明下各個Ids的作用、對應的資料結構、獲取函式資訊。

Ids型別 作用說明 對應的資料結構 獲取函式 說明
stringsIds 儲存所有用到的字串的索引 DexStringId dexGetStringId DexStringId包含 u4 stringDataOff; 該成員指出字串在常量池中偏移,通過dexGetStringData可以取得真正的字串。 dexStringById 函式可以直接用string id索引得到字串值
typeIds 儲存class, 基礎型別的表 DexTypeId dexGetTypeId, dexStringByTypeIdx DexTypeId 只包含u4 descriptorIdx; 這是一個DexStringId的索引。使用dexStringByTypeIdx可以直接獲取對應的字串。Dex中的Type全部是用java全型別限定名來表示的
protoIds 儲存一個method引數及返回值型別的資料的索引 DexProtoId dexGetProtoId DexProtoId包含3個成員:shortyIdx: 返回值引數的短格式(1), 是一個stringsId值; returnTypeIdx:返回值型別,是一個typeId值; parametersOff: 相對與baseAddr的DexTypeList物件的偏移,DexTypeList是以描述每個引數型別的列表物件
fieldId 描述field資訊的索引 DexFieldId dexGetFieldId DexFieldId包含3個成員:classIdx: field所屬類的typeId值;typeIdx:field型別的typeId值;nameIdx: 名字的stringId值
methodId 描述一個方法的資訊索引 DexMethodId dexGetMethodId DexMethodId包含3個成員:classIdx: method所屬類的typeId值; protoIdx;method的引數及返回值索引,protoId索引; nameIdx: 名字的stringId值
classDefs 一個類的定義資訊 DexClassDef dexGetClassDef 定義了一個類

link和data這兩個在原始碼中很少使用,故不要考慮。

(1)引數的短格式是對函式引數的縮寫模式。主要將類的簽名縮寫為’L’,將陣列簽名縮寫為’[‘,每種用型別只佔一個字元。比如有函式簽名 “(IJDLandroid/view/View;[I)Landroid/view/View”, 他的短格式就是 LIJDL[。這裡第一個字元表示返回值。短格式有助於虛擬機器快速處理不需要了解引數具體型別的場合,如計算引數佔用空間大小時。

Class的定義

class的定義主要通過dumpClass函式實現。在瞭解dumpClass之前,我們先看看dumpClassDef函式。
ClassDef是一個類的總體定義,它的結構如下:

/*
 * Direct-mapped "class_def_item".
 */
struct DexClassDef {
    u4  classIdx;           /* index into typeIds for this class */
    u4  accessFlags;
    u4  superclassIdx;      /* index into typeIds for superclass */
    u4  interfacesOff;      /* file offset to DexTypeList */
    u4  sourceFileIdx;      /* index into stringIds for source file name */
    u4  annotationsOff;     /* file offset to annotations_directory_item */
    u4  classDataOff;       /* file offset to class_data_item */
    u4  staticValuesOff;    /* file offset to DexEncodedArray */
};

這裡包含了class的基本資訊。其中classDataOff是具體的class定義的資訊。staticValuesOff則是靜態資料的資訊。

通過呼叫dexGetClassDef函式可以獲取ClassDef資料,這個函式是從DexHeader中的classDefsOff加上具體的class索引獲得的。

ClassData

從dexGetClassData可以得到一個Encoded資料。這個Encodede是針對LEB128編碼而言的。

LEB128編碼規則

  • 以位元組為單位,按照小端規則排列
  • 每位元組最高位為標誌。如果最高位為1,表示有新位元組,如果為0,表示位元組序列結束
  • 依次將剩下7位組合,順序左移7位,生成整數。

例如有如下序列:

序列 A1,B2,C3,04
二進位制 1010 0001,1011 0010,1100 0011,0000 0100
去掉最高位 (010 0)(001 0)(11 00)(10 10) (0 001)(1 000) (0100)
並重新組合 4 2 C A 1 8 4
人類閱讀習慣 0×481AC24

ClassData的定義

函式dexReadAndVerifyClassData讀取並解碼ClassData,生成一個DexClassData的資料物件。首先,我們看看解碼後的資料結構(包括其子結構):

/* expanded form of a class_data_item header */
struct DexClassDataHeader {
    u4 staticFieldsSize;
    u4 instanceFieldsSize;
    u4 directMethodsSize;
    u4 virtualMethodsSize;
};

/* expanded form of encoded_field */
struct DexField {
    u4 fieldIdx;    /* index to a field_id_item */
    u4 accessFlags;
};

/* expanded form of encoded_method */
struct DexMethod {
    u4 methodIdx;    /* index to a method_id_item */
    u4 accessFlags;
    u4 codeOff;      /* file offset to a code_item */
};
/* expanded form of class_data_item. Note: If a particular item is
 * absent (e.g., no static fields), then the corresponding pointer
 * is set to NULL. */
struct DexClassData {
    DexClassDataHeader header;
    DexField*          staticFields;
    DexField*          instanceFields;
    DexMethod*         directMethods;
    DexMethod*         virtualMethods;
};

可以看到,主要包含的是field和method的資訊。

通過解讀dexReadAndVerifyClassData函式,我們可以清晰的看到一個Class的結構資訊。Class結構的資訊與上述結構的資訊,在順序上是一致的,只不過,對於每個field和每個method, 其中的field index與method index的值,不是絕對值,而是上一個值的差值。比如,對於static field,第一個static field的index是10,那麼第二static field的index值是12,那麼,在dex檔案中,第一個static field值儲存的是10,而第二個則是2。static field, instance field, direct method和virtual method,它們的第一個都是一個絕對索引值,而隨後的都是相對值。

這裡面提到的index值,都是對應的常量表的索引。

Method的引數表示

在dumpMethod的時候,時,根據methodIdx,可以得到Method的資料結構

/*
 * Direct-mapped "method_id_item".
 */
struct DexMethodId {
    u2  classIdx;           /* index into typeIds list for defining class */
    u2  protoIdx;           /* index into protoIds for method prototype */
    u4  nameIdx;            /* index into stringIds for method name */
};

可以看到DexMethodId中的幾個成員:classIdx表示method所屬類的typeId的索引,而nameIdx則是對應的method名字的stringId的索引。protoIdx則是method的引數與返回值的資訊。
protoIdx對應的是protoId的索引。

DexProtoId的定義如下:

/*
 * Direct-mapped "proto_id_item".
 */
struct DexProtoId {
    u4  shortyIdx;          /* index into stringIds for shorty descriptor */
    u4  returnTypeIdx;      /* index into typeIds list for return type */
    u4  parametersOff;      /* file offset to type_list for parameter types */
};

DexProtoId的成員已經在前面做個介紹,不必贅述。其中paramtersOff資料結構比較複雜,它指向一個DexTypeList的資料結構,通過函式dexGetProtoParameters可以獲取((pDexFile->baseAddr + pProtoId->parametersOff)。
DexTypeList的資料結構如下:

/*
 * Direct-mapped "type_item".
 */
struct DexTypeItem {
    u2  typeIdx;            /* index into typeIds */
};

/*
 * Direct-mapped "type_list".
 */
struct DexTypeList {
    u4  size;               /* #of entries in list */
    DexTypeItem list[1];    /* entries */
};

這個資料結構儲存了每個引數的型別的typeIdx,我們可以藉此得到所有引數資訊。
使用函式dexProtoGetMethodDescriptor可以將TypeList轉換為可以閱讀的引數簽名。

dumpCode

DexCode

通過dexGetCode可以得到結構DexCode。DexCode的值就是 pDexFile->baseAddr + pDexMethod->codeOff。
DexCode的程式碼是

/*
 * Direct-mapped "code_item".
 *  * The "catches" table is used when throwing an exception,
 * "debugInfo" is used when displaying an exception stack trace or
 * debugging. An offset of zero indicates that there are no entries.
 */
struct DexCode {
    u2  registersSize;
    u2  insSize;
    u2  outsSize;
    u2  triesSize;
    u4  debugInfoOff;       /* file offset to debug info stream */
    u4  insnsSize;          /* size of the insns array, in u2 units */
    u2  insns[1];
    /* followed by optional u2 padding */
    /* followed by try_item[triesSize] */
    /* followed by uleb128 handlersSize */
    /* followed by catch_handler_item[handlersSize] */
};
  • registersSize:該method所有用到的暫存器總數;
  • insSize: 該method的引數。引數的索引是從registersSize - insSize開始的。如果是非static Method,第一個引數是隱藏的this指標
  • outsSize: 該函式呼叫其他函式用到的暫存器的個數。給虛擬機器用的,不用考慮
  • triesSize: try-catch塊的個數
  • debugInfoOff: debug資訊的偏移,相對於baseAddr
  • insnsSize: 程式碼的大小,不包括try catch資訊,以unsigned short為單位

程式碼的資料可以通過dumpBytecodes函式進行反彙編。

try-catch資訊

dumpCatches函式用於dump try-catch資訊。
DexTry資料是Try的資料結構,這不是LEB128資料結構。通過dexGetTries方法獲得,獲取方法是DexCode::insns + pCode->insnsSize處的資料。
DexTry的結構是

/*
 * Direct-mapped "try_item".
 */
struct DexTry {
    u4  startAddr;          /* start address, in 16-bit code units */
    u2  insnCount;          /* instruction count, in 16-bit code units */
    u2  handlerOff;         /* offset in encoded handler data to handlers */
};
  • DexTry陣列的個數由DexCode::triesSize指定
  • startAddr: try塊的開始位置
  • insnCount: try塊的個數,2位元組為單位 handlerOff: catch處理塊的資訊的偏移

訪問handler部分的資料,需要用到輔助類DexCatchIterator。try-catch塊中,catch可以有很多個,最後以finally結束,finally是可選的。不管是catch還是finally,都是通過DexCatchHandler結構來表示的。

handler資料是用LEB128表示的。handlerOff指出handler資料開始處。資料開始處是catch的count,隨後是連續的LEB128表示的DexCatchHandler資料。
如果catch的count數為負數,表示存在一個finally塊,如果是正數,則表示沒有finally塊

DexCatchHandler的結構是

/*
 * Catch handler entry, used while iterating over catch_handler_items.
 */
struct DexCatchHandler {
    u4          typeIdx;    /* type index of the caught exception type */
    u4          address;    /* handler address */
};
  • typeIdx是typeIds陣列的索引,這個是catch塊中Exception類的型別的索引
  • address是catch塊內程式碼的開始地址。這個地址指向DexCode::insns的偏移
    如果最後一個是finally塊,typeIdx的取值就是kDexNoIndex(即0xffffffff)

debug info

debug 資訊包括dex bytecode地址與原始碼的行號對應關係,與bytecode地址與虛擬暫存器型別的對應關係。

dexDexcodeDebugInfo函式是獲取debug資訊的核心函式。這個函式用兩個回撥函式來處理行號對應關係(DexDebugNewPositionCb)和暫存器對應關係(DexDebugNewLocalCb)。

該函式呼叫dexGetDebugInfoStream獲得debug資訊,其實現是pDexFile->baseAddr + pCode->debugInfoOff。
函式dexDecodeDebugInfo0負責解析debug資訊。

在瞭解debug資訊之前,先看看debug資訊dump出來後的結果。debug資訊dump後,形成positons和locals兩個資訊。postions的資訊例子如下:

      positions     : 
        0x0001 line=395
        0x0005 line=396
        0x0009 line=404
        0x000d line=427
        0x0010 line=428
        0x0013 line=429
        0x0014 line=405
        .....

左邊是address地址,右邊原始碼的line開始地址。
locals的例子如下:

      locals        : 
        0x000d - 0x0014 reg=4 res Z 
        0x0015 - 0x0028 reg=1 e Landroid/os/RemoteException; 
        0x0027 - 0x0028 reg=4 res Z 
        0x0029 - 0x003c reg=1 e Ljava/lang/RuntimeException; 
        0x003b - 0x003c reg=4 res Z 
        0x0005 - 0x0053 reg=0 data Landroid/os/Parcel; 
        0x003d - 0x0053 reg=1 e Ljava/lang/OutOfMemoryError; 
        0x004b - 0x0053 reg=2 re Ljava/lang/RuntimeException; 
        ....

左邊是地址範圍,右邊是reg的索引、對應的變數名與變數的型別簽名。他表示在一定地址範圍內,暫存器的型別是什麼。實際上暫存器是可以被複用的,一個暫存器在整個函式內部不會一成不變。

debug資訊中,行號對應關係與暫存器對應關係的資訊是混在一起的。整個資訊用LEB128編碼,其結構如下:

  • 第一個數字為line start,即該函式對應原始碼的開始位置;
  • 第二個數字為parameter size,即引數的個數;
  • 從第三個數字起,是paramter size個string index值,表示的引數的名字;
  • 從paramter size + 2個開始,資料分為兩類:
    • opcode+data,用一個opcode來表示資料的具體型別,後面根具體資料
    • address/line offsets值,即將bytecode的address值的偏移和line的偏移放在一個數字裡面

opcode與offsets的區分是依靠數值 。如果opcode >= 0 && opcode < 0x0a,那麼表示資料是opcode + data內容;否則,就表示address/line的offsets。

對於offsets形式,計算的方法是:

u4 adjust_code = opcode - 0x0a; //首先減去最大的opcode值
address += (adjust_code / 15);
line += -4 + (adjust_code % 15);

對於opcode,有幾種取值:

  • 0x00 (DBG_END_SEQUENCE), 表示debug資訊的結束
  • 0x01 (DBG_ADVANCE_PC), data為一個正整數, 表示將address += data;
  • 0x02 (DBG_ADVANCE_LINE), data為一個正整數,表示line += data;
  • 0x03 (DBG_START_LOCAL), 0x04(DBG_START_LOCAL_EXTENDED) , 表示開始一個新的暫存器資訊;
  • 0x05 (DBG_END_LOCAL), 表示結束一個暫存器資訊;
  • 0x06 (DBG_RESTART_LOCAL), 表示重新開始一個暫存器資訊;
  • 其他值(0x07~0x0a) 忽略。data為空。

line和address的對應關係非常容易理解。
注意:這些opcode與offsets都是交錯儲存在debug info資料中的。在解析debug info資料過程中,存在一個當前address, 當前line與當前local的概念,當前line與當前address總是相互對應的,而當前local總是與當前address對應的。

對於暫存器的對應關係,有幾點需要注意:

  • 在函式入口處,負責傳遞引數的暫存器(索引值最大的幾個暫存器):
    • 其資料型別是由定義在Method中的ProtoIdx型別來定義,即通過方法的引數簽名來獲取這些暫存器的型別資訊;
    • 其引數名字,由debug info資料中第二個數字指出paramter size,然後再由paramter size個string index指向stringIds中的索引,從而得到這些引數的名字;
    • 對於非static方法,有一個隱含的this指標,對應的暫存器的名字是”this”,而對應的型別則是當前method所屬的類,這個資訊沒有儲存在debug info中,但是可以通過method的資訊計算出來;
    • 這個時候,用作引數的暫存器(包括隱含的this指標所在的暫存器),其起始地址都是0;
  • DBG_START_LOCAL,DBG_START_LOCAL_EXTENDED:這兩個opcode表示一個新的暫存器資訊的開始。他們同時意味者老的暫存器資訊的結束:
    • opcode後續的資料,依次是:reg的索引,對應local變數的name的string index,對應的local變數的型別的type index,對應local變數的簽名的string index(僅opcode==DBG_START_LOCAL_EXTENDED時);
    • reg的索引表明當前處理的是哪個暫存器。它意味著,reg之前所對應local變數的範圍已經結束,同時reg對應的新的變數範圍已經開始,即當前 address值是reg之前對應local變數的endAddress,是新變數的startAddress;
  • DBG_END_LOCAL, 後續資料為reg的索引,表示對應的reg變數範圍結束,即當前address值是reg對應變數的endAddress
  • DBG_RESTART_LOCAL 後續資料為reg的索引,表示重新設定reg對應變數的範圍開始,即當前address值為reg對應變數的startAddress。

相關推薦

通過dexdump學習DEX檔案格式

一、dexdump簡介 dexdump是android提供的一個dex檔案檢視工具,在4.4之前的版本上,我們可以在dalvik的dexdump目錄找到原始碼。這個工具簡單而且全面。通過學習這個工具的原始碼,我們可以很快的對dex檔案有一個全面的瞭解。 首先

[譯]Dex檔案格式

Dex檔案格式 原文連結:https://blog.bugsnag.com/dex-and-d8/ 你是否好奇Android應用是如何編譯和到爆陳apk的呢?本文將以微型Dex檔案的實際例子深入Dalvik 可執行格式。 Dex檔案是什麼? Dex檔案包含最終由Androi

23.通過MS17_010學習msf對滲透的利用

  Metersploit 集成了滲透階段的全部利用,從漏洞探測,到漏洞利用,最後到後滲透階段。本次部落格主要拋磚引玉,通過對MS17_010漏洞的復現,來學習Metasploit。 漏洞環境:       靶機:windows 7 (192.

Java程式碼中如何通過 http上傳檔案

例子程式碼如下 package example.filetransfer; import java.io.*; import java.net.*; import java.util.*; public class HttpRequestUtil { /** * 傳送ge

httpclient通過POST上傳檔案,而不是通過流的形式,並在服務端進行解析(通過httpmime.jar操作)

1. 首先需要對應的JAR包 匯入 httpmime-4.1.1.jar。 package url; import io.IoStreamUtil; import java.io.File; import java.io.IOException; import jav

如何通過xshell 上傳檔案至linux

在linux安裝 yum -y install lrzsz  在xshell  輸入rz回車即可彈出輸入檔案框找到要傳到Linux的檔案確定即可 要是Linux傳出到windows 在li

Android Dex檔案格式解析(第二篇)

1 .DEX檔案中使用的資料型別 u1,u2,u4,u8表示佔某固定位元組的無符號數 sleb128表示有符號的LEB128型別資料,uleb128表示無符號的LEB128,uleb128p1表示無符號的LEB128+1 , 關於LEB128:

python解析xml檔案——通過etree解析xml檔案

利用from lxml import etree來解析 ---------------------------這個是有揹包的情況下--------------------------------- <?xmlversion="1.0" ?> <anno

通過示例學習ES2016, 2017, 2018的新特性

譯者按: 本文系統地總結了所有的新特性,並用淺顯的例子解釋。 為了保證可讀性,本文采用意譯而非直譯。另外,本文版權歸原作者所有,翻譯僅用於學習。 小編推薦:Fundebug專注於JavaScript、微信小程式、微信小遊戲,Node.js和Java線上b

Dex 檔案格式詳解

/* * 解析 Dex 檔案 */ #include "dex.h" #include <sstream> #include <string> #include <iostream> void DexFile::parseAllClass() { for (u4

ART深入淺出5--瞭解Dex檔案格式(2)

本文基於Android 7.1,不過因為從BSP拿到的版本略有區別,所以本文提到的原始碼未必與讀者找到的原始碼完全一致。本文在提供原始碼片斷時,將按照 <原始碼相對android工程的路徑>:<行號> <類名> <函式名

Android Dex檔案格式解析

Dex檔案是Android虛擬機器下的可執行檔案,包含了應用程式所用到所有操作指令和執行時資料。在程式編譯過程中,java原始檔先被編譯成class檔案,然後通過dx工具將多個class檔案整合為一個dex檔案。這樣的檔案結構使得各個類能夠共享資料,充分減少了儲存空間,提

【 Vivado 】在工程模式下通過jou檔案學習 Tcl 命令

Xilinx 的資料手冊UG895提供了一些系統級設計的方法,寫得很詳細,詳細到得不到重要的訊息(我菜)。 Tcl命令在工程模式下以及非工程模式下有一些差異,具體什麼差異,這裡暫時不說,後面我想應該會有一篇博文專門講解。(我懂了的話會有,我相信會有。) 這裡尋求一種方法來學習Vivado

通過編譯函數庫學習GCC【轉】

說了 代碼段 必須 () com 意義 同進程 變量 主程 轉自:http://blog.csdn.net/u012365926/article/details/51446295 基本概念 什麽是庫 在windows平臺和linux平臺下都大量存在著庫。 本質上

nginx功能之一可以啟動一個本地伺服器,通過配置server_name和root目錄等訪問目標檔案

  一. 下載 http://nginx.org/   下載後解壓   二. 修改配置檔案 nginx配置檔案在 nginx-1.8.0\conf\nginx.conf http { #壓縮html

PE檔案格式學習(二):總體結構

1.概述 PE檔案分為幾個部分,分別是: DOS頭 DOS Stub NT頭(PE頭) 檔案頭 可選頭 區段頭(一個數組,每個元素都是一個結構體,稱之為IMAGE_SECTION_HEADER) .text .rdata .data .rs

PE檔案格式學習(三):匯出表

1.回顧 上篇文章中介紹過,可選頭中的資料目錄表是一個大小為0x10的陣列,匯出表就是這個陣列中的第一個元素。 我們再回顧下資料目錄表的結構體: struct _IMAGE_DATA_DIRECTORY {     DWORD VirtualAddress;    

PE檔案格式學習(一):概述

1.PE檔案簡介 PE檔案格式是Windows系統中應用最廣泛的檔案格式之一,我們常見的可執行檔案.exe、動態連結庫.dll以及驅動檔案.sys等都是PE檔案格式的。 可以通過十六進位制工具如010editor檢視PE檔案,可以看到PE檔案都有一個共同的特點,就是它們的最開頭都是4D5A,也就是ASCI

PE檔案格式學習(十三):載入配置表

1.介紹 載入配置表早期是用於描述當PE檔案頭或PE可選頭無法描述或者因為太大而無法描述的各種功能。 後來以XP及以後的系統主要是為了儲存SEH控制代碼,稱為安全結構化異常處理程式列表,如果SEH異常處理沒有經過註冊,在載入配置表中沒有控制代碼,這個異常處理就不會被執行。 具體的例子就不演示了,看起來只要是

PE檔案格式學習(十四):繫結匯入表

1.介紹 繫結匯入表的作用是加快程式的啟動速度,一個PE程式在啟動時會去載入匯入表中的dll檔案,並將匯入表的FirstThunk指向的陣列填入函式的真實地址,這需要耗去時間,繫結匯入表中儲存了匯入函式的真實地址,所以當PE在啟動時系統檢測到有繫結匯入表,就會直接將地址填入FirstThunk裡,這樣就省去