ActivitiesCache.db-wal : pourquoi le fichier WAL compte
Comment le mode WAL de SQLite cache l'activité la plus récente de Windows Timeline dans ActivitiesCache.db-wal, et comment l'analyser sans rien altérer.
En bref. ActivitiesCache.db fonctionne en mode WAL de SQLite : les modifications validées vont dans ActivitiesCache.db-wal et n'atteignent le fichier principal qu'au moment d'un checkpoint (par défaut quand le WAL atteint 1 000 pages). Sur un système allumé ou utilisé récemment, l'activité la plus récente n'est souvent que dans le WAL. Collectez les deux fichiers au même instant, n'ouvrez jamais les originaux avec un client SQLite ordinaire, et utilisez un parseur qui rejoue les trames validées et indique quelles lignes viennent du WAL.
S'il ne fallait retenir qu'une chose de cette série, ce serait celle-ci : une Windows Timeline sans son WAL est une Timeline qui s'arrête trop tôt. Et « trop tôt » veut généralement dire « juste avant l'incident », parce que l'incident est récent.
Comment fonctionne le write-ahead logging
Le journal write-ahead de SQLite inverse le principe du journal classique. Au lieu de mettre de côté les pages d'origine puis d'écrire les modifications dans la base, SQLite laisse la base intacte et ajoute les pages modifiées dans un fichier -wal séparé. Une transaction est validée quand son enregistrement de commit est ajouté au WAL (sqlite.org/wal.html).
Les lecteurs cherchent chaque page d'abord dans le WAL, puis dans le fichier de base. Le report des pages dans la base s'appelle un checkpoint. Par défaut, SQLite en déclenche un automatiquement quand un commit fait dépasser 1 000 pages au WAL (sqlite.org). kacos2000 a fait la même observation pour cette base et relevé une taille de page de 4 096 octets dans les fichiers examinés (kacos2000).
Conséquences pour Timeline :
| Situation | Où se trouvent les dernières lignes |
|---|---|
| Utilisateur actif, WAL sous le seuil de checkpoint | Uniquement dans le WAL |
| Checkpoint tout juste exécuté | Dans la base ; le WAL peut être réinitialisé et réutilisé |
| Dernière connexion fermée proprement | Reportées ; le WAL est « généralement » supprimé (sqlite.org) |
| Plantage, coupure de courant, débranchement | Le WAL peut rester sur le disque avec des transactions validées non reportées (sqlite.org) |
Une ligne Timeline n'est pas seulement insérée une fois. Une session de focus (type 6) est mise à jour tant qu'elle dure : son EndTime et son activeDurationSeconds augmentent. Ces mises à jour passent elles aussi d'abord par le WAL. Le WAL influe donc non seulement sur quelles lignes existent, mais aussi sur ce qu'elles disent.
À l'intérieur du fichier WAL
Le format est documenté dans la spécification du format de fichier SQLite :
| Structure | Taille | Champs utiles |
|---|---|---|
| En-tête WAL | 32 octets | Magic, taille de page, numéro de séquence de checkpoint, salt-1, salt-2, somme de contrôle |
| En-tête de trame | 24 octets | Numéro de page, taille de la base après commit (non nulle uniquement sur les trames de commit), sels, somme de contrôle cumulée |
| Corps de trame | une page | La nouvelle version de cette page de la base |
Une trame n'est valide que si ses sels correspondent à l'en-tête et si sa somme de contrôle cumulée est correcte. Une trame dont le champ « taille de la base » est non nul est une trame de commit : elle clôt une transaction. Les trames situées après la dernière trame de commit appartiennent à une transaction jamais validée et doivent être ignorées (sqlite.org).
Après un checkpoint, quand le rédacteur suivant réinitialise le WAL, salt-1 est incrémenté et salt-2 est tiré au hasard, ce qui invalide les anciennes trames. La spécification précise que le fichier peut être tronqué lors de cette réinitialisation, sans que ce soit obligatoire (sqlite.org). C'est là que se trouve l'opportunité forensique : des trames de générations antérieures peuvent encore se trouver après les trames actuelles.
Pourquoi un client SQLite ordinaire est le mauvais outil
Ouvrir ActivitiesCache.db avec une bibliothèque SQLite standard fonctionne, et elle lit même le WAL pour vous s'il se trouve à côté de la base. Le problème, c'est la suite. Selon la documentation de SQLite, la dernière connexion qui se ferme effectue un dernier checkpoint puis supprime le WAL et son fichier de mémoire partagée (sqlite.org/wal.html).
Autrement dit, le simple fait de regarder peut réécrire la base et détruire le WAL, y compris les trames périmées qui contenaient des données plus anciennes. Règles pratiques :
- Hachez les originaux, puis travaillez sur des copies.
- Si vous devez utiliser un client SQLite, ouvrez une copie, ou utilisez les modes lecture seule / immutable sur une copie sacrifiable.
- Préférez un parseur qui lit les octets lui-même et n'écrit jamais.
Comment le Windows Timeline Parser traite le WAL
Le Windows Timeline Parser embarque son propre lecteur SQLite en lecture seule, écrit en Rust et compilé en WebAssembly. Il n'intègre aucun moteur SQLite et ne possède aucun chemin de code qui écrit. Avec le WAL, il :
- Valide le magic de l'en-tête WAL, la taille de page et la somme de contrôle de l'en-tête.
- Parcourt les trames tant que les sels correspondent et que la somme de contrôle cumulée tient.
- Superpose à la base la dernière version validée de chaque page ; les trames d'une transaction non validée sont comptées et ignorées.
- Analyse le résultat, puis analyse la base sans le WAL, et compare ligne par ligne.
- Marque chaque ligne Uniquement dans le WAL (nouvelle depuis le dernier checkpoint) ou Modifiée dans le WAL (la base en contient une version plus ancienne).
Il se protège aussi contre une erreur classique : un -wal provenant d'une autre base. Rien dans le format de fichier ne lie un WAL à sa base, si bien qu'un WAL de même taille de page serait appliqué en silence par un lecteur naïf. L'outil vérifie que la base rejouée reste une Timeline plausible et, sinon, ignore le WAL avec un avertissement.
Ces marqueurs transforment « le WAL compte » en outil de triage. Filtrez sur Uniquement dans le WAL et vous regardez l'activité survenue depuis le dernier checkpoint, qui correspond souvent, sur une machine saisie allumée, aux dernières heures avant la collecte.
Ce que le WAL peut contenir et que personne ne vous montre
Trois types de données peuvent survivre dans le WAL ou autour :
| Données | Où | Analysé par cet outil aujourd'hui ? |
|---|---|---|
| Lignes validées, non reportées | Trames WAL actuelles | Oui |
| Transaction non validée | Trames après le dernier commit | Comptées, ignorées (volontairement) |
| Versions antérieures des pages | Trames d'une génération de sel précédente | Non (signalées, pas carvées) |
| Lignes supprimées | Freeblocks et pages de la freelist de la base | Non |
Les travaux de recherche sur la récupération SQLite, comme bring2lite présenté au DFRWS, montrent que des enregistrements supprimés peuvent être récupérés dans ces structures (Meng et Baier, 2019). L'outil de carving du presse-papiers de kacos2000 indique récupérer des entrées supprimées à la fois dans la base et dans le WAL (kacos2000/WindowsTimeline). Si votre dossier repose sur des données Timeline supprimées, travaillez sur une copie avec un outil de carving et documentez la méthode séparément de la chronologie des enregistrements actifs.
Liste de contrôle
-
ActivitiesCache.dbetActivitiesCache.db-walcollectés au même instant (guide d'acquisition). - Originaux hachés ; analyse uniquement sur des copies.
- Le parseur indique combien de trames ont été validées, combien ignorées, et pourquoi il s'est arrêté.
- Le rapport distingue les lignes présentes uniquement dans le WAL des lignes reportées.
- Trames WAL périmées et pages libres préservées pour le carving si la suppression fait partie du périmètre.
FAQ
Qu'est-ce que ActivitiesCache.db-wal ?
C'est le journal write-ahead de SQLite pour la base Windows Timeline. Les modifications validées y sont d'abord ajoutées puis recopiées dans ActivitiesCache.db seulement lors d'un checkpoint : le WAL contient donc souvent l'activité la plus récente.
Peut-on ouvrir ActivitiesCache.db sans risque dans DB Browser for SQLite ?
Seulement sur une copie. Une connexion SQLite ordinaire lit le WAL placé à côté de la base et peut le reporter dans le fichier principal puis le supprimer à la fermeture de la dernière connexion, ce qui modifie les fichiers.
Le WAL peut-il contenir de l'activité supprimée ?
Oui, c'est possible. Les anciennes trames des générations précédentes du WAL sont invalidées par un changement de sel mais pas forcément écrasées : elles peuvent contenir des versions antérieures des pages. Les récupérer demande des outils de carving ; la plupart des parseurs les ignorent.