Saturday, May 16, 2026

Beyond the C — SEGB and Biome Forensics with crush

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:

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.

Filesystem Panel - Showing SEGB in well-known folders



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.

SEGB table showing columns for a v2 file


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.


SCREENSHOT: Blob Inspector open on a Protobuf payload from an SEGB record


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.1Activity / stream path (e.g. /app/inFocus)
$.2Time Start — when the app came into focus
$.3Time End — when the app left focus
$.4.3Bundle ID (e.g. com.apple.Preferences)
$.5Action GUID
$.7[0].2Transition — how the app was reached (e.g. com.apple.SpringBoard.transitionReason.homescreen)
$.8Time 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';

SQL editor with a json_extract query running against the SEGB table, results shown below


A Practical Workflow

A useful approach for Biome examination in crush:

  1. Navigate to the relevant Biome stream folder.
  2. Open an SEGB file. Check the detected version and record count in the Properties panel before going further.
  3. Scan the Payload column — the decoded Protobuf text is often enough to identify records of interest without writing any SQL.
  4. 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.
  5. Switch to the SQL editor and use json_extract on Payload JSON to isolate specific apps, time ranges, or field values. Autocomplete covers table and column names.
  6. For any record where the decoded text is ambiguous, double-click the Payload cell to open the raw bytes in the Blob Inspector.
  7. Do not skip the remote subfolder — 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

Happy examining. 🐢

No comments:

Post a Comment