Zone de redémarrage et LSN du $LogFile expliqués
Les pages de redémarrage du $LogFile NTFS : champs de la zone de redémarrage, client NTFS, points de contrôle, et comment convertir un LSN en offset.
TL;DR. Les deux premières pages du $LogFile sont des pages de redémarrage RSTR. Chacune contient une zone de redémarrage : LSN courant, taille du journal, nombre de bits du numéro de séquence, drapeaux, et un enregistrement client NTFS qui pointe vers le dernier point de contrôle. Un LSN est un nombre de 64 bits dont les bits de poids faible donnent l'offset de l'enregistrement en unités de 8 octets et les bits de poids fort un compteur de rebouclage ; avec seq_bits lu dans la zone de redémarrage, offset = (LSN << seq_bits) >> (seq_bits − 3). Les LSN ne font que croître : ils ordonnent tout ce que contient le journal — et les mêmes LSN apparaissent dans les en-têtes d'enregistrements du $MFT.
Si vous devez un jour expliquer pourquoi un parseur affiche « LSN 115720 → 117880 », ou vérifier un enregistrement à la main dans un éditeur hexadécimal, c'est cette partie du format qu'il faut connaître. L'organisation des pages est décrite dans Format du $LogFile 1.1 et 2.0.
L'en-tête de la page de redémarrage
Deux copies, à l'offset 0 et une page système plus loin (en général 0x1000). Elles ne sont pas forcément synchronisées (dfir.ru) ; un lecteur valide les deux et garde celle dont le LSN courant est le plus élevé. Offsets d'après libfsntfs et ntfs3 :
| Offset | Taille | Champ |
|---|---|---|
0x00 | 4 | Signature : RSTR, ou CHKD si chkdsk a modifié le journal |
0x04 | 2 | Offset du tableau de séquence de mise à jour |
0x06 | 2 | Nombre d'éléments du tableau de séquence |
0x08 | 8 | Dernier LSN de chkdsk |
0x10 | 4 | Taille de page système |
0x14 | 4 | Taille de page du journal |
0x18 | 2 | Offset de la zone de redémarrage |
0x1A | 2 | Version mineure |
0x1C | 2 | Version majeure (1 ou 2 en pratique) |
Appliquez les corrections de séquence de mise à jour avant de lire quoi que ce soit au-delà du premier secteur.
La zone de redémarrage
À l'offset indiqué en 0x18 :
| Offset | Taille | Champ | Pourquoi c'est utile |
|---|---|---|---|
0x00 | 8 | LSN courant | LSN le plus récent au moment où cette zone a été écrite |
0x08 | 2 | Clients du journal | Nombre d'emplacements clients (normalement un : NTFS) |
0x0A / 0x0C | 2 + 2 | Liste des clients libres / utilisés | 0xFFFF = vide |
0x0E | 2 | Drapeaux | 0x1 E/S sur page unique (ntfs3) ; le parseur dans le navigateur lit 0x2 comme « démonté proprement » |
0x10 | 4 | Bits du numéro de séquence | Nécessaire pour LSN ↔ offset |
0x14 | 2 | Longueur de la zone de redémarrage | |
0x16 | 2 | Offset du tableau des clients | Relatif à la zone de redémarrage |
0x18 | 8 | Taille du fichier journal | À comparer avec votre copie : plus courte = tronquée |
0x20 | 4 | Longueur des données du dernier LSN | |
0x24 | 2 | Longueur de l'en-tête d'enregistrement | |
0x26 | 2 | Offset des données dans une page | Où commencent les enregistrements dans chaque page RCRD |
0x28 | 4 | Compteur d'ouvertures du journal |
L'enregistrement client NTFS
Chaque emplacement client fait 0xA0 octets ; NTFS est normalement le seul client :
| Offset | Champ | Signification |
|---|---|---|
0x00 | LSN le plus ancien | Plus ancien enregistrement dont la reprise peut encore avoir besoin |
0x08 | LSN de redémarrage client | LSN du dernier enregistrement de point de contrôle |
0x1C | Longueur du nom (octets) | |
0x20 | Nom | UTF-16 : NTFS |
Les points de contrôle : enregistrements de type 2
Le LSN de redémarrage client pointe vers un enregistrement de type 2 (redémarrage client). Pour NTFS, sa charge utile (NTFS_RESTART dans ntfs3) liste les LSN et longueurs des dumps de tables écrits à ce point de contrôle :
| Offset | Champ |
|---|---|
0x00 / 0x04 | Version majeure / mineure du client (0.0 ou 1.0) |
0x08 | LSN de début du point de contrôle |
0x10 | LSN du dump de la table des attributs ouverts |
0x18 | LSN du dump des noms d'attributs |
0x20 | LSN du dump de la table des pages modifiées |
0x28 | LSN du dump de la table des transactions |
0x30–0x3C | Longueurs des quatre dumps |
La reprise part de là : elle recharge la table des attributs ouverts et les autres tables, puis avance. Pour l'analyste, le point de contrôle explique pourquoi des enregistrements OpenAttributeTableDump et AttributeNamesDump reviennent régulièrement, et pourquoi un parseur en a besoin pour nommer l'attribut visé par un enregistrement.
Anatomie d'un LSN
Un LSN fait 64 bits, découpés en deux :
63 (64 - seq_bits) 0
+-------------------------+-----------------------------------+
| numéro de séquence | offset en unités de 8 octets |
+-------------------------+-----------------------------------+
Le numéro de séquence augmente à chaque rebouclage du journal, ce qui garde les LSN strictement croissants même si les offsets se répètent. Le découpage dépend de la taille du journal. ntfs3 le calcule ainsi : file_data_bits = log2(taille_journal) − 3 et seq_bits = 64 − file_data_bits :
| Taille du journal | file_data_bits | seq_bits |
|---|---|---|
| 256 Kio (l'exemple synthétique du site) | 15 | 49 |
| 64 Mio (taille courante) | 23 | 41 |
Lisez toujours seq_bits dans la zone de redémarrage plutôt que de le calculer.
Du LSN à l'offset dans le fichier
offset = (LSN << seq_bits) >> (seq_bits - 3)
Le décalage à gauche supprime le numéro de séquence ; le décalage à droite de seq_bits − 3 ramène le champ d'offset et le multiplie par 8. dfir.ru donne un exemple chiffré : avec 44 bits de séquence, le LSN 2124332 a pour numéro de séquence 2 et pour offset 27180 unités de huit octets, soit l'octet 217440.
Un parseur robuste peut s'en servir à l'envers. Au lieu de suivre les chaînes de pages, il parcourt chaque page RCRD à la recherche d'en-têtes alignés sur 8 octets dont le LSN correspond exactement à leur propre offset. Ce contrôle écarte les octets aléatoires et continue de fonctionner quand des pages intermédiaires sont endommagées — c'est ainsi que le parseur de $LogFile dans le navigateur trouve les enregistrements. Les enregistrements qui ne tiennent pas dans le reste d'une page se poursuivent après l'en-tête de la page suivante (et reviennent de la fin du fichier au début de la zone circulaire) ; une page de continuation plus ancienne que l'enregistrement signifie que la suite a été écrasée, et l'enregistrement est marqué incomplet.
Les LSN hors du $LogFile
- Chaque enregistrement FILE du
$MFTstocke, à l'offset0x08de son en-tête, le LSN de la dernière modification journalisée de cet enregistrement — l'un des liens de la TriForce NTFS de David Cowen. Si ce LSN est dans la plage actuelle du journal, la modification qui a produit l'enregistrement FILE courant s'y trouve encore. - Les tampons d'index (
INDX) portent eux aussi un LSN dans leur en-tête.
Comparer le LSN d'un enregistrement $MFT au plus petit LSN du journal indique immédiatement si sa dernière modification est encore retrouvable.
Ce que disent les chiffres en pratique
| Observation | Signification |
|---|---|
| Plus petit LSN ≈ plus grand LSN | Très peu d'historique (journal récemment redimensionné, ou activité intense) |
La page de redémarrage est CHKD | chkdsk a travaillé sur ce journal |
| LSN courant de la zone de redémarrage > plus grand LSN trouvé | Page la plus récente manquante : vérifiez les pages de queue / rapides, ou la copie est périmée |
| Taille du journal dans la zone de redémarrage > taille du fichier | Copie tronquée |
| « Démonté proprement » sur une capture présentée comme faite à chaud | Vérifiez les notes de collecte : le fichier provient peut-être d'une image ou d'un cliché |
Questions fréquentes
Qu'est-ce qu'un LSN dans NTFS ?
Un numéro de séquence de journal est un identifiant de 64 bits attribué à chaque enregistrement du $LogFile. Ses bits de poids faible codent la position de l'enregistrement dans le fichier, en unités de 8 octets, et ses bits de poids fort un numéro de séquence qui augmente à chaque rebouclage du journal : les LSN sont donc toujours croissants.
Comment convertir un LSN du $LogFile en offset dans le fichier ?
Lisez le nombre de bits de séquence dans la zone de redémarrage, puis calculez (LSN << seq_bits) >> (seq_bits - 3). On garde ainsi les 64 - seq_bits bits de poids faible, multipliés par 8, ce qui donne l'offset en octets de l'en-tête de l'enregistrement dans le fichier.
Pour aller plus loin
- Noyau Linux,
fs/ntfs3/fslog.c—RESTART_HDR,RESTART_AREA,CLIENT_REC,NTFS_RESTART,lsn_to_vbo. - Maxim Suhanov, How the $LogFile works?