Un archivo .dex
es el formato de transporte para el código de bytes de Dalvik. Existen ciertas restricciones sintácticas y semánticas para que un archivo sea un archivo .dex
válido, y se requiere un entorno de ejecución para admitir solo archivos .dex válidos.
Restricciones generales de integridad de .dex
Las restricciones de integridad generales se relacionan con la estructura más grande de un archivo .dex
, como se describe en detalle en el formato .dex
.
Identificador | Descripción |
---|---|
G1 |
El número magic del archivo .dex debe ser
dex\n035\0 para la versión 35 o similar para versiones posteriores.
|
G2 |
La suma de verificación debe ser una suma de verificación Adler-32 del contenido completo del archivo, excepto los campos magic y checksum .
|
G3 |
La firma debe ser un hash SHA-1 de todo el contenido del archivo, excepto magic , checksum y signature .
|
G4 |
El El |
G5 |
|
G6 |
endian_tag debe tener el valor ENDIAN_CONSTANT o REVERSE_ENDIAN_CONSTANT .
|
G7 |
Para cada una de las secciones
Los campos |
G8 |
Todos los campos de offset en el encabezado, excepto map_off , deben estar alineados en cuatro bytes.
|
G9 |
El campo map_off debe ser cero o apuntar a la sección de datos. En el último caso, debe existir la sección data .
|
G10 |
Ninguna de las secciones link , string_ids ,
type_ids , proto_ids , field_ids ,
method_ids , class_defs y data
debe superponerse entre sí ni con el encabezado.
|
G11 | Si existe un mapa, cada entrada del mapa debe tener un tipo válido. Cada tipo puede aparecer una vez como máximo. |
G12 |
Si existe un mapa, cada entrada del mapa debe tener un desplazamiento y un tamaño que no sean cero. El desplazamiento debe apuntar a la sección correspondiente del archivo (es decir, un string_id_item debe apuntar a la sección string_ids ) y el tamaño explícito o implícito del elemento debe coincidir con el contenido y el tamaño reales de la sección.
|
G13 |
Si existe un mapa, el desplazamiento de la entrada del mapa n+1 debe ser mayor o igual que el desplazamiento de la entrada del mapa n plus than size of map entry n . Esto implica entradas que no se superponen y un orden de bajo a alto.
|
G14 |
Los siguientes tipos de entradas deben tener un desplazamiento alineado con cuatro bytes: string_id_item , type_id_item , proto_id_item , field_id_item , method_id_item , class_def_item , type_list , code_item y annotations_directory_item .
|
G15 |
Para cada Para cada Para el |
G16 |
Para cada type_id_item , el campo descriptor_idx debe contener una referencia válida en la lista string_ids . La cadena a la que se hace referencia debe ser un descriptor de tipo
válido.
|
G17 |
Para cada proto_id_item , el campo shorty_idx debe contener una referencia válida en la lista string_ids . La cadena a la que se hace referencia debe ser un descriptor de atajo válido. Además, el campo return_type_idx debe ser un índice válido en la sección type_ids , y el campo parameters_off debe ser cero o un desplazamiento válido que apunte a la sección data . Si no es igual a cero, la lista de parámetros
no debe contener ninguna entrada nula.
|
G18 |
Para cada field_id_item , los campos class_idx y type_idx deben ser índices válidos en la lista type_ids . La entrada a la que hace referencia class_idx debe ser un tipo de referencia que no sea de array. Además, el campo name_idx debe ser una referencia válida en la sección string_ids , y el contenido de la entrada a la que se hace referencia debe cumplir con la especificación MemberName .
|
G19 |
Para cada method_id_item , el campo class_idx debe ser un índice válido en la sección type_ids , y la entrada a la que se hace referencia debe ser un tipo de referencia que no sea de array. El campo proto_id debe ser una referencia válida en la lista proto_ids . El campo name_idx debe ser una referencia válida en la sección string_ids , y el contenido de la entrada a la que se hace referencia debe cumplir con la especificación MemberName .
|
G20 |
Para cada field_id_item , el campo class_idx debe ser un índice válido en la lista type_ids . La entrada a la que se hace referencia debe ser un tipo de referencia que no sea de array.
|
Restricciones de código de bytes estáticas
Las restricciones estáticas son restricciones en elementos individuales del código de bytes. Por lo general, se pueden verificar sin emplear técnicas de control ni análisis de flujo de datos.
Identificador | Descripción |
---|---|
A1 |
El array insns no debe estar vacío.
|
A2 |
La primera operación de código en el array insns debe tener el índice cero.
|
A3 |
El array insns solo debe contener códigos de operación de Dalvik válidos.
|
A4 |
El índice de la instrucción n+1 debe ser igual al índice de la instrucción n más la longitud de la instrucción n , teniendo en cuenta los posibles operandos.
|
A5 |
La última instrucción del array insns debe terminar en el índice insns_size-1 .
|
A6 |
Todos los destinos de goto y if-<kind> deben ser opcodes dentro del mismo método.
|
A7 |
Todos los destinos de una instrucción packed-switch deben ser opcodes dentro del mismo método. El tamaño y la lista de objetivos deben ser coherentes.
|
A8 |
Todos los destinos de una instrucción sparse-switch deben ser opcodes dentro del mismo método. La tabla correspondiente debe ser coherente y estar ordenada de menor a mayor.
|
A9 |
El operando B de las instrucciones const-string y const-string/jumbo debe ser un índice válido en el grupo de constantes de cadenas.
|
A10 |
El operando C de las instrucciones iget<kind> y iput<kind> debe ser un índice válido en el grupo de constantes de campo. La entrada a la que se hace referencia debe representar un campo de instancia.
|
A11 |
El operando C de las instrucciones sget<kind> y sput<kind> debe ser un índice válido en el grupo de constantes de campo. La entrada a la que se hace referencia debe representar un campo
estático.
|
A12 |
El operando C de las instrucciones invoke-virtual , invoke-super , invoke-direct y invoke-static debe ser un índice válido en el grupo de constantes del método.
|
A13 |
El operando B de las instrucciones invoke-virtual/range , invoke-super/range , invoke-direct/range y invoke-static/range debe ser un índice válido en el grupo de constantes del método.
|
A14 |
La VM solo debe invocar de forma implícita un método cuyo nombre comienza con "<", no con código proveniente de un archivo .dex . La única excepción es el inicializador de instancias, que puede invocar invoke-direct .
|
A15 |
El operando C de la instrucción invoke-interface debe ser un índice válido en el grupo de constantes del método. El method_id al que se hace referencia debe pertenecer a una interfaz (no a una clase).
|
A16 |
El operando B de la instrucción invoke-interface/range debe ser un índice válido en el grupo de constantes del método.
El method_id al que se hace referencia debe pertenecer a una interfaz (no a una clase).
|
A17 |
El operando B de las instrucciones const-class , check-cast , new-instance y filled-new-array/range debe ser un índice válido en el grupo de constantes de tipo.
|
A18 |
El operando C de las instrucciones instance-of , new-array y filled-new-array debe ser un índice válido en el grupo de constantes de tipo.
|
A19 |
Las dimensiones de un array creado por una instrucción new-array deben ser menores que 256 .
|
A20 |
La instrucción new no debe hacer referencia a clases de array, interfaces ni clases abstractas.
|
A21 |
El tipo al que hace referencia una instrucción new-array debe ser un tipo válido que no sea de referencia.
|
A22 |
Todos los registros a los que hace referencia una instrucción de un solo ancho (no en pares) deben ser válidos para el método actual. Es decir, sus índices deben ser no negativos y menores que registers_size .
|
A23 |
Todos los registros a los que hace referencia una instrucción de doble ancho (par) deben ser válidos para el método actual. Es decir, sus índices deben ser no negativos y menores que registers_size-1 .
|
A24 |
El operando method_id de las instrucciones invoke-virtual y invoke-direct debe pertenecer a una clase (no a una interfaz). En los archivos Dex anteriores a la versión 037 ,
lo mismo debe ser cierto para las instrucciones invoke-super y
invoke-static .
|
A25 |
El operando method_id de las instrucciones invoke-virtual/range y invoke-direct/range debe pertenecer a una clase (no a una interfaz). En los archivos Dex anteriores a la versión 037 ,
lo mismo debe ser cierto para las instrucciones invoke-super/range y
invoke-static/range .
|
Restricciones de código de bytes estructurales
Las restricciones estructurales son restricciones en las relaciones entre varios elementos del código de bytes. Por lo general, no se pueden verificar sin emplear técnicas de control o análisis de flujo de datos.
Identificador | Descripción |
---|---|
B1 | La cantidad y los tipos de argumentos (registros y valores inmediatos) siempre deben coincidir con la instrucción. |
B2 | Los pares de registro nunca deben dividirse. |
B3 | Primero, se debe asignar un registro (o par) para poder leerlo. |
B4 |
Una instrucción invoke-direct debe invocar un inicializador de instancia o un método solo en la clase actual o en una de sus superclases.
|
B5 | Un inicializador de instancias solo se debe invocar en una instancia que no se inicializó. |
B6 | Los métodos de instancia solo se pueden invocar en campos de instancia y solo se puede acceder a instancias ya inicializadas. |
B7 |
No se debe usar un registro que contenga el resultado de una instrucción new-instance si se vuelve a ejecutar la misma instrucción new-instance antes de que se inicialice la instancia.
|
B8 |
Un inicializador de instancias debe llamar a otro inicializador de instancias (misma clase o superclase) antes de que se pueda acceder a los miembros de la instancia.
Las excepciones son campos de instancia no heredados, que se pueden asignar
antes de llamar a otro inicializador, y la clase Object
en general.
|
B9 | Todos los argumentos de método reales deben ser compatibles con la asignación con sus argumentos formales respectivos. |
B10 | Para cada invocación de método de instancia, la instancia real debe ser compatible con la asignación de la clase o interfaz especificada en la instrucción. |
B11 |
Una instrucción return<kind> debe coincidir con el tipo de datos que se muestra del método.
|
B12 | Cuando se accede a miembros protegidos de una superclase, el tipo real de la instancia a la que se accede debe ser la clase actual o una de sus subclases. |
B13 | El tipo de un valor almacenado en un campo estático debe ser compatible con la asignación o convertible al tipo del campo. |
B14 | El tipo de un valor almacenado en un campo debe ser compatible con la asignación o debe poder convertirse al tipo del campo. |
B15 | El tipo de cada valor almacenado en un array debe ser compatible con la asignación del tipo de componente del array. |
B16 |
El operando A de una instrucción throw debe ser compatible con la asignación de java.lang.Throwable .
|
B17 |
La última instrucción accesible de un método debe ser una goto o una rama hacia atrás, una return o una instrucción throw . No debe ser posible dejar el array insns en la parte inferior.
|
B18 | Es posible que no se pueda leer la mitad no asignada de un par de registros anterior (se considera no válida) hasta que otra instrucción la vuelva a asignar. |
B19 |
Una instrucción move-result<kind> debe anteceder inmediatamente (en el array insns ) a una instrucción invoke-<kind> . La única excepción es la instrucción move-result-object , que también puede estar precedida por una instrucción filled-new-array .
|
B20 |
Una instrucción move-result<kind> debe estar inmediatamente
precedida (en el flujo de control real) por una instrucción
return-<kind> coincidente (no se debe omitir). La única excepción es la instrucción move-result-object , que también puede estar precedida por una instrucción filled-new-array .
|
B21 |
Una instrucción move-exception debe aparecer solo como la primera instrucción en un controlador de excepciones.
|
B22 |
El flujo de control no debe poder alcanzar las pseudoinstrucciones packed-switch-data , sparse-switch-data ni fill-array-data .
|