Dalvik VM: Ficheros .dex
En esta entrada vamos a hablar de la estructura interna de los ficheros .dex. Lo primero, decir que, los ficheros .dex se encuentran empaquetados dentro los archivos .apk (Android Package). A continuación podemos ver una imagen con la estructura interna de estos ficheros:
Como podemos apreciar, un fichero .dex esta divido en distintas secciones llamadas “pools”. El pool de strings contiene todos los Strings que las clases dentro del .dex usan. En pool de tipos (type_ids) se guardan los distintos tipos datos usados en la aplicación, etc. Además de las secciones mostradas en la imagen, en la estructura actual de los ficheros dex existe una sección más por debajo de la de datos (data) llamada link_data o enlace de datos. En este momento dicha sección no está documentada. Todo lo que dice la documentación oficial es que en ella se guarda información sobre los ficheros enlazados estáticamente. Si el fichero no es enlazado esta sección permanece vacía y dicha documentación concluye diciendo que dicha sección se use como mejor se adecue a nuestra implementación.Veamos la estructura de cada sección.
Antes de nada vamos a ver los distintos tipos de datos y su longitud.
Name | Description |
---|---|
byte | 8-bit signed int |
ubyte | 8-bit unsigned int |
short | 16-bit signed int, little-endian |
ushort | 16-bit unsigned int, little-endian |
int | 32-bit signed int, little-endian |
uint | 32-bit unsigned int, little-endian |
long | 64-bit signed int, little-endian |
ulong | 64-bit unsigned int, little-endian |
sleb128 | signed LEB128, variable-length (see below) |
uleb128 | unsigned LEB128, variable-length (see below) |
uleb128p1 | unsigned LEB128 plus 1 , variable-length (see below) |
Name | Format | Description |
---|---|---|
magic | ubyte[8] | magic value. Este valor es el que identifica el tipo de fichero. En este caso: { 0x64 0x65 0x78 0x0a 0x30 0x33 0x35 0x00 }= "dex\n035\0" |
checksum | uint | adler32 checksum. Típico valor para identificar cualquier tipo de corrupción. Este valor se calcula en base a todo el fichero, menos magic y checksum. |
signature | ubyte[20] | Hash SHA-1 de todo el fichero menos magic, checksum y signature. Se usa para la identificación de ficheros. |
file_size | uint | Tamaño de todo el fichero incluida la cabecera en bytes. |
header_size | uint = 0x70 | Tamaño de la cabecera en bytes. Se usa para guardar la compatibilidad. |
endian_tag | uint = ENDIAN_CONSTANT | Etiqueta endian. Nos indica que tipo de formato endian usa el fichero. Puede tener los siguientes valores:
uint ENDIAN_CONSTANT = 0x12345678; uint REVERSE_ENDIAN__CONSTANT. |
link_size | uint | Indica el tamaño de la sección de enlace (link section) o 0, si el fichero es enlazado de forma dinámica. |
link_off | uint | Desplazamiento al comienzo de la sección de enlace desde el inicio del fichero o 0 si link_size == 0. |
map_off | uint | Desplazamiento al map_list en caso que éste exista o 0 en caso contrario. El map_list es una lista con todo el contenido del fichero. Esta estructura de datos puede contener datos redundantes, pero la intención de la misma es el poder recorrer el contenido del fichero de una forma más cómoda. Esta lista está ordenada. |
string_ids_size | uint | Número de elementos en la lista de strings. |
string_ids_off | uint | Desplazamiento a la lista de strings o 0 en caso que dicha lista este vacía, circunstancia que raramente se va a dar. |
type_ids_size | uint | Número de elementos en la lista de tipos (type). |
type_ids_off | uint | Desplazamiento a la lista de tipos o 0 en caso que dicha lista este vacía. Caso que raramente también se dará. |
proto_ids_size | uint | Número de elementos en la lista de prototipos. |
proto_ids_off | uint | Desplazamiento a la lista de prototipos. 0 en caso que dicha lista este vacía. De nuevo, situación que raramente se dará. |
field_ids_size | uint | Número de elementos en la lista de campos. |
field_ids_off | uint | Desplazamiento a la lista de campos o 0 en caso que dicha lista esté vacía. |
method_ids_size | uint | Número de elementos en la lista de métodos. |
method_ids_off | uint | Desplazamiento a la lista de métodos. 0 si la lista está vacía. |
class_defs_size | uint | Número de elementos en la lista de clases. |
class_defs_off | uint | Desplazamiento a la lista de clases. 0 en caso dicha lista este vacía, situación poco probable. |
data_size | uint | Tamaño en bytes de la sección de datos. Debe ser un número par múltiplo del tamaño de un uint (sizeof(uint)). |
data_off | uint | Desplazamiento a la sección de datos. |
Name | Format | Description |
---|---|---|
string_data_off | uint | Desplazamiento desde el inicio del fichero hasta la cadena de texto en sí. La estructura de datos a la que este puntero apunta debe de estar en la sección de datos. |
Name | Format | Description |
---|---|---|
utf16_size | uleb128 | Tamaño del string en formato UTF-16 (2 bytes por caracter). |
data | ubyte[] | Array de bytes en formato MUTF-8. Aunque también acepta la codificación UTF-16. |
Name | Format | Description |
---|---|---|
descriptor_idx | uint | Indica el tipo (clase, arrays o tipos primitivos) de cada String especificada en el sección de Strings. Debe estar en el mismo orden que la sección de strings. |
TypeDescriptor → | |
'V' |
|
| | FieldTypeDescriptor |
FieldTypeDescriptor → | |
NonArrayFieldTypeDescriptor | |
| | ('[' * 1…255) NonArrayFieldTypeDescriptor |
NonArrayFieldTypeDescriptor→ | |
'Z' |
|
| | 'B' |
| | 'S' |
| | 'C' |
| | 'I' |
| | 'J' |
| | 'F' |
| | 'D' |
| | 'L' FullClassName ';' |
Syntax | Meaning |
---|---|
V | void ; sólo válido para valores de retorno |
Z | boolean |
B | byte |
S | short |
C | char |
I | int |
J | long |
F | float |
D | double |
Lfully/qualified/Name; | Nombre completo de la clase, incluido los paquetes. |
[descriptor | array of descriptor , usable recursively for arrays-of-arrays, though it is invalid to have more than 255 dimensions. |
Name | Format | Description |
---|---|---|
shorty_idx | uint | Índice dentro de la sección de Strings que contiene la cadena de texto con el nombre del método |
return_type_idx | uint | Índice dentro de la cadena de tipos correspondiente al tipo de dato devuelto por este método. |
parameters_off | uint | Desplazamiento a la lista de tipos de parámetros o 0 en case de que el método no espere ningún parámetro. Dicha sección se encuentra en la sección de datos. |
Name | Format | Description |
---|---|---|
class_idx | ushort | Índice correspondiente a la clase a la que pertenece dicho campo. Este elemento se encuentra en la lista de tipos. Debe referenciar un tipo clase. |
type_idx | ushort | Índice en la lista de tipos que se corresponde con el tipo de este campo |
name_idx | uint | Índice dentro de la lista de Strings que contiene el nombre de dicho campo. |
Name | Format | Description |
---|---|---|
class_idx | ushort | Índice dentro de la lista de tipos que define este método. Éste debe ser del tipo clase o array, pero un tipo primitivo. |
proto_idx | ushort | Índice que define el prototipo de este método en la sección de prototipos. |
name_idx | uint | Índice en la sección de strings que contiene el nombre de este método. |
Name | Format | Description |
---|---|---|
class_idx | uint | Índice en la lista de tipos. Debe ser del tipo clase y no array o primitivo. |
access_flags | uint | Tipo de acceso (public, final, etc) |
superclass_idx | uint | Índice en la sección de tipos del tipo de la superclase o clase que hereda. NO_INDEX en caso de que no tenga superclase. Por ejemplo Object |
interfaces_off | uint | Desplazamiento desde el inicio del fichero hasta la o las interfaces que esta clase implementa o 0 caso que no implemente ninguna. Dicha lista de interfaces deber aparecer en la sección de datos. |
source_file_idx | uint | Índice en la lista de Strings con el nombre del fichero que contiene la fuente original o la constante NO_INDEX en caso de que se carezca de dicha información. |
annotations_off | uint | Desplazamiento a la estructura de anotaciones de esta clase o 0 en caso de que esta clase no contenga anotaciones. La estructura de anotaciones aparece en la sección de datos. |
class_data_off | uint | Desplazamiento a los datos asociados con esta clase. Esos datos deben estar definidos en la sección de datos. |
static_values_off | uint | Desplazamiento a la sección de datos donde se guardan los valores iniciales de los campos estáticos o 0 si la clase no tiene valores estáticos. |
Sólo he intentado repasar las estructuras, que desde mi punto de vista son más atractivas. También podemos apreciar el papel que juega la sección de Strings y quizás ahora se vea un poco más claro el proceso de optimización de los ficheros .dex.
Para tener una idea un poco más clara de la diferencia entre ficheros .jar y ficheros vamos a ver unas imágenes de ejemplo donde se puede ver la diferencia entre ambos.
En esta primera imagen podemos ver como se relacionan, o como se van a distribuir los datos con generemos el fichero .dex.
A continuación veremos una imagen de como estarían distribuidas las clases y sus datos dentro de un .jar. Aquí vemos como cada clase contiene su propia información. No se comparte nada. Ahora veremos como se distribuyen los datos dentro de un fichero .dex. Como podemos ver no existen elementos repetidos y todo está enlazado y compartido. Como ya hemos dicho esta una de las formas en que Dalvik reduce el tamaño de los ficheros y además acelera el acceso a los datos.La estructura de los ficheros .jar es mucho más clara y ordenada, pero recordemos que cuando hablamos de Dalvik hablamos de dispositivos móviles y ligeros, dónde el ahorro de espacio y proceso es crítico.
Enlaces anteriores de esta serie: Dalvik VM: Introducción Dalvik VM: Optimización
Fuente: http://www.netmite.com/android/mydroid/dalvik/docs/dex-format.html
Buscar
Entradas Recientes
- Posts
- Reemplazando la bateria del AirTag
- OpenExpo Europe décima edición, 18 de mayo: El Epicentro de la Innovación y la Transformación Digital
- Docker Init
- Kubernetes para profesionales
- Agenda: OpenExpo Europe 2022 llega el 30 de junio en formato presencial
- Libro 'Manual de la Resilencia', de Alejandro Corletti, toda una referencia para la gestión de la seguridad en nuestros sistemas
- Mujeres hackers en ElevenPaths Radio
- Creando certificados X.509 caducados
- Generador de imágenes Docker para infosec