Format de fichier SEGB de Biome : référence v1 et v2
Référence octet par octet de SEGB v1 et v2 : en-têtes, trailers, états des enregistrements, CRC32, alignement, noms de fichiers et champs protobuf par flux.
En bref. Un flux Biome est un dossier de fichiers SEGB. La v1 a un en-tête de 56 octets, avec SEGB aux octets 52–55 et l'offset de fin des données dans les octets 0–3 ; chaque enregistrement a un en-tête de 32 octets (longueur, état, deux horodatages, CRC32, champ inconnu) et est aligné sur 8 octets. La v2 commence par SEGB, un nombre d'entrées et une date de création, et indexe ses enregistrements au moyen d'un trailer d'entrées de 16 octets (offset de fin, état, date) placé en fin de fichier ; chaque enregistrement se compose d'un CRC32, d'un int32 inconnu et du payload, aligné sur 4 octets. Les états sont 1 écrit, 3 supprimé, 4 vide. Les payloads sont des protocol buffers sans schéma publié. Rien de tout cela n'est documenté par Apple.
Cette référence suit ccl-segb de CCL Forensics (licence MIT), qui cite les travaux de Cellebrite sur la structure v2, et c'est ce qu'implémente KnowledgeC Parser. Pour savoir où se trouvent ces fichiers et pourquoi ils comptent, commencez par le guide d'analyse forensique de knowledgeC.db et knowledgeC ou Biome.
Où se trouvent les fichiers SEGB
~/Library/Biome/streams/restricted/<Stream>/local/<file>
~/Library/Biome/streams/public/<Stream>/local/<file>
~/Library/Biome/streams/restricted/<Stream>/remote/<device UUID>/<file>
~/Library/Biome/streams/restricted/<Stream>/local/tombstone/<file>
/private/var/db/biome/streams/...
Le nom du flux (App.InFocus, App.WebUsage, ...) n'est pas stocké dans le fichier : il vient du dossier. Conservez l'arborescence lors de la collecte, sinon vous perdez le nom du flux, la distinction local / remote et l'UUID de l'appareil. Les fichiers de tombstone/ sont expirés (tombstone Biome).
Tous les entiers ci-dessous sont en little-endian. Les dates sont en Mac absolute time, stockées sous forme de doubles 64 bits : secondes écoulées depuis le 2001-01-01 00:00:00 UTC. Ajoutez 978307200 pour obtenir un temps Unix.
SEGB v1
En-tête de fichier (56 octets)
| Offset | Taille | Type | Champ |
|---|---|---|---|
0x00 | 4 | uint32 | Offset de fin des données (absolu, depuis le début du fichier) |
0x04 | 48 | Non documenté | |
0x34 | 4 | ASCII | Signature SEGB (octets 52–55) |
Les enregistrements commencent à l'octet 56 (0x38) et s'étendent jusqu'à l'offset de fin des données. Si cet offset pointe au-delà de la fin du fichier, la copie est tronquée.
En-tête d'enregistrement (32 octets)
| Offset dans l'enregistrement | Taille | Type | Champ |
|---|---|---|---|
0x00 | 4 | int32 | Longueur du payload |
0x04 | 4 | int32 | État |
0x08 | 8 | double | timestamp1 (Mac absolute) |
0x10 | 8 | double | timestamp2 (Mac absolute) |
0x18 | 4 | uint32 | CRC32 du payload |
0x1C | 4 | int32 | Inconnu |
0x20 | longueur | octets | Payload |
Après le payload, l'enregistrement suivant commence au prochain multiple de 8 depuis le début du fichier. Les noms timestamp1 et timestamp2 sont descriptifs : les sources publiques ne leur attribuent pas une signification fixe pour tous les flux. Rapportez donc les deux valeurs brutes plutôt que d'étiqueter l'une « début » et l'autre « fin ».
SEGB v2
En-tête de fichier (32 octets)
| Offset | Taille | Type | Champ |
|---|---|---|---|
0x00 | 4 | ASCII | Signature SEGB |
0x04 | 4 | int32 | Nombre d'entrées (entrées du trailer) |
0x08 | 8 | double | Date de création (Mac absolute) |
0x10 | 16 | Non documenté |
Trailer (16 octets par entrée, en fin de fichier)
Le trailer occupe les count × 16 derniers octets du fichier.
| Offset dans l'entrée | Taille | Type | Champ |
|---|---|---|---|
0x00 | 4 | int32 | Offset de fin de l'enregistrement, relatif à l'octet 32 |
0x04 | 4 | int32 | État |
0x08 | 8 | double | Date (Mac absolute) |
Enregistrements
Les enregistrements commencent à l'octet 32. Chacun se compose de :
| Offset dans l'enregistrement | Taille | Type | Champ |
|---|---|---|---|
0x00 | 4 | uint32 | CRC32 du payload |
0x04 | 4 | int32 | Inconnu |
0x08 | variable | octets | Payload, jusqu'à l'offset de fin |
Un enregistrement v2 n'a pas de champ de longueur. Pour le lire, triez les entrées du trailer par offset de fin, partez de l'octet 32 et lisez jusqu'à 32 + end offset. L'enregistrement suivant commence à la prochaine frontière de 4 octets. Comme l'état et la date se trouvent dans le trailer, l'en-tête d'un enregistrement v2 ne contient que le CRC et le mot inconnu.
Offsets de fin partagés
Deux entrées du trailer peuvent porter le même offset de fin. Le cas typique est un enregistrement écrit (état 1) puis supprimé (état 3) : les deux entrées pointent vers les mêmes octets, chacune avec sa propre date. Un parseur doit rapporter les deux, sans traiter la seconde comme un nouvel enregistrement. KnowledgeC Parser affiche l'entrée supprimée avec le même payload et la signale comme supprimée. Il ignore aussi les entrées du trailer à l'état 0, qui ne référencent aucune donnée.
États des enregistrements et CRC
| État | Signification | Que faire |
|---|---|---|
| 1 | Écrit | Enregistrement normal |
| 3 | Supprimé | Le payload peut encore être présent : décodez-le et signalez-le comme supprimé |
| 4 | Vide / inutilisé | Aucun enregistrement exploitable |
Le CRC est un CRC-32 standard, tel que calculé par zlib (zlib.crc32), sur le payload seul. Une non-concordance indique un enregistrement partiellement écrit ou endommagé, ou une copie réalisée pendant l'écriture du fichier. Conservez ces enregistrements en les signalant ; ne les écartez pas en silence.
Un exemple v2 annoté
Le fichier ci-dessous a été construit pour cet article selon la structure décrite plus haut : un enregistrement App.InFocus indiquant que Terminal est passé au premier plan. Il est synthétique, et les octets non documentés de l'en-tête sont ici à zéro.
00000000 53 45 47 42 01 00 00 00 00 00 00 a6 c0 2b c8 41 SEGB.........+.A
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020 67 88 af ff 00 00 00 00 18 01 21 00 00 00 80 ff g.........!.....
00000030 2b c8 41 32 12 63 6f 6d 2e 61 70 70 6c 65 2e 54 +.A2.com.apple.T
00000040 65 72 6d 69 6e 61 6c 00 27 00 00 00 01 00 00 00 erminal.'.......
00000050 66 66 66 80 ff 2b c8 41 fff..+.A
| Octets | Valeur | Signification |
|---|---|---|
0x00–0x03 | SEGB | Signature v2 |
0x04–0x07 | 01 00 00 00 | 1 entrée de trailer |
0x08–0x0F | double 811041100.0 | Créé le 2026-09-14 à 01:11:40 UTC |
0x10–0x1F | zéros | Non documenté |
0x20–0x23 | 0xffaf8867 | CRC32 du payload |
0x24–0x27 | 0 | Inconnu |
0x28–0x46 | 31 octets | Payload protobuf (ci-dessous) |
0x47 | 00 | Remplissage jusqu'à une frontière de 4 octets |
0x48–0x4B | 27 00 00 00 | Offset de fin 39 : 32 + 39 = 0x47, la fin du payload |
0x4C–0x4F | 01 00 00 00 | État 1, écrit |
0x50–0x57 | double 811073280.8 | 2026-09-14 10:08:00.8 UTC |
Le payload se décode ainsi :
| Octets | Tag | Champ | Valeur |
|---|---|---|---|
18 01 | champ 3, varint | statut | 1 = au premier plan |
21 + 8 octets | champ 4, 64 bits | date | 811073280.0 = 10:08:00 UTC |
32 12 + 18 octets | champ 6, délimité par longueur | bundle ID | com.apple.Terminal |
Un fichier de ce type, une fois stocké, porterait comme nom sa date de création en microsecondes, ici 811041100000000.
Dates dans les noms de fichiers
Les noms des fichiers SEGB sont des entiers. mac_apt les lit comme un temps Cocoa en microsecondes, ce qui donne une date de création approximative du fichier :
date -u -r $(( 811041100000000 / 1000000 + 978307200 ))
# Mon Sep 14 01:11:40 UTC 2026
Considérez-la comme un indice au niveau du fichier. Les dates des événements viennent des enregistrements et, pour certains flux, du payload.
Payloads protobuf
Les wire types en bref
Un message protobuf est une suite de champs. Chacun commence par une clé varint : field number << 3 | wire type (guide d'encodage).
| Wire type | Encodage | Contenu typique |
|---|---|---|
| 0 | Varint | Entiers, booléens, enums |
| 1 | 8 octets | double, fixed64 |
| 2 | Longueur varint + octets | Chaînes, octets, messages imbriqués |
| 5 | 4 octets | float, fixed32 |
Les wire types 3 et 4 (groupes) sont obsolètes et ne sont pas attendus ici.
Pourquoi le décodage sans schéma est ambigu
Apple ne publie aucun fichier .proto pour Biome. Sans schéma :
- un champ délimité par longueur peut être une chaîne, des octets bruts ou un message imbriqué, et de courtes chaînes comme les bundle IDs se décodent parfois comme des messages valides ;
- un champ de 8 octets peut être un double ou un entier ;
- un varint peut être une valeur signée, non signée, encodée en zigzag ou booléenne.
KnowledgeC Parser essaie d'abord du texte UTF-8 imprimable, puis un message imbriqué qui consomme tous les octets, puis des octets bruts. Il affiche les valeurs de 8 octets comme des doubles, avec une date lorsque la valeur est un Mac absolute time plausible. Certains payloads embarquent des property lists binaires, affichées comme telles. Les numéros de champ sont toujours conservés : vous pouvez donc vérifier toute interprétation avec un autre outil.
Numéros de champ par flux
Ces numéros viennent de la rétro-ingénierie communautaire, dans le plugin BIOME de mac_apt et dans iLEAPP. Ce n'est pas une documentation Apple ; validez-les sur des données de test issues du même build de l'OS avant de vous y fier.
| Flux | Champ | Signification | Source |
|---|---|---|---|
App.InFocus | 3 | Statut : 1 au premier plan, 0 plus au premier plan | mac_apt |
App.InFocus | 4 | Date (double) | iLEAPP |
App.InFocus | 6 | Bundle ID | mac_apt |
App.InFocus | 9, 10 | Chaînes de version | mac_apt |
App.WebUsage | 2 | Date | iLEAPP |
App.WebUsage | 4 / 5 / 6 | URL / domaine / bundle ID | mac_apt |
Safari.* | 1 | Domaine | mac_apt |
ScreenTime.AppUsage | 1 / 3 | Statut / bundle ID | mac_apt |
Notification.Usage | 4 / 8 / 9 | App / titre / sous-titre | mac_apt |
Device.Wireless.WiFi | 1 / 2 | SSID / statut | mac_apt |
Device.Wireless.Bluetooth | 1 / 2 / 3 / 4 | Adresse / nom / ID produit / statut | mac_apt |
SystemSettings.SearchTerms | 1 | Terme recherché | mac_apt |
Les enregistrements App.InFocus sont des événements, pas des intervalles : un enregistrement « au premier plan » est suivi plus tard d'un enregistrement « plus au premier plan » pour la même application. KnowledgeC Parser les apparie en intervalles (même utilisateur, même appareil, même bundle ID, à moins de 24 heures d'écart) et laisse les enregistrements non appariés sous forme d'événements isolés.
Ce qui reste inconnu
- Les 48 octets non documentés de l'en-tête v1, les 16 de l'en-tête v2, et l'int32 « inconnu » de chaque enregistrement.
- Une signification fixe de
timestamp1ettimestamp2en v1, valable pour tous les flux. - Les champs absents du tableau ci-dessus, et tous les champs des flux sans décodeur public.
App.MenuItem, documenté par Unit 42 sur macOS Tahoe 26, n'a pas de correspondance de champs publique : KnowledgeC Parser le décode sans schéma et affiche les numéros de champ bruts. - La version de macOS où la v2 a remplacé la v1.
Quand un rapport repose sur l'un de ces points, dites-le et montrez la valeur brute.
Outils qui lisent SEGB
| Outil | Ce qu'il fait |
|---|---|
| ccl-segb | Lecteur de référence pour des fichiers v1 et v2 isolés, enregistrements bruts |
mac_apt, plugin BIOME | Lit les flux depuis une image ou un dossier et décode les flux ci-dessus |
| iLEAPP | Flux Biome d'iOS |
| KnowledgeC Parser | v1 et v2 dans le navigateur, avec états, contrôles CRC, origine remote et tombstone, et une chronologie fusionnée avec knowledgeC.db |
Questions fréquentes
Le format SEGB est-il documenté par Apple ?
Non. Les structures de SEGB v1 et v2 sont issues de la rétro-ingénierie communautaire, implémentée dans ccl-segb (CCL Forensics), qui cite les travaux de Cellebrite. La signification des champs de payload vient de mac_apt et d'iLEAPP. Tout ce que ces sources ne couvrent pas doit être considéré comme inconnu.
Comment distinguer SEGB v1 de SEGB v2 ?
Cherchez la signature SEGB. En v1, elle se trouve aux octets 52 à 55, à la fin d'un en-tête de 56 octets. En v2, ce sont les quatre premiers octets du fichier, au début d'un en-tête de 32 octets.
Un enregistrement SEGB supprimé contient-il encore des données ?
Souvent, oui. L'état 3 marque un enregistrement comme supprimé, mais le payload peut rester dans le fichier. En v2, une entrée supprimée peut partager son offset de fin avec une entrée écrite : les deux pointent alors vers les mêmes octets. Signalez ces enregistrements comme supprimés, et non comme une activité en cours.
Quelle version de macOS est passée de SEGB v1 à v2 ?
Cette transition n'est pas documentée publiquement pour macOS. Sur iOS, la v1 est signalée d'iOS 14 à 16 et la v2 à partir d'iOS 17. Les parseurs détectent la version d'après l'en-tête : inutile de la connaître à l'avance.