Serie de artículos escritos por @nicky69es sobre la recuperación de datos en SQLite. Esta entrada se centra en describir el contenido de cada «Página».
PAGINAS
La primera página se encuentra en el offset 100. Cada (+tamaño) empieza una hoja y pueden ser de cuatro tipos:
- 0D Tabla hoja, puede contener overflow.
- 05 Tabla interior, sin overflow.
- 0A Indice hoja, puede contener overflow.
- 02 Indice interior, puede contener overflow.
La páginas x0D son las que contienen datos de la tabla y por eso nos centraremos en ellas. El resto son las tablas internas y los índices.
Cabecera de las hojas:
- 1 byte offset relativo 0 de la página, indica el tipo de página. (Si no es ninguno de los tipos anteriormente marcados, entonces se trata de una página overflow)
- 2 bytes offset relativo 1-2 de la página, indica la posición del primer espacio libre (freeblock) dentro de la página.
- 2 bytes offset relativo 3-4 de la página, indica el número de celdas de la página.
- 2 bytes offset relativo 5-6 de la página, indica la posición del comienzo de las celdas.
- 1 byte offset relativo 7 de la página, indica el número de bytes fragmentados libres. (Grupos recuperados consecutivos con tamaño menor de 4 bytes.)
Los bloques de 2 bytes siguientes a la cabecera de página indican las direcciones offset relativas a la página de cada celda, empezando por el mismo valor que el offset relativo de la página (5-6). Habrá tantos bloques como celdas activas y “borradas”, los bloques siguientes al número de celdas indicadas en el offset relativo a la página (3-4), será celdas “borradas”, disponibles.
Cabecera de las páginas tronco “freelist”:
4 bytes offset relativo 0-3 de la página, indica la dirección de la siguiente página tronco.
4 bytes offset relativo 4-7 de la página, indica la cantidad de hojas libres en la lista que contiene.
Los siguientes grupos de 4 bytes, con un total de grupos igual a los indicados en offset 4-7, contienen las direcciones offset de las hojas libres. Puede haber más grupos de 4 bytes de los indicados en el puntero, que indicaban a hojas disponibles antes de su utilización y reestructuración. Se pueden distinguir por su bajo valor decimal.
Cabecera de los freeblocks (offset 1-2 de la página):
2 bytes offset relativo 0-1 del freeblock, indica el offset al siguiente freeblock o “cero” si es el último freeblock.
2 bytes offset relativo 2-3 del freeblock, indica el tamaño del freeblock incluídos estos 4 bytes.
Cabecera de las celdas:
Contiene el tipo de datos y el tamaño. Cada tipo de página tiene una cabecera diferente en sus celdas. Si el contenido de la celda no cabe en la página, los últimos 4 bytes de la celda indican la página overflow donde continúan los datos que exceden.
En las hojas x0D:
- Los primeros bytes son un varint con el total de tamaño (Después del ROWID).
- Los siguientes bytes son un varint con el ROWID (índice de celda en la página).
- 1 byte con la cantidad de bytes que indican los bloques de datos (incluido este indicador).
- Varint varios con el tamaño de cada bloque de datos.
- Bloques de datos.
- 4 bytes con el offset del overflow.
Cálculo del Varint: Se coge el primer byte y se pasa a binario, si el bit de la izquierda (más significativo) es ‘0’, entonces el valor es el que tiene el byte, si el bit de la izquierda es ‘1’ se anotan los 7 bits más a la derecha; se coge el byte siguiente anotando los 7 bits de la izquierda a continuación de los ya anotados. Añadimos los datos del siguiente byte si el bit de la izquierda es ‘1’ y terminamos si es ‘0’.
Ejemplo: 4 bytes x86 x26 x40 x02 -> 10000110 00100110 01000000 00000010 -> 00001100100110 01000000 00000010 -> 806Bytes 64Bytes 2Bytes (de tamaño)
OVERFLOW PAGE
Sus 4 primeros bytes marcarán la siguiente página overflow si existiera, si no existe estarán a “00 00 00 00”.
El resto son los datos que vienen de la celda que la genera hasta completar el tamaño de la celda.
Desde este final de la celda que genera la página overflow hasta el final de la página, puede haber contenido de datos anteriores del que habría que estudiar su formato.
EN RESUMEN
Los archivos sqlite son archivos de bases de datos. Tienen páginas de indices y páginas de tablas. Cada página del archivo contendrá por lo general uno de esos datos.
Cada celda es de suponer que contendrá los nombres de las tablas, los nombres de los campos, los contenidos de los campos. Por ello su tamaño es variable.
En esta base de datos, podemos descubrir los servicios a los que el usuario se ha registrado con la cuenta de iCloud y las cuentas que se han utilizado. En una base de datos como la del whatsapp que se borran y se modifican los datos continuamente, es fácil encontrar restos de datos en bloques de celdas que han quedado en un tamaño inferior. En cuanto a encontrar muchas páginas freelist se hace difícil salvo que la base de datos haya eliminado recientemente una cantidad grande de conversaciones y no hayan sido sustituidas ni reorganizada (desfragmentada) la BBDD, existe también la posibilidad de que una de esas páginas pasadas a libres haya sido reutilizada como página overflow, que en este tipo de bbdd tendría mucho espacio sobrante.
Sabremos lo que hay cuando entremos a mirar.
Es importante conocer cómo se forman y se mueven los datos, para poder determinar ante un tribunal la validez de los programas de extracción y recuperación de datos homologados. Si el día de mañana, los programadores cambian la forma de grabación de datos a byte invertido (poner nibbles de cada byte en orden derecha a izquierda, invertido), estos programas no sacarán la información hasta su actualización aunque la estructura sea la misma.
Autor: @nicky69es
Fuentes: sqlite.org