En la entrada anterior, @nicky69es realizó una introducción a la recuperación de datos en SQLite. En esta entrada, hablará de como encontrar datos borrados y sobre los formatos de la cabecera de las BBDD.
DONDE ENCONTRAR DATOS BORRADOS
Freelist. Como mencioné en la introducción, la base de datos sqlite se guarda en el archivo en bloques llamados hojas de un tamaño fijo. Cuando los datos de una hoja se borran de la base de datos, esta pasa a marcarse como disponible y los datos que contiene se sobre-escribirán cuando se necesiten. La primera de las hojas se denomina “página tronco” que contiene las direcciones de otras páginas tronco (si las hubiera) y las direcciones de las hojas marcadas como disponibles a modo de lista.
Celdas en hojas. Cada hoja está compuesta por celdas de tamaño variable que se van insertando desde el final de la hoja hasta el principio. Cuando los datos de una celda son eliminados de la base de datos, esta se marca como disponible en la misma hoja, pero al borrarse una celda no pasa a ser una “freelist”, pasa a ser un bloque de datos disponible “freeblock”. Normalmente la base de datos desfragmenta la hoja, así que podemos encontrar trozos sin sentido. Podemos ver en la cabecera de la hoja las celdas activas y las que están disponibles y por tanto no han sido sobre-escritas aún.
Páginas overflow. Se generan cuando se queda corto el espacio en la celda. Ya sea porque se ha utilizado una celda borrada anteriormente con unos datos superiores al espacio que ocupaba o por la misma falta de espacio en la última celda de la página. Esto genera una hoja del tamaño
definido en la cabecera con el resto del contenido de la celda, o se reutiliza una de las hojas “disponibles”. Comienzan por el grupo de bytes (00 00 00 00).
Espacio no asignado en la hoja. Como las celdas se graban en las hojas desde el final hacia el inicio de la mismas, el espacio no asignado «unallocated” estará al principio de la hoja.
FORMATO DE LA CABECERA DE LA BBDD
Descripción de la cabecera y cuales son las opciones más interesantes para conseguir nuestro objetivo. Los datos están almacenados en Big-endian¹.
- Los primeros 16 bytes de la cabecera son la firma del archivo «SQLite format 3\000”.
- Los bytes del offset 16-17 indican el tamaño de las páginas en bytes.
- Los bytes de los offset 18(write) y 19(read) indican si está disponible la opción WAL (2=si, 1=no), whatsapp=1.
- Los 4 bytes de los offset 24-27 indican el número de veces que ha cambiado el archivo.
- Los 4 bytes de los offset 28-31 indican la cantidad de páginas que hay en el archivo. Si lo multiplicamos por el tamaño (offset 16-17) no dará el tamaño total del archivo.
- Los 4 bytes de los offset 32-35 indican el número de hoja de la primera “página tronco”. Si hubiera más, irían indicados en esta primera su número. [(número-1)*tamaño] nos da el offset.
Si es “cero” no hay páginas tronco. - Los 4 bytes de los offset 36-39 indican la cantidad de “freelist”.
- Los 4 bytes de los offset 56-59 indican la codificación de la BBDD (1=UTF8, 2=UTF16le,
3=UTFbe)
Esta información se puede ver en la consulta de terminal >sqlite3 archivo.sqlite «.dbinfo»
Autor: @nicky69es
Fuentes: sqlite.org; arumeinformatica.es
¹Big-Endian: A la hora de expresar estos datos tenemos que definir el concepto de byte más representativo (MSB) y byte menos representativo (LSB), que se denomina así al byte que modificado altera el dato en mayor medida y al que lo hace en menor medida. Por ejemplo, expresando el número 13 como binario de 8 bits sería 0000 1011
, el MSB sería 0000 y el LSB sería 1011 puesto que, por ejemplo, 0001 1011
= 27 dista más que 0000 1111
= 15. El formato Big Endian es aquel que ordena los bytes del más significativo al menos significativo.
Los datos 13 y «trece» expresados en hexadecimal son 0x3133
y 0x74726563650d0a
, pues bien escritos como datos de 2 bytes en formato Big Endian quedarían 0x31 0x33
y 0x74 0x72 0x65 0x63 0x65 0x0d 0x0a




