1 Three levels of acquisition
Mobile acquisition methods are usually sorted by how deep they reach. Deeper copies contain more, but need more access to the device, and the deepest ones are often impossible on a current, locked phone.
| Level | What you get | What it needs | Deleted data? |
|---|---|---|---|
| Logical | What the OS chooses to export: a backup, or data read through official interfaces | Unlocked device, trust/pairing with the computer | Only what is still inside exported files (freeblocks, WAL) |
| File system (incl. "full file system") | The files of the data partition, including app sandboxes and system databases | Elevated privileges on the device (root, jailbreak, or a tool that exploits a vulnerability) | Yes, inside the files; plus files apps never back up |
| Physical | A bit-for-bit copy of the flash storage | Low-level access; on modern phones the result is encrypted unless the keys can also be obtained | In principle unallocated space too, but file-based encryption makes it mostly unreadable |
On current phones, "full file system" copies have largely replaced physical images: since the storage is encrypted per file, a decrypted file-system copy is more useful than an encrypted raw dump.
2 Android: adb and the .ab backup
With USB debugging enabled and the computer authorised on the unlocked phone, the Android Debug Bridge gives you
a shell and file transfer. adb pull /sdcard/DCIM copies shared storage. The app sandboxes under
/data/data/ are not readable for the shell user, so a plain adb pull of an app's
databases fails without root.
adb backup was the classic logical method. It writes one .ab file and still exists,
but it is deprecated and increasingly empty:
- an app can opt out with
android:allowBackup="false"in its manifest; - since Android 12, data of apps that target Android 12 or later is no longer included (debuggable apps aside);
- the user must confirm on the device and can set a password, which encrypts the file.
The format itself is simple: four text lines, then a zlib stream that inflates to a tar archive with paths like
apps/<package>/db/….
Unpacking the sample backup (builder output)
Try this: the header ends at byte 0x17. Which two bytes follow, and what do they tell you about
the compression? Then check the tar listing: which folder would hold the app's SQLite databases?
Root- or exploit-based methods (temporary root, bootloader vulnerabilities, vendor service modes) reach the full file system. They are what commercial extraction tools do behind their buttons. They are device- and version-specific, can modify the device, and must be documented and validated; they are outside the scope of this course.
3 iOS: iTunes/Finder backups and Manifest.db
A trusted computer can make a local backup of an iPhone (Finder on macOS, iTunes or the Apple Devices app on Windows, or open-source tools using the same protocol). The backup is a folder named after the device's UDID:
IsEncrypted, app listThere are no original file names on disk. Manifest.db maps them: each row of its Files
table holds the domain (which area of the phone, e.g. AppDomain-<bundle id> or
HomeDomain), the relative path inside it, flags (1 file, 2 directory, 4 symbolic link)
and a file blob with metadata (size, times, protection class; NULL in this sample).
Cell 3 is the chat database: fileID 842b3ea268d81c26ede3c216a5fc1b7bebde69bf, so the
file sits in folder 84/. Note that the -wal file has a row of its own: a backup copies it
as a separate file. The fileID column is the primary key, so SQLite also keeps an index, sorted by
fileID. This is what an index leaf page (type 0A) looks like: each cell holds only
the key and the rowid.
The Files table and the SHA-1 check (builder output)
Try this: compute the fileID of the preferences file yourself:
printf '%s' 'AppDomain-com.example.chatter-Library/Preferences/com.example.chatter.plist' | sha1sum.
In which folder of the backup would it be? Find its row in the hex view.
Encrypted or not?
The user can enable "Encrypt local backup" with a password. Then every file, including Manifest.db
itself, is encrypted, and Manifest.plist carries the key bag. Encrypted backups contain
more than unencrypted ones: saved passwords (keychain items), Wi-Fi settings, website history and Health
data are only included when the backup is encrypted. Examiners therefore often prefer an encrypted backup with a
known password over an unencrypted one.
4 Copy the database with its -wal and -shm
Most apps run SQLite in WAL mode: new and changed pages go to chat.db-wal first and reach
chat.db only at the next checkpoint. chat.db-shm is a shared-memory index into the
WAL. Three consequences for acquisition:
- The newest data may exist only in the WAL. Copy the main file alone and recent messages are missing.
- Old versions of pages live on in the WAL until it is overwritten, including rows that were deleted since. This is often where deleted chats are found (see the WAL page).
- Opening the database can destroy that evidence. When the last connection closes, SQLite checkpoints
the WAL into the main file and deletes it. A GUI browser or a quick
sqlite3 chat.dbon the original does exactly that.
The builder output below shows the same SELECT on two copies of the sample chat database. With
immutable=1, SQLite reads the main file only and ignores the WAL, so the message with id 8, which so
far exists only in the WAL, is missing. With the -wal next to the copy it appears.
Main file only vs. main file + WAL (builder output)
5 Try it yourself
Answer from the hex views and builder outputs above. Numbers can be typed in decimal or hex (0x…).
Which format version does the sample .ab file declare?
The header is four lines of ASCII text, each ending in 0A. The version is the
second line.
Line 1 ends at 0x0E (…55 50 0A, "UP\n"). Line 2 is
35 0A at 0x0F: the ASCII character 0x35 = "5". Format version
5.
Note that this is text, not a binary number: version 10 would be 31 30 0A.
Inside the tar archive of the backup, in which folder of the app are its SQLite databases?
Open "Unpacking the sample backup" in section 2 and read the paths of the tar listing.
The listing shows apps/com.example.chatter/db/chatter.db, 4,096 bytes (4
pages of 1,024). The databases are in db/; sp/ holds the shared preferences
(settings.xml).
In which of the 256 folders of the iOS backup is the chat database's -wal file
stored? Give the two hex digits.
Find the row whose relativePath ends in -wal in the
Files page, and take the first two characters of its fileID.
Cell 4 (rowid 4) has relativePath "Documents/chat.sqlite-wal" and
fileID "ff744af15275a34bce2f6fecec9e569e315edf1c" (bytes 66 66 37 34 … = ASCII
"ff74…").
The file is stored as ff/ff744af1…, so in folder ff. The main database
(fileID 842b3e…) is in 84/: the two files of one database end up far apart.
How many rows of the Files table describe directories (flags = 2)?
Look at the serial type of flags (the 4th serial type in each record header). Serial
type 9 is the constant 1 and has no value bytes; serial type 1 is a 1-byte integer that follows in the values.
Record headers (length byte, then fileID, domain, relativePath, flags, file):
Cell 1: 06 5D 47 0D 01 00, and the flags value byte is 02. Cell 2:
06 5D 47 1F 01 00, flags value 02. Cells 3–6 have 09 in the flags
position: the constant 1, a file.
So 2 directories: the app's root (empty relativePath, serial type 0D = 13 =
empty text) and Documents.
These are the first 32 bytes of the .ab file: the four header lines and the start of the zlib
stream. Edit them and watch the decoded header below:
- Change the compression flag
31("1", at0x11) to30("0"). The zlib group disappears: a tool would now try to read a tar archive directly at0x18, and fail. - Reset, then change the second zlib byte
DA(at0x19) to9C, then toDB. Which one is still a valid zlib header? The two header bytes, read as a big-endian number, must be a multiple of 31. - Reset, then overwrite "none" (
6E 6F 6E 65at0x13) with41 45 53 2D. What does the decoder now say about reading the archive?