限制

.dex 檔案是 Dalvik 位元碼的傳輸格式。檔案必須符合特定的語法和語義限制,才能成為有效的 .dex 檔案,而執行階段則必須只支援有效的 .dex 檔案。

一般 .dex 完整性限制

一般完整性限制與 .dex 檔案的較大結構有關,詳情請參閱 .dex 格式

ID 說明
G1 .dex 檔案的 magic 編號必須是 dex\n035\0 (適用於 35 以上版本),或類似的編號 (適用於較新版本)。
G2 總和檢查碼必須是整個檔案內容的 Adler-32 總和檢查碼,但 magicchecksum 欄位除外。
G3 簽章必須是整個檔案內容的 SHA-1 雜湊,但 magicchecksumsignature 除外。
G4

file_size 必須與實際檔案大小相符,以位元組為單位。(v40 或更早版本)

file_size 必須指向容器中的下一個標頭,或指向實體檔案 (容器) 的結尾。如果指向下一個標頭,檔案大小必須以 4 位元組對齊。所有 file_size 欄位的總和必須等於 container_size(41 以上版本)

G5

header_size 必須具有以下值:0x70 (v40 或更早版本)

header_size 必須設為以下值:0x78 (v41 以上版本)

G6 endian_tag 必須具有以下值: ENDIAN_CONSTANTREVERSE_ENDIAN_CONSTANT
G7

對於每個 linkstring_idstype_idsproto_idsfield_idsmethod_idsclass_defsdata 區段,offsetsize 欄位都必須為零或非零。在後一種情況下,偏移量必須以四個位元組對齊。

offsetsize 欄位必須位於容器內,並參照定義這些欄位的標頭後方的資料。(41 以上版本)

G8 標頭中所有偏移欄位 (map_off 除外) 都必須四個位元組對齊。
G9 map_off 欄位必須為零或指向資料區段。在後一種情況下,data 部分必須存在。
G10 linkstring_idstype_idsproto_idsfield_idsmethod_idsclass_defsdata 區段不得彼此重疊或重疊至標題。
G11 如果有地圖,則每個地圖項目都必須具有有效的類型。每個類型最多只能出現一次。
G12 如果有對應圖,則每個對應圖項目都必須有非零的偏移量和大小。偏移值必須指向檔案的對應部分 (也就是 string_id_item 必須指向 string_ids 部分),且項目的明確或隱含大小必須與該部分的實際內容和大小相符。
G13 如果地圖存在,地圖項目 n+1 的偏移量必須大於或等於地圖項目 n plus than size of map entry n 的偏移量。這表示不重疊的項目和由低至高的排序。
G14 下列類型的項目必須有四個位元組對齊的偏移量:string_id_itemtype_id_itemproto_id_itemfield_id_itemmethod_id_itemclass_def_itemtype_listcode_itemannotations_directory_item
G15

對於每個 string_id_itemstring_data_off 欄位必須包含指向 data 區段的有效參照。(v40 或更早版本)

對於每個 string_id_itemstring_data_off 欄位必須是容器中的偏移值,且位於任何會間接使用該欄位的標頭之後。(41 以上版本)

對於參照的 string_data_itemdata 欄位必須包含有效的 MUTF-8 字串,且 utf16_size 必須與字串的解碼長度相符。

G16 對於每個 type_id_itemdescriptor_idx 欄位都必須包含有效的 string_ids 清單參照。參照的字串必須是有效的類型描述符。
G17 對於每個 proto_id_itemshorty_idx 欄位都必須包含有效的 string_ids 清單參照。參照的字串必須是有效的短代碼描述元。此外,return_type_idx 欄位必須是 type_ids 區段的有效索引,而 parameters_off 欄位必須是零,或是指向 data 區段的有效偏移量。如果不為零,參數清單不得包含任何無效項目。
G18 對於每個 field_id_itemclass_idxtype_idx 欄位都必須是 type_ids 清單中的有效索引。class_idx 參照的項目必須是非陣列參照類型。此外,name_idx 欄位必須是 string_ids 區段的有效參照,且參照項目的內容必須符合 MemberName 規格。
G19 對於每個 method_id_itemclass_idx 欄位必須是 type_ids 區段中的有效索引,且參照的項目必須是陣列以外的參照類型。proto_id 欄位必須是 proto_ids 清單中的有效參照。name_idx 欄位必須是 string_ids 部分的有效參照,且參照項目的內容必須符合 MemberName 規格。
G20 對於每個 field_id_itemclass_idx 欄位必須是 type_ids 清單中的有效索引。參照的項目必須是非陣列參照類型。

靜態位元碼限制

靜態限制是對位元碼個別元素的限制。通常不需要採用控制或資料流分析技術,即可檢查這些項目。

ID 說明
A1 insns 陣列不得為空白。
A2 insns 陣列中的第一個 Opcode 必須有索引 0。
A3 insns 陣列只能包含有效的 Dalvik 指令碼。
A4 指令 n+1 的索引必須等於指令 n 的索引加上指令 n 的長度,並考量可能的運算元。
A5 insns 陣列中的最後一個指令必須在索引 insns_size-1 結束。
A6 所有 gotoif-<kind> 目標都必須是同一個方法中的運算碼。
A7 packed-switch 指令的所有目標都必須是同一個方法中的運算碼。目標的大小和清單必須一致。
A8 sparse-switch 指令的所有目標都必須是同一個方法中的運算碼。對應的資料表必須一致,且以低至高的順序排序。
A9 const-stringconst-string/jumbo 指令的 B 運算元必須是字串常數集合的有效索引。
A10 iget<kind>iput<kind> 指令的 C 運算元必須是欄位常數集區的有效索引。參照的項目必須代表例項欄位。
A11 sget<kind>sput<kind> 指令的 C 運算元必須是欄位常數集區的有效索引。參照的項目必須代表靜態欄位。
A12 invoke-virtualinvoke-superinvoke-directinvoke-static 指令的 C 運算元必須是方法常數集區的有效索引。
A13 invoke-virtual/rangeinvoke-super/rangeinvoke-direct/rangeinvoke-static/range 指令的 B 運算元必須是方法常數集區的有效索引。
A14 名稱開頭為 '<' 的方法只能由 VM 隱含叫用,而非由來自 .dex 檔案的程式碼叫用。唯一例外狀況是執行個體初始化器,可能會由 invoke-direct 叫用。
A15 invoke-interface 指令的 C 運算元必須是方法常數集區中的有效索引。所參照的 method_id 必須屬於介面 (而非類別)。
A16 invoke-interface/range 指令的 B 運算元必須是方法常數集區中的有效索引。所參照的 method_id 必須屬於介面 (而非類別)。
A17 const-classcheck-castnew-instancefilled-new-array/range 指令的 B 運算元必須是類型常數集區的有效索引。
A18 instance-ofnew-arrayfilled-new-array 指令的 C 運算元必須是類型常數集區的有效索引。
A19 new-array 指令建立的陣列維度必須小於 256
A20 new 指令不得參照陣列類別、介面或抽象類別。
A21 new-array 指令所參照的類型必須是有效的非參照類型。
A22 以單一寬度 (非成對) 方式由指令參照的所有暫存器,必須對目前方法有效。也就是說,其索引必須是非負值,且小於 registers_size
A23 以雙寬度 (成對) 方式由指令參照的所有暫存器,必須對目前方法有效。也就是說,這些索引必須是非負值,且小於 registers_size-1
A24 invoke-virtualinvoke-direct 指令的 method_id 運算元必須屬於類別 (而非介面)。在 037 之前的 Dex 檔案中,invoke-superinvoke-static 指令也必須符合相同的條件。
A25 invoke-virtual/rangeinvoke-direct/range 指令的 method_id 運算元必須屬於類別 (而非介面)。在 037 之前的 Dex 檔案中,invoke-super/rangeinvoke-static/range 指令也必須符合相同的條件。

結構化位元碼限制

結構限制是指對位元碼的幾個元素之間關係的限制。通常必須採用控制或資料流分析技術,才能檢查這些問題。

ID 說明
B1 引數 (暫存器和立即值) 的數量和類型必須一律與指令相符。
B2 註冊組合不得分開。
B3 您必須先指派註冊 (或組合),才能讀取。
B4 invoke-direct 指令必須在目前類別或其中一個超類別中,呼叫例項初始化器或方法。
B5 例項初始化器只能在未初始化的例項上叫用。
B6 您只能在已初始化的例項上叫用例項方法,也只能在已初始化的例項上存取例項欄位。
B7 如果在執行個體初始化前再次執行相同的 new-instance 指令,則不得使用儲存 new-instance 指令結果的暫存器。
B8 在存取任何例項成員之前,例項初始化器必須呼叫另一個例項初始化器 (相同的類別或超類別)。例外狀況是未繼承的例項欄位,可在呼叫其他初始化器之前指派,以及一般 Object 類別。
B9 所有實際方法引數都必須與其對應的形式引數相容。
B10 針對每個例項方法叫用作業,實際例項必須與指令中指定的類別或介面相容。
B11 return<kind> 指令必須與其方法的傳回類型相符。
B12 存取父類別的受保護成員時,所存取的例項實際類型必須是目前類別或其子類別之一。
B13 儲存至靜態欄位的值類型,必須與欄位類型相容或可轉換為該類型。
B14 儲存至欄位的值類型必須與欄位類型相容,或可轉換為欄位類型。
B15 儲存至陣列的每個值的類型,必須與陣列的元件類型相容。
B16 throw 指令的 A 運算元必須與 java.lang.Throwable 相容。
B17 方法可到達的最後一個指令必須是回溯 goto 或分支、returnthrow 指令。insns 陣列不得留在底部。
B18 在未重新指派其他指令之前,先前註冊組未指派的一半可能無法讀取 (視為無效)。
B19 move-result<kind> 指令必須在 insns 陣列中,緊接著 invoke-<kind> 指令。唯一例外的是 move-result-object 指令,其前方也可能有 filled-new-array 指令。
B20 move-result<kind> 指令必須在實際控制流程中,立即接在相符的 return-<kind> 指令之前 (不得跳轉至該指令)。唯一例外的是 move-result-object 指令,其前方也可能有 filled-new-array 指令。
B21 move-exception 指令只能出現在例外狀況處理程序的第一個指令中。
B22 控制流程不得存取 packed-switch-datasparse-switch-datafill-array-data 擬似指令。