Digital Forensics of Android WhatsApp SQLite Database (Part II)

En esta segunda parte, se procederá a recuperar **un mensaje que ha sido

eliminado** en la base de datos SQLite de la aplicación WhatsApp y se

analizará la información obtenida para determinar cuando se envío el

mensaje (timestamp) recuperado.

Estructura de SQLite (II)

Una vez que conocemos el esquema de la base de datos, y como se organiza

la información útil (payload data) dentro de las celdas de cada una de

las páginas, es conveniente conocer el formato completo del fichero

SQLite ([file

format](http://www.sqlite.org/fileformat.html#varint_format)) para

navegar en el fichero de forma adecuada.

Lo primero que se necesita es conocer el tamaño de las páginas y el

número total de páginas que contiene la base de datos, esta información

se encuentra dentro de la cabecera de la base de datos (database

header).

Analizando la base de datos del ejemplo (msgstore.db) y utilizando mi

propia herramienta DFSLite (Digital Forensics SQlite Tools)

desarrollada para la ocasión, se obtiene que:

ST2Labs 4 - SQLite Database Header Info

Como se observa en la imagen anterior, se tiene que:

  • Page_size = 4096

  • Num_page = 27

La base de datos en el momento del análisis tiene un máximo de 27

páginas, como cada página tiene un tamaño especifico, se puede calcular

el Offset de acceso al fichero para cada una de las páginas utilizando

la siguiente formula:

Offset (pagina N) = (N -1) * Page_size 

Se debe de tener en cuenta que las páginas se numeran desde 1 hasta N, y

que el Offset para la primera página es 0.

Cada página dentro de la base de datos (excepto la primera página)

guardan el siguiente formato:

ST2Labs 5 - SQLite Page Format

Las celdas (registros) de la base de datos se rellenan desde el final de

la página hacia el inicio, con objeto de permitir que el Cell Pointer

Array aumente según se agregan registros a la página. 

Analizando el contenido del “Cell Pointer Array” se obtienen el número

de celdas que contiene la página y el offset relativo a la página donde

comienzan. Con DFSLite se puede obtener un listado con todos los

Cell Pointer Array e información sobre los registros que existen en cada

una de las páginas de la base de datos de la siguiente forma:

ST2Labs 6 - SQLite Page Cell Pointer Array Info
ST2labs 7 - SQLite All Cell for Page List

Esta información es útil para identificar rápidamente que páginas tienen

registros (celdas) de información y cuales no. Además de obtener el

Offset absoluto y el número total de registros que hay dentro de la base

de datos en cada página.

Toda esta información es interesante desde el punto de vista Forense,

para centrar el análisis en aquellas páginas que no tengan registros

(mayor espacio sin utilizar), en busca de posible información eliminada

y que se encuentre almacenada.

Esto es posible, dado que como si de un sistema de ficheros se tratase

cuando se elimina información de la base de datos, esta no se “borra”

físicamente (no se sobrescribe de forma inmediata) simplemente se

elimina el indice de localización de la información en la base de datos,

y se queda residente en el fichero hasta que ésta sea sobrescrita

posteriormente con otra información.

Por ello, el periodo de **tiempo desde que un registro fue eliminado

hasta que se analiza de forma forense es crucial para recuperar la mayor

cantidad de información**, influyendo directamente el nivel de

intensidad de uso de la aplicación en ese tiempo con la capacidad de

recuperación de información útil.

Hasta aquí la introducción resumida del formato SQLite, se puede

profundizar más en el formato consultando la documentación oficial en el

siguiente

enlace

A continuación vamos directos a analizar la estructura de la tabla

“Messages” de la aplicación WhatsApp dentro de la base de datos SQLite.

**Estructura base datos

Whatsapp**

Tal y como se comprobó en el [primer

articul](http://www.seguridadparatodos.es/2015/11/digital-forensics-of-android-whatsapp.html)o,

con ayuda de la herramienta

sqlite_ex, se

averigua que la tabla “messages” de WhatsApp se encuentra almacenada en

la página 3 de la base de datos SQLite (msgstore.db).

Con ayuda de un editor hexadecimal, abrimos la base de datos y nos

dirigimos al Offset = 8192 correspondiente a la página 3 (véase la

formula comentada anteriormente para el cálculo). Para localizar

rápidamente los registros dentro de la página, me apoyo en la DFSLite

con la opción -p 3, para analizar la estructura del CellPointerArray de

la página, tal que así:

ST2Labs 9 - Cell Pointer Array Info Page 3

El CellPointer Array se encuentra en el Offset: 8200, se realiza un

Decode de “Data” y se obtiene el total de Offset relativos a la página

donde se encuentran los registros válidos (existentes) dentro de la base

de datos:

Decode Cell Pointer Array Data:

  -  Offsets:               [4048, 3390, 3269, 3166]

Con el Offset relativo a la página 3, se puede calcular el Offset de

cada una de los registros válidos de la base de datos (msgstore.db).

por ejemplo: Cell Offset 3166 se corresponde con el Offset absoluto:

11358, se abre la base de datos con un editor hexadecimal y se obtiene:

ST2Labs 10 - Hexa Cell Data Offset 11358

La estructura de un registro (celda) de información de tipo Table, de

una base de datos SQLite tiene la siguiente estructura:

ST2Labs 8 - Sqlite Cell File Format

Para calcular el tamaño de la celda, y el tamaño del payload la base de

datos SQLite utiliza el tipo VarInt, que consiste en el algoritmo de

codificación estático de Huffman de 64 bits, que permite codificar en un

máximo de 9 bytes el tamaño de la celda y/o el payload data.

 ** Para este artículo, no se va a explicar como decodificar los tipo

de datos VarInt.

Analizando la Información

Un registro (cell) dentro de la página 3 de la base de datos SQLite

(msgstore.db) de la aplicación WhatsApp almacenará la información de la

siguiente forma:

ST2Labs 11 - WhatsApp Cell Payload Data SQLite Struct


La información se almacena dentro de una "celda" de la base de datos SQLite de forma continua, la imagen 4 representa "payload data", por tanto lo más interesante es saber que después del mensaje "Data" a continuación le sigue el timestamp.

Analizando la información de la imagen 10, se puede observar que se tiene el Key_remote_jid | key_from_me | key_id | status | data | timestamp. Se ha escogido un registro "no borrado" de la base de datos para analizar, de forma que se pueda contrastar la información resultante.

Con ayuda de DFSLite, se puede extraer la información para el registro 11358 de la página 3, donde se resumen de la forma siguiente:

** Page 3     - Cell Data 1/4 Offset 11358

  -  RowID:           8
  -  Size:                101
  -  Header:            32
  -  Data: 
  
20004108270808290500000f0800000008080808000d0501010100000008
0000333436373432353639313540732e77686174736170702e6e65745557
6870734b34507765664330546f646f20656e206f7264656e210151245e46a
8300151245cfd47ffffff

Cada uno de los campos de la base de datos se codifica según lo que en

SQLite se conoce como “Serial Type Codes Of The Record Format”, como

ya podéis imaginar con DFSLite he decodificado la información del

PAYLOAD HEADER y se obtiene el tipo de cada uno de los campos de la base

de datos y el tamaño, para el caso aquí se analiza, el timestamp es tipo

Integer (48bits) ~ 6 bytes.

ST2Labs 12 - DFSLite Decode Cell SQLite Data

Analizando la información con ayuda de un editor hexadecimal:

ST2Labs 13 - Cell Data to Offset 11358

Ya tenemos el timestamp del mensaje de WhatsApp, solo hace falta

decodificar el valor hexadecimal convertido a decimal para obtener un

valor Fecha y Hora.

Pero esto lo haremos en la ultima parte de mi artículo donde publicaré

el código de DFTime que convierte el timestamp de 6 bytes, y comentaré

como recuperar mensjes “eliminados” de la base de datos.

#ST2Labs

#GEOSystemSoftware

www.st2labs.com | www.seguridadparatodos.es


Ver también