How to extract $UsnJrnl:$J from a disk image (or a live system)

A practical guide to pulling the NTFS USN Journal out of a forensic image, a mounted volume, or a live Windows host — with FTK Imager, X-Ways, The Sleuth Kit, fsutil, and PowerShell.

By 6 min read

The hardest part of working with the USN journal is usually not parsing it. It is laying hands on the file in the first place. $UsnJrnl:$J is an alternate data stream, not a regular file, so it does not show up in Explorer, it does not survive a naive copy, and robocopy will silently lie to you about having pulled it. This is the field guide for actually getting the bytes off disk, broken down by the three places you typically meet them: a forensic image, a mounted volume, and a live machine.

What you are looking for

The journal lives at:

\$Extend\$UsnJrnl:$J

$Extend is a hidden NTFS metadata directory and $J is one of two alternate streams on the $UsnJrnl metadata file. The other stream is $Max, which only holds the journal's configured maximum size and allocation delta — no records. If you mistakenly carve $Max you get a few bytes of useless config. Always pick $J.

Microsoft documents the layout in the Change Journals reference and the USN_RECORD_V2 structure reference. A typical $J is 30 MB to several GB depending on how fsutil usn was configured at install time. The default on Windows clients is around 32 MB; servers are often sized at 1 GB or more.

While you are pulling $J, also pull $MFT from the same volume. Without it, the parser can only show you leaf filenames — every record is bound to a parent MFT entry number, not a path. With both files you get full paths for free.

From a forensic disk image (E01, dd, AFF4)

The most common case in DFIR. Pick the tool you already have a licence for.

FTK Imager (free, GUI)

  1. File → Add Evidence Item, open the image.
  2. Drill into [root]/$Extend/$UsnJrnl.
  3. The pane shows $J and $Max as sibling rows. Right-click $J and pick Export Files.

The "sibling row" detail is the part newcomers get wrong: it is easy to right-click the parent file and export the default stream, which is empty. Pick the $J row specifically.

X-Ways Forensics (commercial)

Expand Root directory → $Extend → $UsnJrnl. The $J stream appears underneath. Recover/Copy writes it out. Same path, same gotcha as FTK.

The Sleuth Kit (free, CLI, cross-platform)

What most Mac/Linux analysts reach for. icat from TSK is the standard tool:

# Find the MFT entry for $UsnJrnl
fls -r -p image.dd | grep '\$UsnJrnl'

# Suppose it reports inode 81, and the $J stream is attribute 128-2:
icat image.dd 81-128-2 > UsnJrnl-J.bin

The <inode>-<type>-<id> triple is how TSK addresses alternate streams. Whichever attribute name ends in :$J is the one you want; fls shows that in its long output.

Velociraptor and KAPE

For broad triage collection, Velociraptor's Windows.NTFS.MFT artefact pack and Kroll's KAPE both pull the journal automatically. KAPE uses target files (!ALL or USNJournal); Velociraptor uses the parse_ntfs plugin. Both also grab $MFT and $LogFile in the same sweep, which is what you actually want.

From a mounted volume

If the image is mounted read-only via ntfs-3g on Linux or Arsenal Image Mounter on Windows, the metadata path appears as a regular file but most tools refuse to read alternate streams transparently.

On Linux with ntfs-3g, the stream is readable directly:

sudo cat '/mnt/image/$Extend/$UsnJrnl:$J' > UsnJrnl-J.bin

Depending on the streams_interface mount option, :$J may appear as a separate path component instead. Check ls -la /mnt/image/\$Extend/ first.

From a live Windows host

You need administrative privileges and an NTFS-aware reader, because Windows blocks ordinary access to metadata files even from administrator processes.

RawCopy

Eric Zimmerman's tool suite includes RawCopy.exe (and RawCopy64.exe), which bypasses the standard file API:

RawCopy.exe /FileNamePath:"C:\$Extend\$UsnJrnl:$J" /OutputPath:"D:\Out"

This is what KAPE uses under the hood when its USNJournal target runs.

PowerForensics (pure PowerShell)

If you cannot drop a binary, PowerForensics reads raw NTFS structures in pure PowerShell:

Import-Module PowerForensics
Get-ForensicFileRecord -Path 'C:\$Extend\$UsnJrnl' |
  ForEach-Object { $_.GetContent() } |
  Set-Content -Path 'C:\Out\UsnJrnl-J.bin' -Encoding Byte

Built-in fsutil (verification, not extraction)

fsutil usn is the supported control surface for the journal but it is not an extraction tool. It can read, query and delete records, not stream the full $J blob. What it is useful for is verifying the journal is enabled and sized before you attempt extraction:

fsutil usn queryjournal C:

Status: 0x00000000 with a non-zero Maximum Size means the journal is active. 0x80000005 means it is disabled and there is nothing to extract until it is created via fsutil usn createjournal. See the fsutil usn reference for the lifecycle commands and their privilege requirements.

After extraction

Once you have the $J file, drop it into the parser at the top of this page, or feed it to whichever offline tool you trust: usnrs, PoorBillionaire/USN-Journal-Parser, or Eric Zimmerman's MFTECmd (which parses $J despite the name).

Grab $MFT (entry 0, same $Extend-adjacent location) at the same time. With both files supplied, any of the above parsers walks the parent-reference chain to resolve full paths for every journal record. Without $MFT you are reading filenames in isolation.

While you are acquiring NTFS metadata, grab $LogFile too if you can. It is small, it rotates fast, and on incidents where the journal alone does not stretch back far enough, $LogFile is the backstop. The USN journal vs MFT vs LogFile post covers when each one earns its keep.

Common pitfalls

Explorer copy. Drag-and-drop of $UsnJrnl copies the default unnamed stream, which is empty. You will not get a warning. Use one of the tools above.

Journal disabled. Workgroup machines and aggressively de-bloated builds sometimes have the journal turned off. fsutil usn queryjournal is the cheapest pre-flight check.

Sparse leading zeroes. The journal is a sparse stream. The first few hundred megabytes of a freshly carved $J can be all zeroes before the first real record. usnrs, the parser on this page and most others skip past automatically. If you are writing a parser from scratch, scan for the first non-zero word and look for a plausible RecordLength value.

Ring buffer wrap. Depending on activity, the journal may have wrapped — older entries are gone. The smallest USN in the file tells you how far back the volume's history actually reaches. Treat that as your hard floor.

Mistakenly grabbing $Max. Same parent file, but no records. If your carve produces a tiny file (a few bytes to a few KB), you almost certainly grabbed the wrong stream.

Further reading

  • Microsoft Learn — Change Journals for the API surface and lifecycle.
  • Eric Zimmerman's tool documentation — RawCopy and the rest of the suite cover live-host acquisition end-to-end.
  • The Sleuth Kit's fls and icat man pages — the canonical CLI reference for image-level extraction.
  • KAPE documentation — Kroll publishes target files including USNJournal and !BasicCollection; reading the target XML is the fastest way to learn what a thorough triage acquisition looks like.