Skip to content

Directory Indexes ($I30)

What $I30 is

Every NTFS directory keeps an index of the files in it, named $I30. A small directory keeps it in its $MFT record ($INDEX_ROOT); a larger one also has INDX records, usually 4,096 bytes each, in an $INDEX_ALLOCATION:$I30 stream. Each index entry holds a copy of the file's $FILE_NAME: its name, MFT reference, parent directory, four timestamps, and two sizes, as of the last time NTFS updated the entry.

When a file is deleted or renamed out of a directory, NTFS removes its entry and moves the entries after it. The old bytes stay in the slack of the INDX record, past the entries in use, until later entries write over them. Index slack can keep the name, times, and size of a file whose $MFT record was reused and whose USN Journal records have rolled over.

Best conclusion: a name found in index slack was, at some time, in this directory's index with the stated $FILE_NAME times and sizes. A slack entry does not say when it was removed, or whether it was deleted, renamed, or moved by rebalancing.

Location and collection

C:\<directory>:$I30:$INDEX_ALLOCATION

$I30 is NTFS metadata: collect it with a raw-aware forensic tool that can export a directory's $I30 stream (exported files are often named $I30). Juntei can also search a disk image or unallocated space for INDX records. Collect the same volume's $MFT and $J too, to tell what the slack entries were.

Analyst cautions

  • Index slack is partial and unordered. Entries are overwritten as the directory changes; a missing name proves nothing.
  • Many slack entries are copies of entries still in use, left when entries move. CopyOfEntryInUse marks them. The same deleted name can also be in slack several times.
  • The times in an index entry are $FILE_NAME times as of the entry's last update. They can differ from both the $STANDARD_INFORMATION and the $FILE_NAME times of the file's $MFT record.
  • AllocatedSize and RealSize are also as of the entry's last update, and can be stale.
  • A slack entry's FileEntry (or ParentEntry) can be missing when later bytes wrote over it. When present, the MFT record it names may since have been reused: compare the sequence number.
  • parse-ntfs i30 reads INDX records. A small directory's index is only in its $MFT record ($INDEX_ROOT); its files are in the $MFT.

Parse with Juntei

Usage: juntei parse-ntfs i30 <INPUT> [OPTIONS]

Input:
  -d, --directory <DIR>  Recursively find $I30 files (with $I30 in their name, or starting with an INDX record)
  -f, --file <FILE>      Parse one $I30 stream, or any file holding INDX records (a disk image, unallocated space)

Filtering:
      --slack-only  Only the entries found in slack
      --no-copies   Leave out the slack entries that copy an entry in use

Output:
  -o, --output <FILE>       Save every entry
  -t, --output-type <TYPE>  csv, json, or jsonl
juntei parse-ntfs i30 -f 'Users_$I30'
juntei parse-ntfs i30 -d evidence/ -o i30.csv
juntei parse-ntfs i30 -f 'Users_$I30' --slack-only --no-copies -t jsonl
juntei parse-ntfs i30 -f disk.raw -o carved-i30.csv

The summary lists the INDX records (and how many were written in part), the entries in use and in slack, and the names of the slack entries that are not exact copies of entries in use. Those names are candidates for deleted or renamed files, not a verdict by themselves.

CSV output fields

Field Interpretation
SourcePath Input file; distinguishes hosts and directories.
RecordOffset, EntryOffset Byte offsets of the INDX record and of the entry in the input. Essential for validation and for records found in disk images.
RecordVCN, RecordLSN The record's position in the index stream and its $LogFile sequence number.
FromSlack True for an entry found past the entries in use.
CopyOfEntryInUse Slack entry with the same name, namespace, file (when known), parent, and times as an entry in use of the same directory index. Usually a leftover from moving entries, not a deleted file.
Filename The name in the directory.
Namespace win32, dos (8.3 short name), win32_and_dos, or posix.
FileEntry, FileSequence The file's MFT reference. Empty for a slack entry whose header was written over.
ParentEntry, ParentSequence The directory's MFT reference. Empty when other bytes were written over it.
CreatedUTC, ModifiedUTC, MFT-ModifiedUTC, AccessedUTC $FILE_NAME times, to 100 ns, as of the entry's last update.
AllocatedSize, RealSize Sizes NTFS copied into the entry; see the cautions above.
FileAttributes Attribute names joined by | (hidden|archive); is_directory for a subdirectory. Bits this Juntei version does not name are retained in hexadecimal (0x00800000).
ReparseValue Reparse tag or extended-attribute size from $FILE_NAME.
Problems Damage in the record, such as sectors written in part. Entries from a damaged record still deserve review, with care.

JSON/JSONL have the same fields in snake_case, with problems as a list and null for unknown values.

How slack entries are found

The slack is scanned at every 8-byte boundary, where entries start, for whole entries, for $FILE_NAME attributes whose entry header was written over, and, at the start of the slack, for a $FILE_NAME whose parent reference the end of the entries in use wrote over. A candidate must look like what Windows writes: a valid UTF-16 name without control characters or path separators, four times between 1980 and 2100, a known namespace, and known attribute flags. A parent reference past 32 bits is bytes written over it and is left empty.

Each record's update sequence array is applied. A sector that doesn't end with the update sequence value was written in part; Juntei reads the record as it is and names the sectors in Problems.

Investigation strategy

  1. Start with the summary's non-copy names in slack, then filter with --slack-only --no-copies.
  2. Look the FileEntry up in the $MFT. The same FileSequence means the same file; a higher one means the record was freed since, and perhaps reused.
  3. Search the USN Journal for the name to learn when it was deleted or renamed.
  4. Compare $FILE_NAME times with the $MFT's $STANDARD_INFORMATION times for timestomping.
  5. Correlate with Prefetch, LNK, Jump Lists, and event logs for how the file was used.

Further Details