Un fichier .dex
est le format de transport du bytecode Dalvik. Pour qu'un fichier soit un fichier .dex
valide, certaines contraintes syntaxiques et sémantiques doivent être respectées. De plus, un environnement d'exécution est nécessaire pour n'accepter que les fichiers .dex valides.
Contraintes générales d'intégrité des fichiers .dex
Les contraintes d'intégrité générales concernent la structure globale d'un fichier .dex
, comme décrit en détail dans le format .dex
.
Identifiant | Description |
---|---|
G1 |
Le numéro magic du fichier .dex doit être dex\n035\0 pour la version 35 ou similaire pour les versions ultérieures.
|
O2 |
La somme de contrôle doit être une somme de contrôle Adler-32 de l'intégralité du contenu du fichier, à l'exception des champs magic et checksum .
|
G3 |
La signature doit être un hachage SHA-1 de l'intégralité du contenu du fichier, à l'exception de magic , checksum et signature .
|
G4 |
|
G5 |
|
G6 |
endian_tag doit avoir la valeur ENDIAN_CONSTANT ou REVERSE_ENDIAN_CONSTANT .
|
G7 |
Pour chacune des sections
Les champs |
G8 |
Tous les champs de décalage de l'en-tête, à l'exception de map_off , doivent être alignés sur quatre octets.
|
G9 |
Le champ map_off doit être nul ou pointer vers la section de données. Dans ce dernier cas, la section data doit exister.
|
G10 |
Aucune des sections link , string_ids , type_ids , proto_ids , field_ids , method_ids , class_defs et data ne doit se chevaucher ni se superposer à l'en-tête.
|
G11 | Si une carte existe, chaque entrée de carte doit avoir un type valide. Chaque type ne peut apparaître qu'une seule fois. |
G12 |
Si une carte existe, chaque entrée de carte doit avoir un décalage et une taille non nuls. Le décalage doit pointer vers la section correspondante du fichier (c'est-à-dire qu'un string_id_item doit pointer vers la section string_ids ), et la taille explicite ou implicite de l'élément doit correspondre au contenu et à la taille réels de la section.
|
G13 |
Si une carte existe, le décalage de l'entrée de carte n+1 doit être supérieur ou égal au décalage de l'entrée de carte n plus than size of map entry n . Cela implique des entrées non superposées et un ordre de bas en haut.
|
G14 |
Les types d'entrées suivants doivent avoir un décalage aligné sur quatre octets: string_id_item , type_id_item , proto_id_item , field_id_item , method_id_item , class_def_item , type_list , code_item et annotations_directory_item .
|
G15 |
Pour chaque Pour chaque Pour le |
G16 |
Pour chaque type_id_item , le champ descriptor_idx doit contenir une référence valide dans la liste string_ids . La chaîne référencée doit être un descripteur de type valide.
|
G17 |
Pour chaque proto_id_item , le champ shorty_idx doit contenir une référence valide dans la liste string_ids . La chaîne référencée doit être un descripteur de raccourci valide. De plus, le champ return_type_idx doit être un indice valide dans la section type_ids , et le champ parameters_off doit être nul ou un décalage valide pointant vers la section data . Si la valeur n'est pas nulle, la liste des paramètres ne doit pas contenir d'entrées vides.
|
G18 |
Pour chaque field_id_item , les champs class_idx et type_idx doivent être des indices valides dans la liste type_ids . L'entrée référencée par class_idx doit être un type de référence autre qu'un tableau. En outre, le champ name_idx doit être une référence valide dans la section string_ids , et le contenu de l'entrée référencée doit être conforme à la spécification MemberName .
|
G19 |
Pour chaque method_id_item , le champ class_idx doit être un indice valide dans la section type_ids , et l'entrée référencée doit être un type de référence autre qu'un tableau. Le champ proto_id doit être une référence valide dans la liste proto_ids . Le champ name_idx doit être une référence valide dans la section string_ids , et le contenu de l'entrée référencée doit être conforme à la spécification MemberName .
|
G20 |
Pour chaque field_id_item , le champ class_idx doit être un indice valide dans la liste type_ids . L'entrée référencée doit être un type de référence autre qu'un tableau.
|
Contraintes de bytecode statiques
Les contraintes statiques sont des contraintes appliquées à des éléments individuels du bytecode. Elles peuvent généralement être vérifiées sans utiliser de techniques de contrôle ou d'analyse du flux de données.
Identifiant | Description |
---|---|
A1 |
Le tableau insns ne doit pas être vide.
|
A2 |
Le premier opcode du tableau insns doit avoir l'index 0.
|
A3 |
Le tableau insns ne doit contenir que des codes d'instruction Dalvik valides.
|
A4 |
L'index de l'instruction n+1 doit être égal à l'index de l'instruction n plus la longueur de l'instruction n , en tenant compte des opérandes possibles.
|
A5 |
La dernière instruction du tableau insns doit se terminer à l'index insns_size-1 .
|
A6 |
Toutes les cibles goto et if-<kind> doivent être des opcodes de la même méthode.
|
A7 |
Toutes les cibles d'une instruction packed-switch doivent être des opcodes de la même méthode. La taille et la liste des cibles doivent être cohérentes.
|
A8 |
Toutes les cibles d'une instruction sparse-switch doivent être des opcodes de la même méthode. Le tableau correspondant doit être cohérent et trié de la valeur la plus basse à la plus élevée.
|
A9 |
L'opérande B des instructions const-string et const-string/jumbo doit être un indice valide dans le pool de constantes de chaîne.
|
A10 |
L'opérande C des instructions iget<kind> et iput<kind> doit être un indice valide dans le pool de constantes de champ. L'entrée référencée doit représenter un champ d'instance.
|
A11 |
L'opérande C des instructions sget<kind> et sput<kind> doit être un indice valide dans le pool de constantes de champ. L'entrée référencée doit représenter un champ statique.
|
A12 |
L'opérande C des instructions invoke-virtual , invoke-super , invoke-direct et invoke-static doit être un indice valide dans le pool de constantes de méthode.
|
A13 |
L'opérande B des instructions invoke-virtual/range , invoke-super/range , invoke-direct/range et invoke-static/range doit être un indice valide dans le pool de constantes de méthode.
|
A14 |
Une méthode dont le nom commence par un "<" ne doit être appelée implicitement que par la VM, et non par du code provenant d'un fichier .dex . La seule exception est l'initialiseur d'instance, qui peut être appelé par invoke-direct .
|
A15 |
L'opérande C de l'instruction invoke-interface doit être un indice valide dans le pool de constantes de méthode. Le method_id référencé doit appartenir à une interface (et non à une classe).
|
A16 |
L'opérande B de l'instruction invoke-interface/range doit être un indice valide dans le pool de constantes de méthode.
Le method_id référencé doit appartenir à une interface (et non à une classe).
|
A17 |
L'opérande B des instructions const-class , check-cast , new-instance et filled-new-array/range doit être un indice valide dans le pool de constantes de type.
|
A18 |
L'opérande C des instructions instance-of , new-array et filled-new-array doit être un indice valide dans le pool de constantes de type.
|
A19 |
Les dimensions d'un tableau créé par une instruction new-array doivent être inférieures à 256 .
|
A20 |
L'instruction new ne doit pas faire référence à des classes de tableaux, à des interfaces ni à des classes abstraites.
|
A21 |
Le type référencé par une instruction new-array doit être un type valide sans référence.
|
A22 |
Tous les registres référencés par une instruction de largeur unique (non paire) doivent être valides pour la méthode en cours. Autrement dit, leurs indices doivent être non négatifs et inférieurs à registers_size .
|
A23 |
Tous les registres référencés par une instruction en double largeur (paire) doivent être valides pour la méthode actuelle. Autrement dit, leurs indices doivent être non négatifs et inférieurs à registers_size-1 .
|
A24 |
L'opérande method_id des instructions invoke-virtual et invoke-direct doit appartenir à une classe (et non à une interface). Dans les fichiers Dex antérieurs à la version 037 , il doit en être de même pour les instructions invoke-super et invoke-static .
|
A25 |
L'opérande method_id des instructions invoke-virtual/range et invoke-direct/range doit appartenir à une classe (et non à une interface). Dans les fichiers Dex antérieurs à la version 037 , il doit en être de même pour les instructions invoke-super/range et invoke-static/range .
|
Contraintes de bytecode structurelles
Les contraintes structurelles sont des contraintes sur les relations entre plusieurs éléments du bytecode. Elles ne peuvent généralement pas être vérifiées sans utiliser des techniques de contrôle ou d'analyse du flux de données.
Identifiant | Description |
---|---|
B1 | Le nombre et les types d'arguments (registres et valeurs immédiates) doivent toujours correspondre à l'instruction. |
B2 | Les paires de registres ne doivent jamais être séparées. |
B3 | Un registre (ou une paire) doit d'abord être attribué avant de pouvoir être lu. |
B4 |
Une instruction invoke-direct ne doit appeler un initialiseur d'instance ou une méthode que dans la classe actuelle ou l'une de ses super-classes.
|
B5 | Un initialiseur d'instance ne doit être appelé que sur une instance non initialisée. |
B6 | Les méthodes d'instance ne peuvent être appelées que sur des instances déjà initialisées et les champs d'instance ne peuvent être accessibles que sur des instances déjà initialisées. |
B7 |
Un registre contenant le résultat d'une instruction new-instance ne doit pas être utilisé si la même instruction new-instance est à nouveau exécutée avant l'initialisation de l'instance.
|
B8 |
Un initialiseur d'instance doit appeler un autre initialiseur d'instance (même classe ou super-classe) avant que les membres de l'instance puissent être accessibles.
Les exceptions sont des champs d'instance non hérités, qui peuvent être attribués avant d'appeler un autre initialiseur et la classe Object en général.
|
B9 | Tous les arguments de méthode réels doivent être compatibles avec leurs arguments formels respectifs. |
B10 | Pour chaque appel de méthode d'instance, l'instance réelle doit être compatible avec l'affectation de la classe ou de l'interface spécifiée dans l'instruction. |
B11 |
Une instruction return<kind> doit correspondre au type renvoyé de sa méthode.
|
B12 | Lorsque vous accédez aux membres protégés d'une super-classe, le type réel de l'instance à laquelle vous accédez doit être la classe actuelle ou l'une de ses sous-classes. |
B13 | Le type d'une valeur stockée dans un champ statique doit être compatible avec l'affectation ou convertible en type de champ. |
B14 | Le type d'une valeur stockée dans un champ doit être compatible avec le type du champ ou convertible en celui-ci. |
B15 | Le type de chaque valeur stockée dans un tableau doit être compatible avec l'affectation du type de composant du tableau. |
B16 |
L'opérande A d'une instruction throw doit être compatible avec l'affectation java.lang.Throwable .
|
B17 |
La dernière instruction accessible d'une méthode doit être une instruction goto ou une branche en arrière, une instruction return ou une instruction throw . Il ne doit pas être possible de laisser le tableau insns en bas.
|
B18 | La moitié non attribuée d'une ancienne paire de registres ne peut pas être lue (elle est considérée comme non valide) tant qu'elle n'a pas été réattribuée par une autre instruction. |
B19 |
Une instruction move-result<kind> doit être immédiatement précédée (dans le tableau insns ) par une instruction invoke-<kind> . La seule exception est l'instruction move-result-object , qui peut également être précédée d'une instruction filled-new-array .
|
B20 |
Une instruction move-result<kind> doit être immédiatement précédée (dans le flux de contrôle réel) par une instruction return-<kind> correspondante (elle ne doit pas être ignorée). La seule exception est l'instruction move-result-object , qui peut également être précédée d'une instruction filled-new-array .
|
B21 |
Une instruction move-exception ne doit apparaître que comme première instruction dans un gestionnaire d'exception.
|
B22 |
Les pseudo-instructions packed-switch-data , sparse-switch-data et fill-array-data ne doivent pas être accessibles par le flux de contrôle.
|