.dex
파일은 Dalvik 바이트 코드의 전송 포맷입니다. 파일이 유효한 .dex
파일이 되기 위한 특정한 문법적 제약 조건과 의미적 제약 조건이 있으며, 유효한 .dex 파일만 지원하기 위한 런타임이 필요합니다.
일반 .dex 무결성 제약 조건
일반 무결성 제약 조건은 .dex
형식에 자세히 설명된 것처럼 .dex
파일의 대규모 구조와 관련이 있습니다.
식별자 | 설명 |
---|---|
G1 | .dex 파일의 magic 숫자는 dex\n035\0 또는 dex\n037\0 이어야 합니다. |
G2 | 체크섬은 magic 및 checksum 필드를 제외한 전체 파일 콘텐츠의 Adler-32 체크섬이어야 합니다. |
G3 | 서명은 magic , checksum , signature 를 제외한 전체 파일 콘텐츠의 SHA-1 해시여야 합니다. |
G4 |
file_size 는 바이트 단위의 실제 파일 크기와 일치해야 합니다.
|
G5 |
header_size 는 값이 0x70 이어야 합니다.
|
G6 | endian_tag 는 값이 ENDIAN_CONSTANT 또는 REVERSE_ENDIAN_CONSTANT 중 하나여야 합니다. |
G7 |
각 link , string_ids , type_ids , proto_ids , field_ids , method_ids , class_defs , data 섹션에서 offset 및 size 필드는 모두 0이거나 모두 0이 아니어야 합니다. 후자의 경우 오프셋은 4바이트로 정렬되어야 합니다.
|
G8 |
헤더에서 map_off 를 제외한 모든 오프셋 필드는 4바이트로 정렬되어야 합니다.
|
G9 |
map_off 필드는 0이거나 데이터 섹션을 가리켜야 합니다. 후자의 경우에는 data 섹션이 있어야 합니다.
|
G10 | link , string_ids , type_ids , proto_ids , field_ids , method_ids , class_defs , data 섹션 중 어느 섹션도 서로 겹치거나 헤더와 겹쳐서는 안 됩니다. |
G11 | 지도가 있는 경우 각 지도 항목의 유형은 유효해야 합니다. 각 유형은 최대 한 번만 표시될 수 있습니다. |
G12 |
지도가 있는 경우 각 지도 항목의 오프셋과 크기는 0이 아니어야 합니다. 오프셋은 파일의 관련 섹션을 가리켜야 하고(예: string_id_item 은 string_ids 섹션을 가리켜야 함) 항목의 명시적 또는 암시적 크기는 섹션의 실제 콘텐츠 및 크기와 일치해야 합니다.
|
G13 |
지도가 있는 경우 지도 항목 n+1 의 오프셋은 지도 항목 n plus than size of map entry n 의 오프셋보다 크거나 같아야 합니다. 이는 항목이 중복되지 않고 오름차순으로 정렬됨을 의미합니다.
|
G14 | string_id_item , type_id_item , proto_id_item , field_id_item , method_id_item , class_def_item , type_list , code_item , annotations_directory_item 유형의 항목은 오프셋이 4바이트로 정렬되어야 합니다. |
G15 |
각 string_id_item 의 string_data_off 필드에는 data 섹션의 유효한 참조가 포함되어야 합니다. 참조된 string_data_item 의 경우 data 필드에는 유효한 MUTF-8 문자열이 포함되어야 하고 utf16_size 는 문자열의 디코딩된 길이와 일치해야 합니다.
|
G16 |
type_id_item 마다 descriptor_idx 필드에는 string_ids 목록의 유효한 참조가 포함되어야 합니다. 참조된 문자열은 유효한 유형 설명어여야 합니다.
|
G17 |
proto_id_item 마다 shorty_idx 필드에는 string_ids 목록의 유효한 참조가 포함되어야 합니다. 참조된 문자열은 유효한 짧은 설명어여야 합니다. 또한, return_type_idx 필드는 type_ids 섹션의 유효한 색인이어야 하고, parameters_off 필드는 0이거나 data 섹션을 가리키는 유효한 오프셋이어야 합니다. 0이 아닌 경우 매개변수 목록에는 무효한 항목이 있어서는 안 됩니다.
|
G18 |
field_id_item 마다 class_idx 필드와 type_idx 필드가 모두 type_ids 목록의 유효한 색인이어야 합니다. class_idx 에 의해 참조되는 항목은 비배열 참조 유형이어야 합니다. 또한, name_idx 필드는 string_ids 섹션의 유효한 참조여야 하고 참조된 항목의 콘텐츠는 MemberName 사양을 준수해야 합니다.
|
G19 |
method_id_item 마다 class_idx 필드는 type_ids 섹션의 유효한 색인이어야 하고 참조된 항목은 비배열 참조 유형이어야 합니다. proto_id 필드는 proto_ids 목록의 유효한 참조여야 합니다. name_idx 필드는 string_ids 섹션의 유효한 참조여야 하고 참조된 항목의 콘텐츠는 MemberName 사양을 준수해야 합니다.
|
G20 |
field_id_item 마다 class_idx 필드는 type_ids 목록의 유효한 색인이어야 합니다. 참조된 항목은 비배열 참조 유형이어야 합니다.
|
정적 바이트 코드 제약 조건
정적 제약 조건은 바이트 코드의 개별 요소에 적용되는 제약 조건입니다. 일반적으로 정적 제약 조건은 제어 흐름 또는 데이터 흐름 분석 기법을 사용하지 않고 확인할 수 있습니다.
식별자 | 설명 |
---|---|
A1 |
insns 배열은 비워 두면 안 됩니다.
|
A2 |
insns 배열에서 첫 번째 명령 코드는 색인이 0이어야 합니다.
|
A3 |
insns 배열은 유효한 Dalvik 명령 코드만 포함해야 합니다.
|
A4 | 명령어 n+1 의 색인은 가능한 피연산자를 고려할 때 명령어 n 의 색인과 명령어 n 의 길이를 더한 값과 같아야 합니다. |
A5 | insns 배열의 마지막 명령어는 색인 insns_size-1 에서 끝나야 합니다. |
A6 | 모든 goto 타겟과 if-<kind> 타겟은 동일한 메서드 내의 명령 코드여야 합니다. |
A7 |
packed-switch 명령어의 모든 타겟은 동일한 메서드 내의 명령 코드여야 합니다. 타겟의 크기와 목록은 일관되어야 합니다.
|
A8 |
sparse-switch 명령어의 모든 타겟은 동일한 메서드 내의 명령 코드여야 합니다. 관련 테이블은 일관되고 오름차순으로 정렬되어야 합니다.
|
A9 | const-string 명령어와 const-string/jumbo 명령어의 B 피연산자는 문자열 상수 풀의 유효한 색인이어야 합니다. |
A10 |
iget<kind> 명령어와 iput<kind> 명령어의 C 피연산자는 필드 상수 풀의 유효한 색인이어야 합니다. 참조된 항목은 인스턴스 필드를 나타내야 합니다.
|
A11 |
sget<kind> 명령어와 sput<kind> 명령어의 C 피연산자는 필드 상수 풀의 유효한 색인이어야 합니다. 참조된 항목은 정적 필드를 나타내야 합니다.
|
A12 | invoke-virtual , invoke-super , invoke-direct , invoke-static 명령어의 C 피연산자는 메서드 상수 풀의 유효한 색인이어야 합니다. |
A13 | invoke-virtual/range , invoke-super/range , invoke-direct/range , invoke-static/range 명령어의 B 피연산자는 메서드 상수 풀의 유효한 색인이어야 합니다. |
A14 |
이름이 '<'로 시작하는 메서드는 .dex 파일에서 시작하는 코드가 아닌 VM에 의해서만 암시적으로 호출되어야 합니다. 단, 인스턴스 이니셜라이저는 예외적으로 invoke-direct 에 의해 호출될 수 있습니다.
|
A15 |
invoke-interface 명령어의 C 피연산자는 메서드 상수 풀의 유효한 색인이어야 합니다. 참조된 method_id 는 클래스가 아닌 인터페이스에 속해야 합니다.
|
A16 |
invoke-interface/range 명령어의 B 피연산자는 메서드 상수 풀의 유효한 색인이어야 합니다.
참조된 method_id 는 클래스가 아닌 인터페이스에 속해야 합니다.
|
A17 | const-class , check-cast , new-instance , filled-new-array/range 명령어의 B 피연산자는 유형 상수 풀의 유효한 색인이어야 합니다. |
A18 | instance-of , new-array , filled-new-array 명령어의 C 피연산자는 유형 상수 풀의 유효한 색인이어야 합니다. |
A19 | new-array 명령어에 의해 생성된 배열의 차원은 256 보다 작아야 합니다. |
A20 | new 명령어는 배열 클래스, 인터페이스 또는 추상 클래스를 참조해서는 안 됩니다. |
A21 | new-array 명령어에 의해 참조되는 유형은 유효한 비참조 유형이어야 합니다. |
A22 |
명령어에 의해 단일 너비(쌍 아님) 형태로 참조되는 모든 레지스터는 현재 메서드에 유효해야 합니다. 즉, 색인이 음수가 아니고 registers_size 보다 작아야 합니다.
|
A23 |
명령어에 의해 이중 너비(쌍) 형태로 참조되는 모든 레지스터는 현재 메서드에 유효해야 합니다. 즉, 색인이 음수가 아니고 registers_size-1 보다 작아야 합니다.
|
A24 |
invoke-virtual 및 invoke-direct 명령어의 method_id 피연산자는 인터페이스가 아닌 클래스에 속해야 합니다. 버전 037 이전의 Dex 파일에서 invoke-super 및 invoke-static 명령어도 마찬가지여야 합니다.
|
A25 |
invoke-virtual/range 및 invoke-direct/range 명령어의 method_id 피연산자는 인터페이스가 아닌 클래스에 속해야 합니다. 버전 037 이전의 Dex 파일에서 invoke-super/range 및 invoke-static/range 명령어도 마찬가지여야 합니다.
|
구조적 바이트 코드 제약 조건
구조적 제약 조건은 바이트 코드의 여러 요소 간의 관계에 적용되는 제약 조건입니다. 일반적으로 구조적 제약 조건은 제어 흐름 또는 데이터 흐름 분석 기법을 사용하지 않고는 확인할 수 없습니다.
식별자 | 설명 |
---|---|
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 또는 분기이거나 return 또는 throw 명령어이어야 합니다. insns 배열을 하단에 둘 수 없어야 합니다.
|
B18 | 이전 레지스터 쌍 중 할당되지 않은 절반은 다른 명령어에 의해 다시 할당될 때까지 읽을 수 없습니다(유효하지 않은 것으로 간주됨). |
B19 |
insns 배열에서 move-result<kind> 명령어 바로 앞에는 invoke-<kind> 명령어가 와야 합니다. 단, move-result-object 명령어는 예외입니다. 이 명령어 앞에는 filled-new-array 명령어가 올 수도 있습니다.
|
B20 |
실제 제어 흐름에서 move-result<kind> 명령어 바로 앞에는 일치하는 return-<kind> 명령어가 와야 합니다(바로 건너뛸 수 없어야 함). 단, move-result-object 명령어는 예외입니다. 이 명령어 앞에는 filled-new-array 명령어가 올 수도 있습니다.
|
B12 | move-exception 명령어는 예외 핸들러의 첫 번째 명령어로만 표시되어야 합니다. |
B22 | packed-switch-data , sparse-switch-data 및 fill-array-data 의사 명령어는 제어 흐름을 통해 도달 가능해서는 안 됩니다. |