Il post seguente è stato tradotto per gentile concessione di Mobile Device Forensics
Sono affascinato da SQLite. Ma prima che possiate dire “Mike hai proprio bisogno di uscire di più e farti una vita! ” considerate questo: i due sistemi operativi per smartphone più popolari attualmente sono IOS e Android e utilizzano database SQLite per memorizzare informazioni importanti, come contatti, SMS e i record delle chiamate. Si tratta di parecchi utenti: sia vittime che carnefici. Vi siete mai chiesti come SQLite strutturi i suoi record? Comprenderne l’architettura è fondamentale per avvalorare l’output degli strumenti di forensic e sapere dove cercare le prove, incluse quelle preziose informazioni eliminate.
Le immagini del database SQLite iniziano sempre con una ben nota signature a 16 byte che, in ASCII, è rappresentata dal “formato SQLite3” seguito da un byte null. L’header dell’immagine del database è di 100 byte. Una discussione completa sull’header dell’immagine del database si può trovare sulla pagina ufficiale di SQLite .
Tra le altre cose un’immagine del database, serializzata e ben formata, avrà uno schema di database o un layout di tabella. Conoscere lo schema delle tabelle è la parte chiave della conoscenza, in quanto fornirà la guida verso l’header del record e dei conseguenti contenuti dei record.
Come esempio useremo un record del database degli SMS di un iPhone di prima generazione con iOS versione 3.13. Di seguito è riportato una schermata dello schema della tabella dei messaggi, che usa il mio editor Mac SQLite preferito: Base .
Preso atto dello schema della tabella dei messaggi all’interno del database sms, diamo un’occhiata a un record con un editor esadecimale.
Il record è strutturato come mostra il grafico sottostante.
Inoltre il record utilizza i valori della tabella sottostante per rappresentare i valori dei byte.
Prendiamo il nostro esempio e analizziamo l’header del record. Il primo byte, ovviamente, rappresenta la lunghezza del nostro record: in questo caso il record è di 110 byte. Il secondo byte è la nostra chiave.
Il byte successivo rappresenta la lunghezza dell’header del nostro record includendo questo byte, che è di 19 byte.
Il byte successivo è null, il che indica che il valore non è incluso nel record. Questo sarebbe stato rappresentato dal ROWID dello schema. Il byte successivo corrisponde alla riga dell’indirizzo nello schema. Il byte 0×27 è dispari e maggiore di 13. Secondo la nostra tabella questo corrisponde al testo e la lunghezza in byte è calcolata prendendo il valore decimale sottraendo tredici e dividendo per due.
39 -13 = 26 / 2 = 13
Possiamo vedere dal grafico sottostante che l’indirizzo, o il numero di telefono, è in realtà 13 byte di lunghezza.
Il byte successivo, 0×4, corrisponde nello schema alla data dell’SMS. Si tratta di un valore di quattro byte memorizzato in epoch time. Il valore qui è 1296980309 e si traduce in Dom, 06 Feb 2011 09:18:29 GMT+1.
Il byte successivo, 0×81 è, come indicato nello schema, il messaggio di testo; ma è l’unico. SQLite utilizza un metodo di compressione basato sulla codifica di Huffman per memorizzare i valori maggiori di 127 bit. In questo caso il byte nell’header del record che indica il messaggio di testo è \X81 o 129 e, di conseguenza, maggiore di 127. Dato che il metodo utilizza 2 byte fino ad un valore decimale di 16383, si può assumere che il byte successivo \x0d stia anche per la lunghezza del messaggio di testo. Il metodo per calcolare la lunghezza del messaggio di testo è il seguente: dove X = il valore del primo byte e Y = il valore del secondo byte.
(X-128) x 128 + Y
Dopo aver eseguito il calcolo ecco il risultato:
(129-128) x 128 + 13
\ X142
Per trovare la lunghezza dell’header ora facciamo riferimento alla tabella e calcoliamo normalmente:
(N-13) / 2
(129) / 2
64
Questa, infatti, è la lunghezza del messaggio di testo. Il messaggio è puro esa in ascii.
Il byte successivo nell’header è 0×1 e nello schema si riferisce alla riga dei flag. Il valore in questo caso è 0×02, ciò significa che si tratta di un testo in entrata.
L’ultimo byte significativo compare nell’offset 17 del record e, come indica la nostra tabella, è un valore maggiore di 13 (0×11 = decimale 17).
Poiché il calcolo è N-13/2 il valore che abbiamo qui è 2 byte e si riferisce, nello schema, al paese. Nel nostro esempio è 0x6A 0x6F, o “Jo”, per la Giordania.
Spero che troverete utile questo post nelle vostre imprese di forensic. Questo post non sarebbe stato possibile senza il generoso aiuto e il consiglio di DC Shafik Punja di Calgary e Sheran Gunasekera di ZenConsult Pte Ltd.
Le ricerche sulla codifica di Huffman nei record di SQLite è stata condotta utilizzando l’articolo Murilo Tito Pereira “Analisi della forensic della cronologia Internet di Firefox 3 e il recupero dei record eliminati di SQLite” pubblicato da Elselvier.
Fonte: SQLite Records
I am facinated by SQLite. But before you say “Mike you really need to get out more and get a life! ” consider this -the two most popular smartphone operating systems of today, iOS and Android, use SQLite databases to store important information such as contacts, SMS, and call records. That’s a lot of users – both victims and perpetrators. Have you ever wondered how the SQLite structures its records? An understanding of the SQLite record architecture is crucial to validating the output of forensic tools and for knowing where to look for evidence – including that elusive brass ring, deleted information.
SQLite database images always begin with a well know 16 byte signature which in ASCII is represented by “SQLite format 3″ followed by a null byte. The database image header is 100 bytes in length. A full discussion of the database image header can be found on the official SQLite page. Amongst other things a well formed serialized database image will have a database schema or table layout. Knowing the schema of tables is a key bit of knowledge as it will provide the guide to the record header and subsequent record contents.
We will be using a record from the sms database of a first generation iPhone running iOS version 3.13 as an example for this post. Below is a screen shot taken of the schema of the message table using my favorite Mac SQLite editor Base.
Having noted the schema of the message table within the sms database, lets take a look at a record in a hex viewer.
The record is structured as is show in the below graphic.
In addition the record uses the values in the below table to represent the values of the bytes.
So let’s take our example and work through the record header. The first byte of course is our record length – in this case the record is 110 bytes long. The second byte is our key.
The next byte is the length of our record header including this byte – which is 19 bytes.
The next byte is null which indicates that the value is not included in the record. This would have been the ROWID from the schema. The next byte corresponds to the address row in the schema. The byte 0×27 is odd and greater than 13. According to our table this corresponds to text and the byte length is derived by taking the decimal value subtracting thirteen and then dividing by two.
39 -13 = 26 / 2 = 13
We can see from the below graphic that the address or telephone number is indeed 13 bytes in length.
The next byte, 0×4 corresponds in the schema to the date of the SMS. This is a four byte value and is stored in epoch time. The value here is 1296980309 and translates to Sun, 06 Feb 2011 08:18:29 GMT.
The next byte, 0×81 is, as is indicated in the schema, the text message – but it is unique. SQLite uses a compression method based on Huffman coding to store values greater than 127 bits. In this instance the byte in the record header indicating the text message is \x81 or 129 and therefore greater than 127. Since the method uses 2 bytes up to a decimal value of 16,383, we can assume the next byte \x0D is also for the length of the text message. The method to calculate the length of the text message is as follows – where X = the first byte value and Y = the second byte value –
(X-128) x 128 + Y
Calculated out this comes to the below
(129-128) x 128 + 13
\x142
To find the length of the header we now refer to the table and do our calculation as normal
(N-13)/2
(129)/2
64
This is indeed the length of the text message. The message is straight hex to ascii.
The next byte in the header is 0×1 and in the schema refers to the flags row. The value in this case is 0×02 which means that it is an incoming text.
The last byte of significance in this record occurs at offset 17 in the record and as our table indicates is a value greater than 13 (0×11 = decimal 17). Since the calculation is N-13/2 the value we have here is 2 bytes and this refers in the schema to the country. In our example this is 0x6A 0x6F or “jo” for Jordan.
I hope that you find this post useful in your forensic endeavors. This post would not have been possible without the generous help and counsel of DC Shafik Punja of Calgary and Sheran Gunasekera of ZenConsult Pte Ltd.
Research regarding Huffman encoding in SQLite records was conducted using Murilo Tito Pereira’s article “Forensic analysis of the Firefox 3 Internet history and recovery of deleted SQLite records” published by Elselvier.
Source: SQLite Records