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 tiempo de ejecución para admitir solo archivos .dex válidos.
Restricciones generales de integridad de .dex
Las restricciones de integridad generales tienen que ver con la estructura más grande de un archivo .dex
, como se describe en detalle en formato .dex
.
Identificador | Descripción |
---|---|
G1 | El número magic del archivo .dex debe ser dex\n035\0 o dex\n037\0 . |
G2 | La suma de verificación debe ser una suma de verificación Adler-32 de todo el contenido del archivo excepto el campo magic y checksum . |
G3 | La firma debe ser un hash SHA-1 de todo el contenido del archivo, excepto magic , checksum y signature . |
G4 | file_size debe coincidir con el tamaño real del archivo en bytes. |
G5 | El header_size debe tener el valor: 0x70 |
G6 | El endian_tag debe tener el valor: ENDIAN_CONSTANT o REVERSE_ENDIAN_CONSTANT |
G7 | Para cada una de las link , string_ids , type_ids , proto_ids , field_ids , method_ids , class_defs y data , los campos offset y size deben ser cero o distintos de cero. En el último caso, el desplazamiento debe estar alineado con cuatro bytes. |
G8 | Todos los campos de desplazamiento en el encabezado, excepto map_off deben estar alineados con cuatro bytes. |
G9 | El campo map_off debe ser cero o apuntar a la sección de datos. En este último caso, la sección data debe existir. |
G10 | Ninguna de las link , string_ids , type_ids , proto_ids , field_ids , method_ids , class_defs y data deben superponerse entre sí o con el encabezado. |
G11 | Si existe un mapa, cada entrada del mapa debe tener un tipo válido. Cada tipo puede aparecer como máximo una vez. |
G12 | Si existe un mapa, cada entrada del mapa debe tener un desplazamiento y un tamaño distintos de 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, entonces el desplazamiento de la entrada del mapa n+1 debe ser mayor o igual al 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 menor a mayor. |
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 , annotations_directory_item . |
G15 | Para cada string_id_item , el campo string_data_off debe contener una referencia válida a la sección data . Para el string_data_item al que se hace referencia, el campo data debe contener una cadena MUTF-8 válida y utf16_size debe coincidir con la longitud decodificada de la cadena. |
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 breve 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 es distinto de 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 una matriz. Además, el campo name_idx debe ser una referencia válida a 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 una matriz. 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 a 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 una matriz. |
Restricciones de código de bytes estático
Las restricciones estáticas son restricciones sobre elementos individuales del código de bytes. Por lo general, se pueden verificar sin emplear técnicas de control o análisis de flujo de datos.
Identificador | Descripción |
---|---|
A1 | La matriz insns no debe estar vacía. |
A2 | El primer código de operación en la matriz insns debe tener índice cero. |
A3 | La matriz insns debe contener sólo códigos de operación 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 de la matriz insns debe terminar en el índice insns_size-1 . |
A6 | Todos los objetivos goto e if-<kind> deben ser códigos de operación dentro del mismo método. |
A7 | Todos los objetivos de una instrucción packed-switch deben ser códigos de operación dentro del mismo método. El tamaño y la lista de objetivos deben ser coherentes. |
A8 | Todos los objetivos de una instrucción sparse-switch deben ser códigos de operación 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 cadena. |
A10 | El operando C de las instrucciones iget<kind> e 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 e 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 e invoke-static/range debe ser un índice válido en el grupo de constantes del método. |
A14 | Un método cuyo nombre comienza con '<' solo debe ser invocado implícitamente por la VM, no por el código que se origina en un archivo .dex . La única excepción es el inicializador de instancia, que puede ser invocado mediante invoke-direct . |
A15 | El operando C de la instrucción invoke-interface debe ser un índice válido en el grupo constante 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 constante 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 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 una matriz creada mediante una instrucción new-array deben ser inferiores a 256 . |
A20 | La new instrucción no debe hacer referencia a clases de matriz, interfaces o clases abstractas. |
A21 | El tipo al que hace referencia una instrucción new-array debe ser un tipo válido y sin referencia. |
A22 | Todos los registros a los que hace referencia una instrucción de ancho único (sin par) deben ser válidos para el método actual. Es decir, sus índices deben ser no negativos y más pequeños que registers_size . |
A23 | Todos los registros a los que hace referencia una instrucción en forma de doble ancho (par) deben ser válidos para el método actual. Es decir, sus índices deben ser no negativos y más pequeños que registers_size-1 . |
A24 | El operando method_id de las instrucciones invoke-virtual e invoke-direct debe pertenecer a una clase (no a una interfaz). En los archivos Dex anteriores a la versión 037 lo mismo debe ocurrir con las instrucciones invoke-super e invoke-static . |
A25 | El operando method_id de las instrucciones invoke-virtual/range e 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 ocurrir con las instrucciones invoke-super/range e invoke-static/range . |
Restricciones estructurales de código de bytes
Las restricciones estructurales son restricciones a 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 | El número y tipos de argumentos (registros y valores inmediatos) siempre deben coincidir con la instrucción. |
B2 | Los pares de registros nunca deben dividirse. |
B3 | Primero se debe asignar un registro (o par) antes de poder leerlo. |
B4 | Una instrucción invoke-direct debe invocar un inicializador de instancia o un método sólo en la clase actual o en una de sus superclases. |
B5 | Un inicializador de instancia debe invocarse solo en una instancia no inicializada. |
B6 | Los métodos de instancia solo se pueden invocar y solo se puede acceder a los campos de instancia en instancias ya inicializadas. |
B7 | No se debe utilizar un registro que contenga el resultado de una instrucción new-instance si la misma instrucción new-instance se ejecuta nuevamente antes de que se inicialice la instancia. |
B8 | Un inicializador de instancia debe llamar a otro inicializador de instancia (misma clase o superclase) antes de que se pueda acceder a cualquier miembro de la instancia. Las excepciones son los 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 del método real deben ser compatibles con la asignación de sus respectivos argumentos formales. |
B10 | Para cada invocación de método de instancia, la instancia real debe ser compatible con la asignación con la clase o interfaz especificada en la instrucción. |
B11 | Una instrucción return<kind> debe coincidir con el tipo de retorno de su método. |
B12 | Al acceder a miembros protegidos de una superclase, el tipo real de instancia a la que se accede debe ser la clase actual o una de sus subclases. |
B13 | El tipo de valor almacenado en un campo estático debe ser compatible con la asignación o convertible al tipo de campo. |
B14 | El tipo de valor almacenado en un campo debe ser compatible con la asignación o convertible al tipo de campo. |
B15 | El tipo de cada valor almacenado en una matriz debe ser compatible con la asignación con el tipo de componente de la matriz. |
B16 | El operando A de una instrucción throw debe ser compatible con la asignación con java.lang.Throwable . |
B17 | La última instrucción accesible de un método debe ser una instrucción goto atrás o una rama, una return o una instrucción throw . No debe ser posible dejar la matriz insns en la parte inferior. |
B18 | La mitad no asignada de un par de registros anterior no se puede leer (se considera inválida) hasta que haya sido reasignada mediante alguna otra instrucción. |
B19 | Una instrucción move-result<kind> debe ir precedida inmediatamente (en la matriz insns ) por una instrucción invoke-<kind> . La única excepción es la instrucción move-result-object , que también puede ir precedida por una instrucción filled-new-array . |
B20 | Una instrucción move-result<kind> debe ir inmediatamente precedida (en el flujo de control real) por una instrucción return-<kind> coincidente (no se debe saltar a ella). La única excepción es la instrucción move-result-object , que también puede ir precedida por una instrucción filled-new-array . |
B21 | Una instrucción move-exception debe aparecer sólo como la primera instrucción en un controlador de excepciones. |
B22 | Las pseudoinstrucciones packed-switch-data , sparse-switch-data y fill-array-data no deben ser accesibles mediante el flujo de control. |