通過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裡,這樣就省去