14 agosto 2012

Forense de SQLite III - Páginas Libres

Comentaba en la entrada anterior que los ficheros SQLite se componen de varios tipos distintos de páginas. Uno de estos tipos son las listas de páginas libres (Freelist). Éstas pueden ser de dos tipos, freelist trunk y freelist leaf, que yo libremente voy a traducir a página troncal y hoja de página para tratar de explicarlo mejor.

Las páginas troncales son índices con punteros a hojas que algún día contuvieron información y están inactivas.

Una página troncal se compone de arrays de cuatro bytes con números enteros big-endian que van identificando las hojas disponibles. El primer elemento (color rojo en la Figura 1) de este array es especial, y su valor es un puntero a otra página troncal, ya que si no cupiesen todos los elementos en una única página, se usaría otra y se irían encadenando sucesivamente hasta que el primer elemento tenga valor  0, indicando que no existen más troncales. El segundo elemento (color azul en la Figura 1) de 4bytes, también es especial e indica el número restante de elementos de 4 bytes que compone la página troncal. Es decir, el número punteros a hojas libres (hojas verdes en la Figura 1) que contiene ese índice.

Figura 1. Esquema páginas libres: troncales y hojas

Con un ejemplo seguro que se ve mejor. Usando la misma base de datos que en la entrada anterior, y de la que se obtuvo de la cabecera que la primera página troncal era la 740. Abrimos el fichero en el offset de esa página, para calcularlo: ( primera página troncal  - 1 )*tamaño de página, o lo que es lo mismo:  (740-1)*4096=3026944

Figura 2. Ejemplo de página troncal libre
Donde:
  • 00 00 03 3A: indican que hay otra página troncal en la posición 826. 
  • 00 00 01 FO: indican que hay en total 496 celdas esta página con posiciones de páginas de hojas libres.
  • 00 00 05 FC...00 00 04 75: son arrays con números de páginas libres. En total se ha visto que hay 496 grupos. (la captura solo es un trozo).
Si abrimos el fichero en la posición de la página 00 00 05 FC (página 1532, offset: 6270976), desde esa posición hasta donde acaba la página (6270976+4096=6275072), se obtendrán datos eliminados, que pueden o no tener estructura, según veremos en siguientes entradas.



Del ejemplo, en toda la página se ve un trozo de correo electrónico. En otros casos habrá menos información o tan solo basura.

Dependiendo de cómo esté configurada la base de datos, es posible que no existan páginas libres, ya que si está activo "auto_vacuum", se liberan estas páginas reorganizando la base de datos, reduciendo su tamaño y dejando el espacio disponible al sistema de ficheros. En el que ya se usarían las técnicas clásicas de recuperación y carving en el propio sistema de ficheros.

Para saber si la base de datos usa o no auto_vacuum, se consulta la cabecera tal y como explicábamos en la segunda entrada de la serie.

También hay que considerar la posibilidad de que la página troncal libre (la de los punteros) no esté completa, por lo que existirán datos marcados como disponibles, desde el final del último puntero hasta que termine la página. En el ejemplo que se ha usado como página troncal, hay 496 celdas * 4 bytes por celda, hacen un total de 1984 bytes ocupados en celdas, más los 8 bytes con el puntero inicial a otras troncales y el contador de celdas, suma 1992. Por lo que la página troncal 720, tan solo hay ocupados 1992 bytes, lo que deja libre 2104 bytes (4096-1992) en los que podría haber información eliminada.

Las páginas libres (tanto troncales como hojas) no son el único sitio del que se puede recuperar datos. Existen otros lugares en los que buscar y que se comentarán en siguientes entradas.


Todos las entradas de la serie:

11 comments :

SLander dijo...

Está perfectamente explicado, se entiende de maravilla. Muy buen trabajo :)

silverhack dijo...

Impresionante Alex. Me está gustando mucho esta serie de artículos

Alejandro Ramos dijo...

Gracias tio, viendo las pocas lecturas, comentarios y tal, pensaba que no le interesaba ni a perri :))


Ya estoy con la siguiente parte y deseando publicar el script ;D

Madrikeka dijo...

Pues comeeento...... yo al leerme la primera parte y ver que iban a venir más, estoy esperando al final para hacerme "el" pdf, por que como en este tema estoy bastante pez, prefiero leerlo del tirón y ya sacar conclusiones decentes :D

Alex dijo...

Yo escribo en mi blog y desanima un poco cuando ves pocas visitas y comentarios de los usuarios... Pero aquí te dejo el mio como prueba de que me gusta bastante tu blog. Hasta he copiado una base de datos sacada de una aplicación android y me he puesto a comprobar la cabecera. Pero parece que es pequeña porque no tiene páginas troncales ni nada..


Sigue así y a ver si te animas a escribir cositas sobre Android como hicieras con IOS.


Un saludo

Alejandro Ramos dijo...

jajaja, gracias

Alejandro Ramos dijo...

Gracias alex!, que no tenga páquinas libres troncales, es normal. Hay aplicaciones que las borra (como whatsapp en iphone).


Un saludo! ... y ya nos dirás la url de tu blog!

Alex dijo...

Seguramente, era una base de datos un poco pequeña. Por supuesto!, aquí la dejo... aunque no hay punto de comparación con tu blog :\ -> http://www.elbauldelprogramador.com/page/2/

No soy Perri dijo...

Me digno a comentar por 1ª vez en esta excelente página para garantizarle a Alejandro que no sé si a perri le interesa, pero a este humilde geek cuasi-ingeniero técnico de informática, esta serie le interesa y más que mucho.

Aprovecho para daros la enhorabuena por el excelente contenido que publicáis y daros la gracia por vuestra labor de divulgación en general.

Estoy seguro que como yo habrá cientos, agradecidos enormemente a todos vosotros por compartir vuestros conocimientos de forma desinteresada con toda la comunidad.

¡¡¡¡¡ Un saludo y a seguir dándole caña cracks !!!!!!!

Alejandro Ramos dijo...

muchas gracias. La verdad es que yo mismo tras leerlo y leerlo varias veces me parece que quedó un poco "tostón" y lloriqueaba un poco. Seguiré con ello, creo que quedarán otro par de entradas más.


Un saludo no-perri y gracias otra vez!! :)))

Alejandro Ramos dijo...

Muy chulo. Sigue dándole caña!