Le format .bcf, octet par octet
Une lecture pratique du format binaire RecentFileCache.bcf avec un dump hexadécimal, un enregistrement décodé et les cas limites qu'un parser doit gérer.
Le format RecentFileCache.bcf est assez petit pour s'apprendre autour d'un café. La référence autorisée est libyal/dtformats. Ce billet parcourt la même spec avec un dump hex réel et les cas limites qui font trébucher les parsers en pratique.
Endianness et encodage
- Tous les entiers sont little-endian.
- Les chaînes sont UTF-16LE, terminées par NUL.
- Pas de pied, pas de corps préfixé par longueur. Les enregistrements vont jusqu'à EOF.
Si vous avez déjà écrit un parser pour un des formats binaires de l'ère AppCompat Windows, rien de tout cela ne vous surprendra.
L'en-tête de 20 octets
| Offset | Taille | Valeur | Description |
|---|---|---|---|
| 0 | 4 | 0x0fffeefe | Signature. Le seul champ d'en-tête à traiter comme porteur. |
| 4 | 4 | 0x00002211 | Inconnu. Constante observée. |
| 8 | 4 | 0x00000003 | Inconnu. Constante observée. |
| 12 | 4 | 0x00000001 | Inconnu. Constante observée. |
| 16 | 4 | variable | Possiblement une somme de contrôle. Aucun parser public ne la vérifie. |
Validez la signature. Si les octets à l'offset 0 ne sont pas fe ef ff 0f little-endian, vous ne regardez pas un RecentFileCache.bcf. Sortez et avertissez. Les trois autres constantes ont eu la même valeur sur tous les échantillons que j'ai vus en une décennie d'hôtes Win7. Traitez-les comme des constantes pour des vérifications de cohérence ; ne conditionnez pas le parsing à elles.
Un enregistrement
offset size field
0 4 char_count ; nombre d'unités de code UTF-16, INCLUT le NUL final
4 var path ; UTF-16LE, terminé par NUL
Un char_count à 5 signifie 4 unités de code de chemin plus le NUL, soit 10 octets de charge utile plus 4 pour le compteur.
Un char_count à 0 n'est pas un enregistrement vide légitime. Tous les parsers que j'ai vus le traitent soit comme une corruption soit comme un terminateur et s'arrêtent. Faites pareil. N'essayez pas de lire 0 octet en boucle infinie.
Un dump hex commenté
Fichier minimal contenant C:\foo.exe et D:\bar :
00000000 fe ef ff 0f 11 22 00 00 03 00 00 00 01 00 00 00 en-tête (signature + 3 inconnus)
00000010 00 00 00 00 possible checksum (à zéro)
00000014 0b 00 00 00 char_count = 11 (10 chars + NUL)
00000018 43 00 3a 00 5c 00 66 00 6f 00 6f 00 2e 00 65 00 "C:\foo.e"
00000028 78 00 65 00 00 00 "xe" + NUL
0000002e 07 00 00 00 char_count = 7 (6 chars + NUL)
00000032 44 00 3a 00 5c 00 62 00 61 00 72 00 00 00 "D:\bar" + NUL
Décodé :
| Enregistrement | char_count | Chemin |
|---|---|---|
| 0 | 11 | C:\foo.exe |
| 1 | 7 | D:\bar |
Taille totale : 64 octets.
Notez que les chemins enregistrés dans les échantillons réels portent presque toujours le préfixe NT \??\ (par exemple \??\C:\Users\bob\AppData\Local\Temp\setup.exe). C'est la notation de chemin DOS du NT object manager. Enlevez-la pendant la normalisation. N'essayez pas de la « corriger » avant de valider la signature.
Cas limites qu'un vrai parser doit gérer
Un parser robuste ne fait pas confiance au fichier. Les .bcf réels dans la nature arrivent avec tous ces problèmes.
- Mauvaise signature. Les copies forensiques sont rembourrées, préfixées d'en-têtes d'acquisition ou tirées d'une région mal alignée. Validez la signature ; avertissez mais continuez si vous voulez un comportement indulgent.
char_count = 0. Traitez comme terminateur. Stop.char_countplus grand que les octets restants. Fichier tronqué ou enregistrement corrompu. Stop et avertissement. Ne lisez pas au-delà d'EOF.- Octets de queue après le dernier enregistrement bien formé. Courant, surtout sur des fichiers acquis en pleine réécriture. Émettez un avertissement pour que l'analyste sache qu'il y a des données de queue inexpliquées.
- Corps de chaîne vide (
char_count = 1). Juste le NUL. Techniquement valide. Émettez un chemin vide ; ne plantez pas. - Paires de substituts UTF-16. Le format les permet. Décodez de façon permissive avec remplacement des séquences malformées. Ne faites pas échouer tout le fichier pour un point de code laid.
L'implémentation de référence dans ce dépôt fait tout ce qui précède et émet un tableau structuré d'avertissements à côté des enregistrements.
Ce que le format ne vous dit pas
Après tout ce parsing soigné, vous avez une liste de chemins. Il n'y a pas :
- d'horodatages par entrée,
- de tailles de fichiers,
- de hashes,
- de signataires,
- de métadonnées PE,
- ni d'indication du moment où une entrée a été ajoutée par rapport au dernier passage de
ProgramDataUpdater.
Si vous voulez répondre « quand » ou « qu'était ce binaire », couplez chaque hit BCF intéressant avec Amcache.hve pour la même époque (ou Prefetch, ou le fichier sur disque, ou l'enregistrement MFT) et triangulez. Le BCF vous donne une liste de pistes. Les métadonnées vivent ailleurs.