DEV Community

Cover image for The Evidence Is in the Phone. Most of It Never Makes It Into the Case.
Charles West
Charles West

Posted on

The Evidence Is in the Phone. Most of It Never Makes It Into the Case.

In every custody dispute, every contested divorce, every harassment claim — the phone is the richest source of evidence available. Both sides know it. Attorneys request text message exports. PIs take screenshots. Forensic examiners produce reports.

And almost every time, what ends up in the case file is a fraction of what's actually there.

I'm a technologist — 25 years in software, QA, systems design — and when I cracked open my own iPhone backup, what I found changed the way I think about phone evidence entirely. This article walks through what's actually inside an iTunes/Finder backup at the file and database level, because most people — including many professionals — have never looked.

The Backup Structure: What Apple Actually Stores

When you back up an iPhone to a computer via iTunes (Windows) or Finder (macOS), Apple creates a folder in a predictable location:

  • macOS: ~/Library/Application Support/MobileSync/Backup/
  • Windows: %APPDATA%\Apple Computer\MobileSync\Backup\

Inside, you'll find a folder named with the device's UDID. Open it and you'll see thousands of files with 40-character hexadecimal filenames — no extensions, no directory structure. It looks like chaos.

It's not. Every one of those filenames is a SHA-1 hash of the file's original domain and path on the device.

How the Hashing Works

Apple uses a consistent hashing scheme. Each file on the device has a domain (like HomeDomain or MediaDomain) and a relative path (like Library/SMS/sms.db). The backup filename is:

SHA1(domain + "-" + relativePath)
Enter fullscreen mode Exit fullscreen mode

For example, the messages database:

SHA1("HomeDomain-Library/SMS/sms.db")
= 3d0d7e5fb2ce288813306e4d4636395e047a3d28
Enter fullscreen mode Exit fullscreen mode

That hash is the filename in the backup folder. No extension, no directory hierarchy — just the hash. This means if you know the domain and path of a file on the device, you can calculate exactly which backup file contains it.

Manifest.db: The Rosetta Stone

The most important file in any backup is Manifest.db — a SQLite database that maps every hashed filename back to its original path, domain, and metadata. Its structure looks like this:

CREATE TABLE Files (
    fileID TEXT PRIMARY KEY,
    domain TEXT,
    relativePath TEXT,
    flags INTEGER,
    file BLOB
);
Enter fullscreen mode Exit fullscreen mode
  • fileID — the SHA-1 hash (the filename in the backup folder)
  • domain — the app or system domain (HomeDomain, AppDomain-com.app.name, etc.)
  • relativePath — the original file path on the device
  • flags — file type (1 = file, 2 = directory, 4 = symlink)
  • file — a binary plist blob containing file metadata (size, timestamps, permissions)

Query it and you get a complete directory listing of the entire device:

SELECT fileID, domain, relativePath FROM Files
WHERE flags = 1
ORDER BY domain, relativePath;
Enter fullscreen mode Exit fullscreen mode

This single query reveals every file backed up from the phone — thousands of entries spanning messages, photos, call logs, browser history, app data, and more.

The Key SQLite Databases

Here's where it gets interesting. Several of the backed-up files are SQLite databases themselves, each containing structured, queryable data. The most important ones:

Messages — sms.db

Hash: 3d0d7e5fb2ce288813306e4d4636395e047a3d28
Path: HomeDomain-Library/SMS/sms.db

-- Key tables
message          -- every SMS and iMessage
chat             -- conversation threads
chat_message_join -- links messages to chats
handle           -- phone numbers / email addresses
attachment       -- photos, videos, files sent in messages

-- Useful query: messages with contact info and timestamps
SELECT
    m.ROWID,
    m.text,
    m.date,           -- Apple epoch: seconds since 2001-01-01
    m.is_from_me,
    m.date_read,
    m.date_delivered,
    h.id AS contact
FROM message m
LEFT JOIN handle h ON m.handle_id = h.ROWID
ORDER BY m.date;
Enter fullscreen mode Exit fullscreen mode

Note: Apple timestamps use Core Data epoch — seconds (or nanoseconds, depending on iOS version) since January 1, 2001, not the Unix epoch. You'll need to convert:

from datetime import datetime, timedelta

APPLE_EPOCH = datetime(2001, 1, 1)

def apple_timestamp_to_datetime(ts):
    if ts > 1e15:  # nanoseconds (iOS 14+)
        ts = ts / 1e9
    return APPLE_EPOCH + timedelta(seconds=ts)
Enter fullscreen mode Exit fullscreen mode

Call History — call_history.db

Hash: 2b2b0084a1bc3a5ac8c27afdf14afb42c61a19ca
Path: HomeDomain-Library/CallHistoryDB/CallHistory.storedata

-- Key table: ZCALLRECORD
SELECT
    ZADDRESS,          -- phone number
    ZDATE,             -- Apple epoch timestamp
    ZDURATION,         -- call duration in seconds
    ZORIGINATED,       -- 1 = outgoing, 0 = incoming
    ZANSWERED,         -- 1 = answered, 0 = missed/declined
    ZCALLTYPE          -- 1 = voice, 8 = FaceTime video, 16 = FaceTime audio
FROM ZCALLRECORD
ORDER BY ZDATE;
Enter fullscreen mode Exit fullscreen mode

Photos Metadata — Photos.sqlite

Path: CameraRollDomain-Media/PhotoData/Photos.sqlite

-- Key tables: ZASSET, ZADDITIONALASSETATTRIBUTES
SELECT
    a.ZFILENAME,
    a.ZDATECREATED,
    a.ZLATITUDE,
    a.ZLONGITUDE,
    attr.ZORIGINALFILESIZE,
    attr.ZCAMERAMAKE,
    attr.ZCAMERAMODEL
FROM ZASSET a
LEFT JOIN ZADDITIONALASSETATTRIBUTES attr
    ON a.Z_PK = attr.ZASSET
ORDER BY a.ZDATECREATED;
Enter fullscreen mode Exit fullscreen mode

Every photo with GPS coordinates, camera model, exact timestamp — all queryable.

Safari Browser History — History.db

Hash: e74113c185fd8297e140571f7e3beb3cfceddb58
Path: HomeDomain-Library/Safari/History.db

SELECT
    hi.url,
    hi.visit_count,
    hv.visit_time,    -- Apple epoch
    hv.title
FROM history_items hi
JOIN history_visits hv ON hi.id = hv.history_item
ORDER BY hv.visit_time;
Enter fullscreen mode Exit fullscreen mode

Other Key Databases

Data File Path Hash
Notes HomeDomain-Library/Notes/notes.sqlite Varies by iOS version
Contacts HomeDomain-Library/AddressBook/AddressBook.sqlitedb 31bb7ba8914766d4ba40d6dfb6113c8b614be442
Voicemail HomeDomain-Library/Voicemail/voicemail.db Varies
Wi-Fi locations SystemPreferencesDomain-SystemConfiguration/com.apple.wifi.plist Varies
Calendar HomeDomain-Library/Calendar/Calendar.sqlitedb Varies

What Most People Miss

Here's the problem: an attorney requests "text messages between the parties." Someone scrolls through the phone, takes screenshots, maybe exports a PDF through a consumer app.

That workflow misses almost everything.

It misses the call that happened two minutes before the text — the one that provides context for why the message was sent. It misses the browser search at 1 AM that shows state of mind. It misses the GPS coordinates on a photo that contradict a stated alibi. It misses the voicemail that was listened to but never saved.

Most critically, it misses the pattern — the escalation visible only when you lay out messages, calls, and locations on a single timeline across weeks or months.

Individual screenshots are moments frozen in isolation. The real story lives in the connections between data points across multiple channels.

The Tooling Gap

The professional forensic tools — Cellebrite, Magnet AXIOM, Oxygen — are powerful, but they're built for law enforcement and enterprise labs. They cost thousands per license and require training and certification.

Consumer tools let you browse messages and export contacts, but they don't do cross-channel analysis. They don't reconstruct timelines. They don't let you see a call log, text thread, browser history, and location data side by side in chronological order.

There's a gap in the middle — and it's exactly where most family law cases, PI investigations, and civil disputes live.

What I Built

I built OpenExtract to fill that gap. It's a free, open-source desktop app that reads a local iPhone backup and extracts everything — messages, calls, photos, contacts, voicemails, notes, browser history, and more — into structured, searchable, exportable formats.

It parses Manifest.db, resolves the SHA-1 hashes, opens each SQLite database, converts Apple-epoch timestamps, and produces unified, cross-referenced output. It runs locally — no cloud, no account, no subscription.

If you work with phone evidence and you've never opened Manifest.db in a SQLite browser, I'd encourage you to try it. You might be surprised by how much data is sitting right there, already preserved, waiting to be queried.

Site: openextract.app
GitHub: github.com/openextract


Charles is a retired technologist and the developer behind OpenExtract. This is the third in a series of articles about phone data, personal records, and the tools we use to make sense of them.

Top comments (0)