Windows.Carving.USNFiles

The USN journal is an important source of information about when files were manipulated on a system.

Ideally you can parse the journal directly using the Windows.Forensics.Usn artifact on the endpoint itself. However, sometimes all you have is a copy of the USN file itself (for example after collection with the Windows.KapeFiles.Targets). If you only have the file, you can use this artifact to parse the USN records out of it by essentially carving the records out.

NOTE: This artifact is not as good as the Windows.Forensics.Usn artifact because it can not resolve the full path of the files from the MFT itself! In practice you should always prefer to collect Windows.Forensics.Usn rather than just the $J file.


name: Windows.Carving.USNFiles
description: |
  The USN journal is an important source of information about when
  files were manipulated on a system.

  Ideally you can parse the journal directly using the
  `Windows.Forensics.Usn` artifact on the endpoint itself. However,
  sometimes all you have is a copy of the USN file itself (for example
  after collection with the `Windows.KapeFiles.Targets`). If you only
  have the file, you can use this artifact to parse the USN records
  out of it by essentially carving the records out.

  NOTE: This artifact is not as good as the `Windows.Forensics.Usn`
  artifact because it can not resolve the full path of the files from
  the MFT itself! In practice you should always prefer to collect
  `Windows.Forensics.Usn` rather than just the $J file.

imports:
  - Windows.Carving.USN

parameters:
  - name: USNFile
    default: \\.\C:\$Extend\$UsnJrnl:$J
  - name: Accessor
    default: ntfs
    type: choices
    choices:
      - ntfs
      - file
  - name: FileRegex
    description: "Regex search over File Name"
    default: "."
    type: regex
  - name: DateAfter
    type: timestamp
    description: "search for events after this date. YYYY-MM-DDTmm:hh:ssZ"
  - name: DateBefore
    type: timestamp
    description: "search for events before this date. YYYY-MM-DDTmm:hh:ssZ"

sources:
  - query: |
        -- firstly set timebounds for performance
        LET DateAfterTime <= if(condition=DateAfter,
             then=DateAfter, else="1600-01-01")
        LET DateBeforeTime <= if(condition=DateBefore,
            then=DateBefore, else="2200-01-01")

        -- This rule performs an initial reduction for speed, then we
        -- reduce further using other conditions.
        LET USNYaraRule = '''rule X {
            strings:
              // First byte is the record length < 255 second byte should be 0-1 (0-512 bytes per record)
              // Version Major and Minor must be 2 and 0
              // D7 01 is the ending of a reasonable WinFileTime
              // Name Offset and Name Length are short ints but should be < 255
              $a = { ?? (00 | 01) 00 00 02 00 00 00 [24] ?? ?? ?? ?? ?? ?? D? 01 [16] ?? 00 3c 00  }
            condition:
              any of them
        }
        '''

        -- Find all the records in the drive.
        LET Hits = SELECT String.Offset AS Offset, parse_binary(
           filename=USNFile, accessor=Accessor, struct="USN_RECORD_V2",
           profile=USNProfile, offset=String.Offset) AS _Parsed
        FROM yara(files=USNFile, accessor=Accessor,
                  rules=USNYaraRule, number=200000000)
        WHERE _Parsed.RecordLength > 60 AND  // Record must be at least 60 bytes
              _Parsed.FileNameLength > 3 AND _Parsed.FileNameLength < 100

        SELECT Offset, _Parsed.TimeStamp AS TimeStamp,
               _Parsed.Filename AS Name,
               _Parsed.FileReferenceNumberID AS MFTId,
               _Parsed.ParentFileReferenceNumberID AS ParentMFTId,
               _Parsed.Reason AS Reason
        FROM Hits
        WHERE Name =~ FileRegex AND
              TimeStamp < DateBeforeTime AND
              TimeStamp > DateAfterTime