← Back to blog

USN Reason Codes — Reading Between the Bits

A field-by-field walkthrough of the USN_RECORD reason bitmask and what each combination tells you about a file's lifecycle on disk.

3 min read

If you spend any time in Windows forensics, the USN reason bitmask is going to become muscle memory. It is a 32-bit field that NTFS sets on every journal record to summarise what just changed about a file. The bits don't tell you everything — they're additive, not exclusive — but read together they give you a remarkably precise picture of file lifecycle.

The bits

FlagHexWhat it means in practice
DataOverwrite0x00000001A region of the main data stream was overwritten
DataExtend0x00000002The main data stream grew
DataTruncation0x00000004The main data stream shrank
NamedDataOverwrite / Extend / Truncation0x10 / 0x20 / 0x40Same, but on an alternate data stream
FileCreate0x00000100A new file or directory was created
FileDelete0x00000200The file was deleted from the namespace
EaChange0x00000400Extended attributes changed
SecurityChange0x00000800ACLs/owner changed
RenameOldName0x00001000The "before" half of a rename
RenameNewName0x00002000The "after" half of a rename
IndexableChange0x00004000Indexed flag toggled
BasicInfoChange0x00008000Timestamps, attributes, or compression changed
HardLinkChange0x00010000A hard link was added or removed
CompressionChange0x00020000NTFS compression was toggled
EncryptionChange0x00040000EFS state changed
ObjectIdChange0x00080000Object ID set or cleared
ReparsePointChange0x00100000Reparse point added/changed/removed
StreamChange0x00200000An alternate data stream was added/renamed/deleted
Close0x80000000The handle that produced the change has been closed

Close is special: NTFS coalesces successive operations under the same handle, and only emits a final record with Close set once the handle is gone. If you see a record without Close, you're looking at the system flushing intermediate state — useful, but the "Close" record is the authoritative summary.

Patterns you'll see in the wild

A handful of patterns occur so often that you should recognise them instantly:

  • New file written by an app. FileCreate | DataExtendDataExtend | CloseBasicInfoChange | Close. The last one is the file getting its mtime stamped on close.
  • Rename across directories. Two records on the same FileReferenceNumber: RenameOldName | Close then RenameNewName | Close. The parent reference differs between the two — that's how you reconstruct the move.
  • Atomic save-by-rename. Many editors write to a temp file, then rename it onto the target. You see FileCreate on the temp, FileDelete | Close on the original, and RenameNewName | Close on the temp.
  • Ransomware encrypt-then-rename. DataOverwrite records covering megabytes, followed by RenameNewName | Close with the new extension. The DataOverwrite count and timing are often where you first notice a sample on disk.
  • Antivirus quarantine. FileDelete | Close immediately following a recent FileCreate, all under the same MFT entry. The journal gives you the smoking gun that AV touched the file even after the file itself is gone.

What the bits won't tell you

The reason bitmask is about the file, not about the actor. There is no user, no process ID, no command line. Combine the journal with Security.evtx (4663 object access) or with Microsoft-Windows-Sysmon/Operational events to attach an actor to each operation. The USN gives you the when and what; other logs give you the who.

A practical reading recipe

When you open a parsed journal:

  1. Filter for FileCreate to see what is genuinely new in the time window.
  2. Look for RenameNewName to catch movement and "save-as" patterns.
  3. Plot DataExtend count over time — bulk writes (backups, encryption, exfil staging) jump out.
  4. Always read records with Close set first; treat intermediates as supporting evidence.

The web app on this site lets you filter by any combination of reasons, which makes step 1–3 a one-click exercise.