Gustavo Sied > Sin categoría > Recuperación de datos eliminados de SQLite Registros: Redux
Recuperación de datos eliminados de SQLite Registros: Redux
Gustavo
31 enero, 2014
http-equiv=»Content-Type» content=»application/xhtml+xml; charset=utf-8″ />
/ * <[CDATA [* / var asciidoc = {/ / Namespace!. / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / Indice generador / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / * Autor: Mihai Bazon , septiembre de 2002 * http://students.infoiasi.ro/ ~ mishoo ** Tabla de generador de contenido * Versión: 0.4 ** Siéntase libre de utilizar esta secuencia de comandos en los términos de la GNU General Public License *, siempre y cuando lo hace no suprimir o alterar este aviso. * / / * Modificado por Troy D. Hanson, septiembre de 2006. Licencia: GPL * / / * modificado por Stuart Rackham, 2006, 2009. Licencia: GPL * / / / toclevels = 1 .. 4. toc: function (toclevels) {function getText (el) {var text = ""; for (var i = el.firstChild; i = null; i = i.nextSibling!) {if (== i.nodeType 3 / * Node.TEXT_NODE * /) / / IE no habla constantes. texto + = I.Data; else if (i.firstChild = null!) Texto + = getText (i);} texto return;} function TocEntry (el, texto, toclevel) {this.element = el; this.Text = texto; this.toclevel = toclevel;} tocEntries función (EL, toclevels) {var result = new Array; var re = new RegExp ('[HH] ([1 -' + (toclevels 1) + '])') / / Función que escanea el árbol DOM para elementos de encabezado (la API DOM2 / / NodeIterator sería una mejor técnica, pero no con el apoyo de todos / / los navegadores). iterate var = function (el) {for (var i = el.firstChild;! i = null; i = i.nextSibling) {if (== i.nodeType 1 / * Node.ELEMENT_NODE * /) {var = mo re . exec (i.tagName); if (mo && (i.getAttribute ("clase") | | i.getAttribute ("className")) = "float"!) {resultado [result.length] = new TocEntry (i , getText (i), mo [1] -1);} iteración (i);}}} iterate (el); return resultado;} var toc = document.getElementById ("toc"); if (toc) {! vuelta;} / / Eliminar entradas de la TDC existentes en caso de que estamos volviendo a cargar el TOC. var tocEntriesToRemove = []; var i; for (i = 0; i
«; var id = palmos [i] getAttribute («id»);. if (id = nulos!) refs [«#» + id] = n;}} si (n == 0) noteholder.parentNode.removeChild (Bonista); else {/ / Proceso footnoterefs. for (i = 0; i
renace de las cenizas
He recibido muchas, muchas preguntas acerca de la recuperación de los registros borrados de bases de datos SQLite desde entonces he publicado un artículo acerca de mi primer intento de recuperar los datos eliminados. Bueno, la hipótesis de comprobar la diferencia entre la base de datos original y una copia aspirado parecía sonido en el tiempo y, en efecto, el rendimiento cayó datos de registro, sino que también incluyó datos de los registros asignados. Lo más importante que aprendí fue que tenía mucho que aprender sobre el formato de archivo de base de datos SQLite.
Desde entonces, me he encontrado cada vez más bases de datos SQLite, y la cuestión de la recuperación de los registros descartados ha convertido en algo fundamental. He aprendido cómo hacerlo, y voy a compartir algunos de los secretos con ustedes ahora. Pero en primer lugar, lo que necesita saber un poco acerca de las bases de datos SQLite …
Base de datos SQLite encabezado principal
Los primeros 100 bytes de una base de datos SQLite definir y describir la base de datos. El valor de la clave para la recuperación de disco es el tamaño de la página, un 16-bit (de dos bytes) entero big endian en el byte de desplazamiento 16. Bases de datos SQLite están divididos en páginas, por lo general coincide con el sistema de archivos de tamaño de bloque subyacente. Cada página tiene un solo uso, y las que contienen los registros que son del interés de los examinadores forenses es la página de la hoja de árbol b mesa, lo cual me referiré como la TLP . El TLP se distingue de otros tipos de páginas por su primer byte, x0d o entero 13.
Así, podemos encontrar los TLP con el conocimiento de la tamaño de página de base de datos se obtiene a partir de la cabecera de la base de datos y comprobar el primer byte de cada página para x0d. En python, debería parecerse a:
Python 3: Encontrar páginas mesa de b-árbol de hoja
<- Generador: GNU fuente-highlight 3.1.6 por Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite ->
de import unpack
open ( 'some.db' , 'rb' ) como f :.
= f leer ()
= unpack ( '> h' , [ 16 : 18 ]) [ 0 ]
= []
para en : bold "> rango ( 0 , len ( ), ):
si Datos ] == " color: # 993399 "> 13 ;.
append ( el desplazamiento )
Nota div> |
El código anterior imprime el desplazamiento de TLP. Asegúrese de que está utilizando Python 3 si quieres probar esto por ti mismo. |
Tabla B-hoja del árbol de páginas
Los TLPs mantener los registros, y en consecuencia, los registros (suprimido) redujo datos cuando se producen. Cada página tiene una cabecera de 8 bytes, desglosado de la siguiente manera:
Tabla 1. Encabezado de tabla página de hoja de árbol b
Offset |
Tamaño |
Valor |
0
|
1
|
Página x0d (int 13)
|
1
|
2
|
class=»table»>
|
class=»table»>
|
2
|
El número de células
|
5
|
2
|
class=»table»>
|
class=»table»>
|
1
|
class=»table»>
|
El encabezado introduce algunos términos que necesitan explicación. A freeblock espacio no asignado en la siguiente página una o más registros asignados. Es creado por la caída de un registro de la tabla. Cuenta con una cabecera de cuatro bytes: los dos primeros bytes son un entero big endian de 16 bits que apunta a la siguiente freeblock (cero significa su último freeblock), y los segundos dos bytes son un entero big endian de 16 bits que representa el tamaño de la freeblock, incluyendo la cabecera.
Las células son las estructuras que contienen los registros. El se componen de una longitud de carga útil, la clave y la carga útil. La longitud y la clave, también conocido como el rowid, son números enteros de longitud variable. ¿Qué son? Me alegra que lo preguntes:
enteros de longitud variable
Entero de longitud variable o «varint» es una codificación Huffman estática de enteros de 64 bits complemento a dos que utiliza menos espacio para los pequeños valores positivos. Un varint es entre 1 y 9 bytes de longitud. El varint consta de cero o más bytes que tiene el conjunto de bit de orden seguido de un solo byte con el bit de orden clara, o nueve bytes, lo que sea más corto. Los siete bits más bajos de cada uno de los primeros ocho bytes y todos los 8 bits de la novena bytes se utilizan para reconstruir el entero de 64 bits complemento a dos. Varints son big-endian: Bits extraídos del byte anterior del varint son los más significativos y los bits extraídos de los bytes posteriores
. http://www.sqlite.org/fileformat2.html
– SQLite.org
no voy a entrar en varints más lejos en este post, porque no voy a estar discutiendo la decodificación de células en este post. Baste decir que, con la longitud de carga útil, podemos definir la carga útil, que a su vez se compone de una cabecera y columnas. La cabecera es una lista de varints, el primero que describe la longitud de la cabecera, y el resto decribing los datos de columna y tipos. El encabezado de la página contiene el número de células y la compensación a la primera celda en la página.
El último valor en la cabecera, freebytes, describe el número de bytes fragmentados en la página. Bytes fragmentados son agrupaciones de bytes de tres o menos que no pueda ser reasignado a una nueva célula (que tiene un mínimo de cuatro bytes).
Inmediatamente después de la página cabecera es una matriz de punteros celular. Se compone de 16 bits enteros grandes endian de longitud igual a la cantidad de células en la página. Por lo tanto, si hay 10 células en la página, la matriz es de 20 bytes de longitud (10 agrupaciones de 2 btye).
Página espacio sin asignar
Hay tres tipos de espacio no asignado en un TLP. Freeblocks y freebytes hemos discutido, y el tercero es el espacio entre el final de la matriz celular y la primera celda en la página se hace referencia en la documentación de SQLite como simplemente «no asignado». Freeblocks y no asignado pueden contener datos de registro recuperables, mientras freebytes son demasiado pequeños para la interpretación. Por lo tanto, conociendo el primero freeblock (definido en el encabezado de página), la longitud de la matriz celular (interpretado por el número de celdas definidas en el encabezado de la página) y el desplazamiento de la primera celda (sí, lo has adivinado, se define en el . encabezado de página), se puede recuperar todo el espacio no asignado en la página de análisis
Python 3: Encontrar la Tabla B-árbol de hoja ! Página espacio no asignado
<- Generador: GNU fuente-highlight 3.1.6 por Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/ software / src-highlite ->
para el desplazamiento en :
style="color: página = [ : + ]
PageHeader = unpack ( > bhhhb ' , página [: 8 ])
pageByte , , , cellOffset , = PageHeader
# obtener sin asignar
= 8 + * 2
= - iniciar
= [ inicio : ]
print ( , unalloc , = ',' )
# get freeblocks, si alguno
si fbOffset > 0 :
mientras = 0 :
, Tamaño = unpack ( > hh ' , style="color: página [ : + 4 ])
= [ : fbOffset + ]
print ( , freeblock , = ',' )
= inicio
Con las líneas de los dos cuadros de código, hemos engatusado los datos asignados de la base de datos SQLite «some.db». Hemos impreso el desplazamiento de cada bloque no asignado y el contenido (en formato bytes python) a la salida estándar. Con sólo un poco de manipulación, podemos convertir esto en un script de un programa reutilizable, y el contenido puede ser grepped para cuerdas. Al mínimo, ahora tenemos una manera de determinar si se suprime el contenido de la base de datos relacionada con la investigación, por ejemplo, podríamos grep la salida del mmssms.db Android para un número de teléfono para ver si hay registros eliminados. Buscando contra toda la base de datos no sería útil porque no podemos separar la asigna a partir de los contenidos sin asignar!
Ahora, esto, obviamente, no reconstruye los registros para nosotros , pero la recuperación de los datos no asignado es un buen comienzo. En próximos posts voy a describir cómo reconstruir los registros asignados con un ojo hacia la reconstrucción de registros sin asignar.