File system · Lezione 4 di 8
File di metadati NTFS: $LogFile, $UsnJrnl e flussi di dati alternativi
12 min di lettura
La lezione 1.3 ha mostrato come la $MFT descrive ogni file nel suo stato attuale. Questa lezione tratta tre funzionalità di NTFS che registrano ciò che è accaduto in precedenza o contengono dati che sfuggono a un esame superficiale: il registro delle transazioni $LogFile, il diario delle modifiche USN e i flussi di dati alternativi. Grazie a queste funzionalità, un esaminatore può dimostrare che un file è stato creato, rinominato o eliminato anche dopo la sua scomparsa e individuare dati nascosti accanto a un file ordinario.
$LogFile: il registro delle transazioni
$LogFile corrisponde al record 2 della MFT. NTFS è un file system con journaling: prima di modificare i propri metadati (record della MFT, indici delle directory, bitmap di allocazione), scrive un record di registro che descrive la modifica. Se il sistema si arresta in modo anomalo durante l'operazione, al montaggio successivo Windows riapplica o annulla questi record per mantenere coerenti i metadati. $LogFile protegge solo i metadati; non conserva copie del contenuto dei file scritto negli attributi $DATA non residenti.
Struttura
- Area di riavvio. Le prime due pagine da 4.096 byte contengono la firma
RSTR. Sono due copie dell'area di riavvio, che registra la posizione corrente nel registro e il punto da cui deve iniziare il ripristino. - Pagine dei record di registro. Il resto del file è costituito da pagine con la firma
RCRD. Ogni record di registro contiene un numero di sequenza del registro (LSN), un ID di transazione, un'operazione di redo (come applicare la modifica) e un'operazione di undo (come annullarla), oltre ai byte interessati. Tra i nomi delle operazioni figuranoInitializeFileRecordSegment,DeallocateFileRecordSegment,AddIndexEntryAllocation,DeleteIndexEntryAllocationeUpdateResidentValue. - Collegamento alla MFT. L'intestazione di ogni record della MFT contiene, all'offset 0x08, l'LSN dell'ultima modifica registrata per quel record, consentendo agli strumenti di associare i record di registro ai record della MFT.
Il registro è circolare e viene riutilizzato continuamente. Per impostazione predefinita, la sua dimensione è di alcune decine di MB; occorre leggere la dimensione effettiva dall'attributo $DATA del record 2 della MFT anziché presumerla. Su un disco di sistema molto attivo, questo spazio copre soltanto un intervallo compreso tra pochi minuti e alcune ore di attività; su un volume poco utilizzato può risalire più indietro.
Che cosa può rivelare
Poiché i dati di redo e undo contengono i byte effettivi dei metadati, $LogFile può mostrare creazioni, ridenominazioni ed eliminazioni recenti di file, inclusi nomi precedenti e nuovi, voci di indice rimosse da una directory e dati residenti o valori di $STANDARD_INFORMATION prima e dopo una modifica (utili quando i timestamp sono stati alterati). I record di registro non hanno un proprio campo temporale: gli orari provengono dai timestamp presenti nei dati degli attributi registrati oppure dalla correlazione con il diario USN. Esempi di parser sono LogFileParser e NTFS Log Tracker; il secondo correla $LogFile con $UsnJrnl.
Il diario delle modifiche USN
Il diario USN (update sequence number, numero di sequenza degli aggiornamenti) registra le modifiche a file e directory affinché i software di backup e indicizzazione possano individuare ciò che è cambiato. Windows lo abilita per impostazione predefinita sul volume di sistema. Si trova in $Extend\$UsnJrnl (il numero di record della MFT di $UsnJrnl non è fisso, a differenza di quello di $LogFile) e contiene due flussi $DATA con nome:
| Flusso | Contenuto |
|---|---|
$J | I record delle modifiche, aggiunti uno dopo l'altro |
$Max | Impostazioni del diario: dimensione massima, incremento di allocazione e ID del diario |
L'USN di un record è il suo offset in byte all'interno di $J. Quando il diario supera la dimensione massima, NTFS dealloca la parte più vecchia di $J e la rende sparsa (un intervallo privo di cluster sottostanti che viene letto come una sequenza di zeri). La dimensione logica di $J può quindi indicare diversi GB, mentre solo le decine di MB più recenti contengono record. fsutil usn queryjournal C: su un sistema in esecuzione mostra i valori configurati; sui volumi di sistema di Windows 10 e 11 il massimo è comunemente pari a 32 MB.
Quanto indietro risale il diario dipende dall'attività e dalla dimensione massima: spesso da giorni a settimane su una workstation, talvolta solo poche ore su un server molto attivo. I record più vecchi possono sopravvivere nello spazio non allocato e nelle copie shadow del volume. Sulle unità NTFS rimovibili il diario è spesso assente, a meno che non sia stato abilitato da un software o da fsutil usn createjournal; FAT32 ed exFAT (lezione 1.5) non dispongono di alcun diario.
USN_RECORD_V2
La maggior parte dei record su NTFS è di versione 2 (la versione 3 utilizza ID di file a 128 bit e compare principalmente su ReFS). Tutti gli interi sono in formato little-endian.
| Offset | Dimensione | Campo |
|---|---|---|
| 0x00 | 4 | Lunghezza del record (multiplo di 8) |
| 0x04 | 2 + 2 | Versione principale (2), versione secondaria (0) |
| 0x08 | 8 | Numero di riferimento del file (voce della MFT di 6 byte + sequenza di 2 byte) |
| 0x10 | 8 | Numero di riferimento del file padre |
| 0x18 | 8 | USN |
| 0x20 | 8 | Timestamp (FILETIME, UTC, momento in cui il record è stato scritto) |
| 0x28 | 4 | Flag del motivo |
| 0x2C | 4 | Informazioni sull'origine (diverse da zero per le modifiche apportate da servizi di sistema quali la replica) |
| 0x30 | 4 | ID di sicurezza |
| 0x34 | 4 | Attributi del file (ad es. 0x20 archivio, 0x10 directory) |
| 0x38 | 2 + 2 | Lunghezza del nome del file in byte, offset del nome del file (normalmente 0x3C) |
| 0x3C | var. | Nome del file, UTF-16LE, senza percorso |
Flag del motivo comuni:
| Flag | Valore | Significato |
|---|---|---|
| DATA_OVERWRITE | 0x00000001 | I dati nel flusso senza nome sono stati sovrascritti |
| DATA_EXTEND | 0x00000002 | Il flusso senza nome è aumentato di dimensione |
| DATA_TRUNCATION | 0x00000004 | Il flusso senza nome è diminuito di dimensione |
| FILE_CREATE | 0x00000100 | File o directory creato |
| FILE_DELETE | 0x00000200 | File o directory eliminato |
| RENAME_OLD_NAME | 0x00001000 | Il record contiene il nome precedente a una ridenominazione o a uno spostamento |
| RENAME_NEW_NAME | 0x00002000 | Il record contiene il nome successivo a una ridenominazione o a uno spostamento |
| BASIC_INFO_CHANGE | 0x00008000 | Attributi o timestamp modificati |
| STREAM_CHANGE | 0x00200000 | Un flusso con nome è stato aggiunto, rimosso o rinominato |
| CLOSE | 0x80000000 | Ultimo handle chiuso; conclude questo insieme di modifiche |
Come una singola operazione genera più record
I flag del motivo si accumulano. Mentre un file è aperto, ogni nuovo tipo di modifica genera un record il cui motivo è l'OR di tutto ciò che è stato rilevato fino a quel momento e, quando l'ultimo handle viene chiuso, NTFS scrive un record finale con l'aggiunta di CLOSE. Quindi, la creazione e la scrittura di un file producono FILE_CREATE, poi FILE_CREATE | DATA_EXTEND, quindi FILE_CREATE | DATA_EXTEND | CLOSE. Il record CLOSE va letto come il riepilogo dell'intera operazione.
Due avvertenze. «Elimina» in Esplora file normalmente sposta il file in $Recycle.Bin, operazione che appare come record RENAME_OLD_NAME / RENAME_NEW_NAME (con il nuovo nome che inizia con $R), non come FILE_DELETE; FILE_DELETE compare in caso di eliminazione definitiva, svuotamento del Cestino o eliminazione eseguita da un programma. Inoltre, un record dimostra che una modifica è avvenuta, non chi l'abbia effettuata o perché.
Ricostruzione dei percorsi completi
Un record contiene soltanto il nome del file e il numero di riferimento del file padre. Per ricostruire il percorso, si suddivide il riferimento al padre in voce della MFT (i 6 byte meno significativi) e numero di sequenza (i 2 byte più significativi), si cerca tale voce nella $MFT, se ne ricava il nome e si ripete l'operazione con il relativo padre fino a raggiungere la voce 5, la directory radice. Se il numero di sequenza nella $MFT differisce da quello nel record, la voce è stata liberata o riutilizzata e il percorso non è affidabile. La $MFT mostra i nomi attuali delle cartelle; i record di ridenominazione di una cartella mostrano quelli precedenti. MFTECmd, ad esempio, analizza $J esportandolo in CSV e risolve una colonna ParentPath quando la $MFT viene fornita con -m.
Flussi di dati alternativi
Ogni file NTFS contiene un attributo $DATA senza nome (tipo 0x80, lunghezza del nome 0): è il contenuto visibile quando si apre il file. Un file o una directory può contenere anche un numero qualsiasi di attributi $DATA con nome, chiamati flussi di dati alternativi (ADS). Ciascuno è un attributo $DATA separato nello stesso record della MFT, con il nome del flusso memorizzato nell'intestazione dell'attributo; un flusso piccolo è residente all'interno del record, mentre uno più grande dispone delle proprie sequenze di cluster. La sintassi è file.txt:stream oppure, nella forma completa, file.txt:stream:$DATA. La dimensione mostrata da Esplora file è soltanto quella del flusso senza nome.
Zone.Identifier
Quando un browser o un client di posta salva su Windows un file proveniente da Internet, aggiunge un flusso denominato Zone.Identifier con testo come [ZoneTransfer], ZoneId=3, ReferrerUrl=… e HostUrl=…. ZoneId 3 indica l'area Internet (0 computer locale, 1 Intranet locale, 2 siti attendibili, 4 siti con restrizioni). I browser recenti basati su Chromium, come Chrome ed Edge su Windows 10 e 11, aggiungono i campi ReferrerUrl e HostUrl; HostUrl è l'URL di download. Altri programmi possono scrivere soltanto la riga ZoneId. Si tratta di una prova diretta della provenienza, ma alcuni strumenti di download e di estrazione degli archivi non lo creano né lo propagano.
Occultamento e perdita dei dati
È possibile scrivere qualsiasi contenuto in un flusso, ad esempio con type secret.zip > notes.txt:x.zip, senza che la dimensione del file visibile cambi; alcuni malware hanno memorizzato payload in questo modo. Gli ADS esistono soltanto su NTFS (e ReFS): copiare un file su FAT32 o exFAT, allegarlo a un messaggio di posta elettronica o caricarlo online elimina tutti i flussi con nome, quindi la loro assenza sui supporti rimovibili non dimostra nulla riguardo all'originale.
Rilevamento dei flussi
dir /relenca i flussi nella formanotes.txt:x.zip:$DATA.- Il comando PowerShell
Get-Item .\notes.txt -Stream *elenca ciascun flusso e la relativa lunghezza. - In un'immagine, l'output di MFTECmd contrassegna i file che contengono flussi (
HasAds) e assegna a ciascun flusso una riga distinta (IsAds), riportando il testo residente di Zone.Identifier inZoneIdContents. L'aggiunta di un flusso genera anche record USN con STREAM_CHANGE.
Esempio svolto: un file nel diario USN
Il $J di un disco di sistema Windows 11 contiene questi record (i record di altri file intercalati tra essi sono omessi, motivo per cui gli USN presentano dei salti). Tutti hanno il riferimento al file 0x0005000000012A3F e il riferimento al padre 0x0003000000009C40.
| USN | Timestamp (UTC) | Motivo | Nome |
|---|---|---|---|
| 1476395008 | 2026-03-14T09:21:07.250Z | FILE_CREATE (0x00000100) | draft.txt |
| 1476395088 | 2026-03-14T09:21:07.251Z | FILE_CREATE, DATA_EXTEND (0x00000102) | draft.txt |
| 1476395168 | 2026-03-14T09:21:07.253Z | FILE_CREATE, DATA_EXTEND, CLOSE (0x80000102) | draft.txt |
| 1476421632 | 2026-03-14T09:24:51.008Z | RENAME_OLD_NAME (0x00001000) | draft.txt |
| 1476421712 | 2026-03-14T09:24:51.008Z | RENAME_NEW_NAME (0x00002000) | keys.txt |
| 1476421792 | 2026-03-14T09:24:51.009Z | RENAME_NEW_NAME, CLOSE (0x80002000) | keys.txt |
| 1476444584 | 2026-03-14T09:30:12.115Z | FILE_DELETE, CLOSE (0x80000200) | keys.txt |
Lunghezza del record. draft.txt è composto da 9 caratteri, pari a 18 byte in UTF-16: 60 + 18 = 78, arrotondato per eccesso a un multiplo di 8 = 80 byte. Per questo motivo il record successivo della stessa sequenza ravvicinata si trova a 1476395008 + 80 = 1476395088. keys.txt produce 60 + 16 = 76, con riempimento fino a 80.
Timestamp. Il primo record contiene il valore FILETIME 134179536672500000 (intervalli di 100 ns a partire da 1601-01-01). 134179536672500000 / 10.000.000 = 13.417.953.667,25 s; sottraendo 11.644.473.600 s (dal 1601 al 1970) si ottiene il tempo Unix 1.773.480.067,25 = 2026-03-14T09:21:07.250Z.
Riferimenti. 0x0005000000012A3F: i 6 byte meno significativi, 0x12A3F, corrispondono alla voce 76.351 della MFT; i 2 byte più significativi indicano la sequenza 5. Il padre 0x0003000000009C40 corrisponde alla voce 40.000, sequenza 3. Nella $MFT, la voce 40.000 (sequenza 3) è Desktop, la cui catena di directory padre è ana, Users e la radice; pertanto il percorso completo era C:\Users\ana\Desktop\draft.txt, rinominato nella stessa posizione in keys.txt.
Interpretazione. Il file è stato creato e scritto alle 09:21:07Z, rinominato alle 09:24:51Z ed eliminato definitivamente alle 09:30:12Z, non inviato al Cestino, poiché non compare alcuna ridenominazione verso $Recycle.Bin. La voce 76.351 potrebbe già contenere un altro file con sequenza 6; il diario dimostra comunque il vecchio nome e gli orari. $LogFile può confermare l'eliminazione se copre ancora le 09:30.
Focus sull'esame: Ci si può attendere di dover ricavare un orario, un nome originale o un percorso completo da $J, il che richiede di leggere il record CLOSE di una sequenza ravvicinata, distinguere RENAME_OLD_NAME da RENAME_NEW_NAME e risolvere il riferimento al padre attraverso la $MFT. Potrebbe essere chiesto da dove proviene un file scaricato (HostUrl in Zone.Identifier) oppure quale file contiene un flusso nascosto. Occorre sapere quale artefatto copre ciascun intervallo temporale: $LogFile da minuti a ore, $J generalmente da giorni a settimane.
Punti chiave
- $LogFile (record 2 della MFT) registra le transazioni sui metadati come record di redo/undo dopo un'area di riavvio
RSTR; è piccolo, circolare e copre soltanto l'attività recente. $Extend\$UsnJrnl:$Jcontiene voci USN_RECORD_V2; l'USN è l'offset del record nel flusso sparso$J, mentre$Maxcontiene le impostazioni delle dimensioni.- I flag del motivo si accumulano fino a un record con CLOSE; le ridenominazioni producono un record OLD_NAME e uno NEW_NAME; l'eliminazione da Esplora file è generalmente una ridenominazione verso
$Recycle.Bin. - I percorsi vengono ricostruiti a partire dal riferimento al file padre attraverso la $MFT; occorre verificare il numero di sequenza prima di considerare attendibile il risultato.
- Gli attributi $DATA con nome sono flussi di dati alternativi; Zone.Identifier registra ZoneId, ReferrerUrl e HostUrl e tutti i flussi vanno persi su FAT32/exFAT.