$MFT tells you what the filesystem looks like right now. It does not tell you the order of operations that produced this state. For that NTFS keeps a second artifact, the Update Sequence Number Journal, called $UsnJrnl. Pair the two and a static snapshot becomes a movie. Read the dedicated USN parser site for the journal-specific deep dive; this post is about why you read it together with the MFT and what the combination shows that neither does alone.
What $UsnJrnl records
Every time a file is created, modified, renamed, or deleted, NTFS appends a fixed-size record to the journal describing the event. The fields on each USN record:
- USN: a monotonically increasing 64-bit counter. The position in the journal.
- MFT record number of the changed file.
- Sequence number of that record at the time of the change.
- Parent directory's MFT record number (and sequence).
- Reason mask: bitwise OR of the operations that triggered this entry. The full list is in Microsoft's USN reason codes. The ones you read most:
FILE_CREATE(0x00000100)FILE_DELETE(0x00000200)DATA_OVERWRITE(0x00000001)DATA_EXTEND(0x00000002)DATA_TRUNCATION(0x00000004)RENAME_OLD_NAME(0x00001000)RENAME_NEW_NAME(0x00002000)OBJECT_ID_CHANGE(0x00080000)REPARSE_POINT_CHANGE(0x00100000)STREAM_CHANGE(0x00200000)CLOSE(0x80000000)
- Source info: bitmask indicating special-case sources (data management, indexing, replication). Usually zero.
- Security ID.
- File name at the time of the change.
- Timestamp of the change.
CLOSE is the bit you should know. Most USN entries have it set, indicating the file handle was closed when the event was recorded. Entries without CLOSE are still-open handles whose changes were flushed; you may see follow-on entries for the same record with the final CLOSE later. The pattern matters for ransomware analysis: a FILE_CREATE | DATA_EXTEND | CLOSE on a .locked file paired with a FILE_DELETE | CLOSE on the original is the encryption pattern in one journal sequence.
Where it lives
$UsnJrnl is a regular NTFS file with its data in the named data stream $J. The MFT record for it sits under the $Extend directory (MFT record 11 is $Extend). The path from the volume root is \$Extend\$UsnJrnl:$J. There is also a small $Max stream holding the journal configuration (maximum size, allocation delta, USN of the first valid entry).
You acquire it with the same tools that grab $MFT:
- KAPE's
MFTtarget includes$UsnJrnl:$Jautomatically. - FTK Imager can export it via
[NTFS volume]/$Extend/$UsnJrnl:$J. The file is sparse; do not be surprised when the "size" is huge and the actual content is much smaller. - Sleuth Kit on a disk image:
icat -o <partition_offset> image.dd <inode>where the inode is the$UsnJrnlMFT record number.fls -pfinds the inode. mft_dumpand MFTECmd both have$Jparsing modes.
How it complements $MFT
The MFT shows you the present state. The USN journal shows you the verbs that produced it. Pair them and patterns emerge that neither shows alone:
- Files that no longer exist on disk but appear in
$UsnJrnl. Created and deleted between snapshots, but the journal preserved the record. The MFT slot may even have been reused since; the USN entry still names the file and points at the original record/sequence. - The exact order of renames during a ransomware run.
OPEN,DATA_OVERWRITE,RENAME_OLD_NAME,RENAME_NEW_NAME,CLOSE. The MFT diff between snapshots tells you the file moved; the journal tells you the order it moved in. - Whether a "modified" file was actually rewritten or just touched.
DATA_OVERWRITEmeans content changed. A metadata-only change (ACL update, attribute set) shows different reason flags and no data-related ones. - What process group wrote which file. The journal does not record the process directly, but combined with Sysmon Event ID 11 (file create) and Event ID 23 (file delete) timestamps, you can almost always attribute journal entries to specific processes.
The merge workflow
The way I merge MFT and USN data for timelining:
- Parse
$MFTto a flat row-per-record CSV (MFTECmd,mft_dump -o csv, or the browser parser export). - Parse
$UsnJrnl:$Jto a flat row-per-event CSV. - Add a
sourcecolumn to each (MFTandUSN). - Concatenate and sort by timestamp.
- Pivot to records that match the case (specific record numbers, specific filenames, specific parent directories).
- Read the timeline as prose: for each record number, list the events in order.
The output for a single file looks like:
2026-05-15T10:23:01.123Z USN FILE_CREATE | DATA_EXTEND | CLOSE rec=12345 seq=3 parent=99 name=secret.docx
2026-05-15T10:23:01.123Z MFT IN_USE=1 SI_created=10:23:01.123Z FN_created=10:23:01.123Z
2026-05-15T10:24:18.456Z USN DATA_OVERWRITE | CLOSE rec=12345 seq=3 name=secret.docx
2026-05-15T10:24:18.456Z MFT SI_modified=10:24:18.456Z
2026-05-16T08:11:02.000Z USN RENAME_OLD_NAME rec=12345 seq=3 name=secret.docx
2026-05-16T08:11:02.000Z USN RENAME_NEW_NAME | CLOSE rec=12345 seq=3 name=secret.docx.locked
2026-05-16T08:11:02.001Z USN FILE_DELETE | CLOSE rec=12345 seq=3 name=secret.docx.locked
That sequence is the entire life of the file. Created, modified, renamed (to add the .locked extension), deleted. Five operations, one file, less than 24 hours.
Limits and pitfalls
The journal rotates. Default size is 32 MB on most installations, sometimes larger on Server SKUs and recent Windows 11 builds. On a busy host that fits a few days. Older events fall off the end as new ones come in. Arrive a week after an incident and expect gaps.
The journal can be deleted. fsutil usn deletejournal /D C: removes it entirely. A new one starts with a fresh counter. The recreation leaves footprints (see NTFS anti-forensics) but the historical entries are gone.
Wrap-around looks like a normal rotation. The first USN you see in a captured $J is wherever the journal happened to start at that moment. There is no "this is what was here last week" history. If you want a longer window, look for older $UsnJrnl copies in VSS snapshots; each snapshot has its own journal copy at the time of the snapshot.
Timestamps drift from MFT timestamps by milliseconds. Do not over-index on alignment. Sort to the second and use the USN reason codes as the tiebreaker.
Record number reuse. A USN entry references rec=12345 seq=3. If the current MFT shows that record at sequence 4, the slot has been reused since. The USN entry still names the original file; the current MFT shows the successor. Always cross-check sequence numbers.
Driver minifilters can suppress entries. Some EDR and backup software suppresses certain USN reasons to reduce noise. The journal does not record these. If your USN data looks sparse for a category of operation that should be frequent (file access, for instance), check what minifilters are installed.
$LogFile, briefly
$LogFile records transaction-level operations: allocate this attribute, deallocate that one, update this index entry. Granular but lower-level than USN. Useful in the seconds immediately around a crash or a metadata-heavy event. MFTECmd parses it; nothing else common does. If you have a tampered USN journal, $LogFile is sometimes the only remaining record of what actually happened.
A workflow that holds up
- Always acquire
$MFT,$UsnJrnl:$J,$LogFile, and VSS-snapshot copies of all three together. - Hash everything (SHA-256) immediately.
- Parse all three.
- Merge MFT and USN into a single timeline. Layer
$LogFileon top for the seconds around any event of interest. - Cross-reference with Sysmon, Security event logs, Prefetch, Amcache.
- Document what you ruled out as well as what you concluded.
The MFT-plus-USN pair is the closest thing NTFS gives you to a complete filesystem activity log. Treat it that way.
Further reading
- Microsoft, USN Record Structures. Authoritative reference for record format and reason codes.
- Eric Zimmerman, MFTECmd USN parsing modes. The most complete parser, includes resilience for partial/wrapped journals.
- TZWorks
jpand the usnparser.com browser tool for alternative parsers when MFTECmd is not available.