Moin! 👋
This post walks through the SEGB viewer in crush, which received a complete forensic overhaul in the current release. The short version: Protobuf payloads are decoded automatically, and a built-in SQL editor lets you query every record — including nested and repeated Protobuf fields — without writing a single line of Python first.
What Is SEGB — and Why Should I Care?
SEGB is Apple's binary log format used by the Biome service. The name comes
from the four-byte magic header at the start of every file: 53 45 47 42 —
ASCII for SEGB. Apple has never publicly documented the format; the community
named it informally, and the name stuck.
Biome emerged in iOS 15 alongside knowledgeC.db, and by iOS 16 it had largely
replaced it. Today there are well over 130 defined Biome streams on a modern iOS device,
each tracking a specific type of user activity in its own folder — application foreground
and background events, device unlock events, Safari browsing history, Siri interactions,
messaging activity, airplane mode toggles, and much more. Every stream stores its records
in SEGB files. Every SEGB file payload is almost always Protobuf.
There are two versions of the format in the wild. SEGB v1 was used in iOS 15 and iOS 16. SEGB v2 arrived with iOS 17 and remains in use through current iOS versions — the internal structure changed significantly, with the addition of a trailer section that must be parsed to read the file correctly. crush handles both versions automatically; you do not need to know which one you are looking at before opening the file.
Two resources from the community worth reading alongside this post:
- Understanding and Decoding the Newest iOS SEGB Format (v2 / iOS 17) — Cellebrite Research (2023)
- iOS 16 — Now You 'C' It, Now You Don't: Breaking Down the Biomes — D20 Forensics (2022)
The open-source Python library that the crush SEGB parser builds on is ccl-segb by Alex Caithness and the CCL Solutions Group — full credit to them for that work.
Where to Find SEGB Files
A full filesystem acquisition is required — logical or backup-level imaging does not expose Biome data.
iOS:
- Primary user streams:
/private/var/mobile/Library/Biome/streams/public/ - System streams:
/private/var/db/biome/streams/
macOS:
/private/var/db/biome/streams/
These are the well-known paths — but SEGB files are not limited to them. On a full
filesystem image you will find additional SEGB data in locations such as
Library/DuetExpertCenter/, Library/PersonalizationPortrait/,
and inside app group containers under
Containers/Shared/AppGroup/<AppID>/. crush detects SEGB files by
their magic bytes automatically — so when you open a full filesystem image, files in
these locations show up in the file system panel when filtering for
type:SEGB without any manual searching.
In the well-known paths each stream lives in its own subdirectory named after the
data it tracks — _DKEvent.App.inFocus, _DKEvent.device.Unlocked,
_DKEvent.Safari.History, Device.Display.Backlight, and so on.
Within each stream folder you will find a local subfolder (records from this
device) and a remote subfolder (records synced from the user's other Apple
devices on the same Apple ID). There is also a tombstone folder containing
expired record versions. crush reads all of them.
The SEGB files themselves have no file extension and are named with a large integer — a Cocoa epoch timestamp in microseconds, which gives you a rough creation time from the filename alone before you open anything.
For this post I am using SEGB files from an iPhone acquisition, specifically from the App.inFocus stream:
/filesystem1/private/var/mobile/Library/Biome/streams/public/_DKEvent.App.inFocus/local/
Opening an SEGB File in crush
SEGB files appear as plain files in the crush file panel — no extension, no special icon. To open one, double-click it. crush reads the magic header, determines whether the file is v1 or v2, parses the records, decodes the Protobuf payloads, and opens the viewer. The detected version and total record count are shown in the Properties panel.
No extraction needed — crush reads directly from inside ZIP or TAR archives or from a folder on disk. All connections are read-only.
The SEGB Table
The main view is the SEGB table — the same name used in the SQL editor. Each row is one record from the file. The columns present depend on whether the file is v1 or v2; some are common to both.
Columns common to v1 and v2:
| Column | Description |
|---|---|
| Index | Sequential record number, 0-based. Order of appearance in the file. |
| Offset | Byte offset where the payload data begins, after the record header. Useful for correlating with raw hex examination. |
| State | Entry lifecycle state: Written = active record, Deleted = marked for deletion, Unknown = empty or unrecognised. Deleted records are colour-coded red. |
| CRC Stored | CRC32 value written into the entry header at creation time. |
| CRC Calc | CRC32 calculated over the current payload bytes at parse time. |
| CRC Passed | True if the CRC stored by the system matches the CRC crush calculates over the parsed payload bytes — confirming that what crush read matches what was written. False warrants closer examination: it may indicate corruption, an unknown format variant, or a parse issue. |
| Payload Size | Size of the raw Protobuf payload in bytes. |
| Payload | Schema-less wire-format decode of the raw payload bytes, rendered as human-readable text. Cocoa timestamps are decoded to ISO datetimes automatically, nested messages are expanded inline, repeated fields collected into arrays. Raw bytes remain accessible via the Blob Inspector. |
v1 only:
| Column | Description |
|---|---|
| Timestamp 1 | First Cocoa absolute time double from the 32-byte record header (bytes 8–15). Exact semantics not formally documented by Apple; in practice often identical to Timestamp 2, possibly reflecting record creation and commit time. |
| Timestamp 2 | Second Cocoa absolute time double from the 32-byte record header (bytes 16–23). May differ from Timestamp 1 in some entry states. |
v2 only:
| Column | Description |
|---|---|
| Creation | Cocoa absolute time from the trailer entry at the end of the file. Records when the entry was created. |
| Trailer Offset | Byte offset of this entry's trailer record within the trailer table at the end of the file. |
| Entry End Offset | End offset of the entry's data area, relative to the start of the entry region (after the 32-byte file header). Used internally to calculate entry length. |
Deleted Records
A record marked Deleted has an empty payload — the content is gone. What remains is the record itself: its index, offset, timestamp, and state. That is still forensically meaningful. A deleted entry proves that something was recorded here and was subsequently removed. The timestamp tells you when. The offset tells you exactly where in the file the entry sits. That is often enough to establish that activity occurred, even without the payload content.
Cell Preview and BLOB Inspector
Selecting any row in the SEGB table populates an inline preview panel below the table with the decoded content of the selected cell — the same human-readable Protobuf rendering shown in the Payload column, but with more space to read it. This works across all viewers in crush: SQLite, LevelDB, Realm, and SEGB.
For deeper inspection, double-clicking a cell or using the context menu opens the shared Blob Inspector dialog. The Blob Inspector always receives the raw bytes of the cell. For a Payload cell where crush has already decoded the Protobuf, the inspector additionally shows the decoded value alongside the raw bytes — so you can cross-reference the rendered text with the underlying hex without switching tools. From there you can switch to any other decode mode: Hex, UTF-8, Base64, and so on.
The SQL Editor — Querying the Biome
This is the feature that makes the crush SEGB viewer genuinely different from a basic file parser.
When you open an SEGB file, crush creates a backing SQLite database in memory and loads
all decoded records into a table named SEGB. The SQL editor — with
autocomplete for table and column names — lets you query that table directly.
Two payload columns are available:
| Column | Content |
|---|---|
Payload |
Human-readable rendered text — same as the table column |
Payload JSON |
Protobuf fields as JSON — queryable with json_extract |
The Payload JSON column is where the real power is. Every Protobuf field is
stored by its field number as a JSON key. SQLite's json_extract function lets
you reach into any field — including nested messages and repeated fields.
crush decodes payloads schema-less at the wire level, so field numbers match the raw Protobuf field numbers — not named keys. The meaning of each field varies by stream and is not publicly documented by Apple, but is consistent within a stream across devices and OS versions. Community tools like iLEAPP carry explicit field mappings for the most forensically relevant streams and are a good reference when you need to know what a specific field contains.
The SQL editor is primarily an analysis and exploration tool. The goal is not to replace
a dedicated parser — it is to understand the data well enough to build one. Working
through the fields with json_extract, identifying which field number carries
the bundle ID, which carries the timestamps, and how nested or repeated fields are
structured, is exactly the groundwork needed before writing a parser for iLEAPP or any
other tool. crush lets you do that interactively, without writing a single line of Python first.
For the App.inFocus stream some key fields are:
| json_extract path | Meaning |
|---|---|
$.1.1 | Activity / stream path (e.g. /app/inFocus) |
$.2 | Time Start — when the app came into focus |
$.3 | Time End — when the app left focus |
$.4.3 | Bundle ID (e.g. com.apple.Preferences) |
$.5 | Action GUID |
$.7[0].2 | Transition — how the app was reached (e.g. com.apple.SpringBoard.transitionReason.homescreen) |
$.8 | Time Write — when this record was written to the SEGB file |
For a detailed breakdown of the App.inFocus stream structure — including the record header layout and protobuf field analysis — D20 Forensics covered this in depth: iOS 16 — Now You 'C' It, Now You Don't. For the App.inFocus stream specifically, the payload field structure is consistent across SEGB v1 and v2, making it a useful cross-reference regardless of which version you are examining.
Some example queries for App.inFocus:
-- App focus timeline: bundle ID, start, end, and how the app was reached
SELECT "Index",
json_extract("Payload JSON", '$.4.3') AS bundle_id,
json_extract("Payload JSON", '$.2') AS time_start,
json_extract("Payload JSON", '$.3') AS time_end,
json_extract("Payload JSON", '$.7[0].2') AS transition
FROM SEGB
WHERE State = 'Written'
ORDER BY time_start;
-- All focus events for a specific app
SELECT * FROM SEGB
WHERE json_extract("Payload JSON", '$.4.3') = 'com.apple.Preferences';
-- Deleted records — payload is empty, but index, offset and timestamp remain
SELECT "Index", "Offset", "State"
FROM SEGB
WHERE State = 'Deleted';
A Practical Workflow
A useful approach for Biome examination in crush:
- Navigate to the relevant Biome stream folder.
- Open an SEGB file. Check the detected version and record count in the Properties panel before going further.
- Scan the Payload column — the decoded Protobuf text is often enough to identify records of interest without writing any SQL.
- Deleted records have an empty payload — but the record itself remains, including index, offset, timestamp, and state, which can be enough to establish that activity occurred.
- Switch to the SQL editor and use
json_extractonPayload JSONto isolate specific apps, time ranges, or field values. Autocomplete covers table and column names. - For any record where the decoded text is ambiguous, double-click the Payload cell to open the raw bytes in the Blob Inspector.
- Do not skip the
remotesubfolder — data from the user's other Apple devices may cover time ranges not present in the local files, or contain records that were already deleted locally.
Further Reading
- ccl-segb — Python modules for reading SEGB v1 and v2 files — Alex Caithness, CCL Solutions Group (open source)
- Python modules for SEGB files made available via GitHub — CCL Solutions Group
- Understanding and Decoding the Newest iOS SEGB Format (v2 / iOS 17) — Cellebrite Research (2023)
- iOS 16 — Now You 'C' It, Now You Don't: Breaking Down the Biomes — D20 Forensics (2022)
- Breaking Down the Biomes (series) — D20 Forensics (2022)
Happy examining. 🐢
No comments:
Post a Comment