Skip to content

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.

Publié le 8 min de lecture

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 :

OffsetTailleChamp
0x004Signature : RSTR, ou CHKD si chkdsk a modifié le journal
0x042Offset du tableau de séquence de mise à jour
0x062Nombre d'éléments du tableau de séquence
0x088Dernier LSN de chkdsk
0x104Taille de page système
0x144Taille de page du journal
0x182Offset de la zone de redémarrage
0x1A2Version mineure
0x1C2Version 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 :

OffsetTailleChampPourquoi c'est utile
0x008LSN courantLSN le plus récent au moment où cette zone a été écrite
0x082Clients du journalNombre d'emplacements clients (normalement un : NTFS)
0x0A / 0x0C2 + 2Liste des clients libres / utilisés0xFFFF = vide
0x0E2Drapeaux0x1 E/S sur page unique (ntfs3) ; le parseur dans le navigateur lit 0x2 comme « démonté proprement »
0x104Bits du numéro de séquenceNécessaire pour LSN ↔ offset
0x142Longueur de la zone de redémarrage
0x162Offset du tableau des clientsRelatif à la zone de redémarrage
0x188Taille du fichier journalÀ comparer avec votre copie : plus courte = tronquée
0x204Longueur des données du dernier LSN
0x242Longueur de l'en-tête d'enregistrement
0x262Offset des données dans une pageOù commencent les enregistrements dans chaque page RCRD
0x284Compteur d'ouvertures du journal

L'enregistrement client NTFS

Chaque emplacement client fait 0xA0 octets ; NTFS est normalement le seul client :

OffsetChampSignification
0x00LSN le plus ancienPlus ancien enregistrement dont la reprise peut encore avoir besoin
0x08LSN de redémarrage clientLSN du dernier enregistrement de point de contrôle
0x1CLongueur du nom (octets)
0x20NomUTF-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 :

OffsetChamp
0x00 / 0x04Version majeure / mineure du client (0.0 ou 1.0)
0x08LSN de début du point de contrôle
0x10LSN du dump de la table des attributs ouverts
0x18LSN du dump des noms d'attributs
0x20LSN du dump de la table des pages modifiées
0x28LSN du dump de la table des transactions
0x30–0x3CLongueurs 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 journalfile_data_bitsseq_bits
256 Kio (l'exemple synthétique du site)1549
64 Mio (taille courante)2341

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 $MFT stocke, à l'offset 0x08 de 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

ObservationSignification
Plus petit LSN ≈ plus grand LSNTrès peu d'historique (journal récemment redimensionné, ou activité intense)
La page de redémarrage est CHKDchkdsk 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 fichierCopie tronquée
« Démonté proprement » sur une capture présentée comme faite à chaudVé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

Articles liés

Articles liés