In this module
$INDEX_ROOT and $INDEX_ALLOCATION — Directory Analysis
Figure WF1.5 — NTFS directory index structure showing $INDEX_ROOT as the B-tree root and $INDEX_ALLOCATION records as tree nodes. Active entries represent current directory contents. Slack space after the last active entry in each record may contain deleted file entries with filenames, timestamps, and MFT references — forensic evidence of files that were in the directory before deletion.
How NTFS stores directory contents
A directory in NTFS is an MFT record with $INDEX_ROOT and (for directories with more than a handful of entries) $INDEX_ALLOCATION attributes. The directory does not contain the files themselves — it contains an index of $FILE_NAME attribute copies, organized as a B-tree sorted by filename. Each index entry is a self-contained copy of a child file's $FILE_NAME data: the child's MFT reference (entry number + sequence number), the parent directory's MFT reference, the four $FN timestamps, the file size, the file flags, and the filename itself.
When you list a directory in Windows (dir, Explorer, Get-ChildItem), the system reads the directory's $INDEX_ROOT and $INDEX_ALLOCATION attributes and extracts the filenames and metadata from the index entries. It does not read each child file's MFT record — the index entries contain all the information needed for a directory listing. This is why large directory listings are fast: the data is pre-indexed in the parent directory's MFT record.
For small directories (fewer than roughly 15-20 files, depending on filename lengths), the entire index fits in $INDEX_ROOT, which is resident in the directory's MFT record. No $INDEX_ALLOCATION attribute exists. For larger directories, $INDEX_ROOT becomes the root node of the B-tree, and the child nodes are stored in $INDEX_ALLOCATION records — 4,096-byte blocks allocated in clusters on disk (similar to how non-resident $DATA uses clusters).
Index entries and their content
Each index entry in the B-tree contains:
MFT file reference (8 bytes): The child file's MFT entry number (6 bytes) and sequence number (2 bytes). This is how the directory entry links to the file's MFT record.
Index entry length (2 bytes): The total size of this entry including all fields. Used to navigate from one entry to the next.
$FN content length (2 bytes): The size of the embedded $FILE_NAME content.
Index entry flags (4 bytes): Bit 0 indicates a sub-node exists (the entry has a child in the B-tree below it). Bit 1 indicates this is the last entry in the index record (a sentinel entry that marks the end of the list).
Embedded $FILE_NAME content: A complete copy of the child file's $FILE_NAME attribute data — parent reference, four $FN timestamps, allocated size, real size, file flags, filename namespace, and the filename. This is the same data that exists in the child file's own $FN attribute.
The duplication of $FN data in both the file's MFT record and the parent directory's index is forensically valuable. If the file's MFT record has been reallocated (destroyed by a new file using the same entry), the directory's index entry may still contain the original filename and timestamps. And if the directory's index entry has been removed (the file was deleted), the file's own MFT record may still contain the data. The two sources corroborate each other when both exist and provide backup evidence when one has been destroyed.
$I30 slack — recovering deleted file evidence
The forensic value of $I30 slack comes from how B-trees handle deletion. When NTFS removes an index entry, it may reorganize the B-tree by merging nodes, rebalancing branches, or simply sliding entries forward to close the gap. In all cases, the bytes occupied by the deleted entry are not zeroed — they become slack at the end of the index record (if entries were shifted forward) or remain in place as overwritten regions (if the tree was restructured).
MFTECmd with the --de (detailed) flag and specialized tools like INDXParse examine the slack space in $INDEX_ALLOCATION records and carve out recognizable $FILE_NAME structures. A carved entry typically provides the deleted file's name, its parent directory MFT reference, the $FN timestamps, and the file size at the time of the directory entry's creation. This information is forensically significant even when the file's MFT record is unavailable:
In the insider threat scenario (INC-NE-2026-0915), the departing engineer deleted files from a staging directory after copying them to USB. The MFT entries for those files were eventually reallocated. But the staging directory's $I30 slack still contains the filenames and timestamps of the deleted files — proving they existed in that directory, which is sufficient to establish that the directory was used for staging exfiltration data.
In the unauthorized access dispute (INC-NE-2026-1130), the employee claims they never accessed the restricted folder. The restricted folder's $I30 index doesn't show the employee's files (because the employee only browsed, not saved). But the employee's home directory may have ShellBag evidence (WF4) of navigating to the restricted folder. The restricted folder's $INDEX_ROOT was modified (the access updated the directory's $SI accessed timestamp), and the $I30 index records may show access-time updates on existing entries that correlate with the employee's session times.
You are investigating a directory that the suspect claims was always empty — they say it was a placeholder folder created for a future project. MFTECmd's standard output shows the directory contains zero active files, which is consistent with the suspect's claim. However, you notice the directory's MFT record has a $INDEX_ALLOCATION attribute, which means the directory's index was large enough at some point to require non-resident storage. An always-empty directory would only have $INDEX_ROOT with no $INDEX_ALLOCATION.
Your options: (A) Accept the suspect's claim — the directory is empty and always has been. (B) Parse the $INDEX_ALLOCATION records for this directory and examine the slack space for deleted file entries. The presence of $INDEX_ALLOCATION suggests the directory once contained files, and their entries may persist in slack.
The correct approach is B. The $INDEX_ALLOCATION attribute's existence is itself evidence — NTFS only creates $INDEX_ALLOCATION when the directory contains enough entries to overflow $INDEX_ROOT. An always-empty directory would never have this attribute. Parse the allocation records with INDXParse or MFTECmd's $I30 carving mode. Any entries found in slack prove the directory previously contained files, contradicting the suspect's claim.
Practical $I30 analysis
To extract $I30 slack data from a forensic image, you need the directory's $INDEX_ALLOCATION attribute content. KAPE includes targets for $I30 extraction. MFTECmd can parse $I30 data when provided with the raw index allocation records. The INDXParse tool by William Ballenthin is specifically designed for $I30 slack carving.
The analysis workflow: identify the directory of interest (by MFT entry number or path), extract its $INDEX_ALLOCATION data from the forensic image, run the carving tool, and examine the output for deleted entries. Each recovered entry provides a filename, parent reference, timestamps, and file size — enough to establish that the file existed in that directory and when it was last modified.
The reliability of $I30 slack evidence depends on two factors: how much file creation activity has occurred in the directory since the target files were deleted (new entries overwrite slack space), and how the B-tree was reorganized during deletion (some reorganizations overwrite deleted entries immediately, others leave them intact in slack). In directories with low activity after deletion, recovery rates are high. In directories with high turnover (temporary directories, download folders), recovery rates are lower because new entries continuously overwrite the slack space.
Try it: Examine $I30 slack in a directory
Using the lab evidence provided with this module (or a KAPE collection from your own lab VM):
1. Identify a directory that you know previously contained files that have been deleted. If using your lab VM, create a test directory, add several files, then delete them. 2. Extract the $I30 data for the target directory using KAPE's $I30 target or by extracting the directory's $INDEX_ALLOCATION from the forensic image. 3. Run MFTECmd with the --de flag on the extracted MFT, filtering for the target directory's MFT entry number. 4. Examine the output for entries with "InUse: False" or similar indicators of deleted/slack entries. 5. For each deleted entry found, record the filename, timestamps, and MFT reference. Compare against the MFT to determine whether the file's MFT record still exists.
Document how many deleted entries you recovered, their filenames, and their timestamps. This exercise demonstrates that file deletion leaves recoverable traces in the parent directory's index structure — evidence that persists independently of the deleted file's own MFT record.
$INDEX_ROOT vs $INDEX_ALLOCATION — when each exists
Every directory has $INDEX_ROOT (type 0x90) — this is the root of the B-tree and is always resident in the directory's MFT record. Small directories (typically under 15-20 files) fit entirely within $INDEX_ROOT, and no $INDEX_ALLOCATION exists.
When a directory grows beyond what $INDEX_ROOT can hold, NTFS creates $INDEX_ALLOCATION (type 0xA0) — a non-resident attribute that stores index records in 4,096-byte blocks on disk. NTFS also creates $BITMAP (type 0xB0) to track which index records in $INDEX_ALLOCATION are in use. Once $INDEX_ALLOCATION is created, it persists even if the directory shrinks back to a few files — NTFS doesn't collapse the index back to $INDEX_ROOT-only.
This persistence is forensically useful. If a directory has $INDEX_ALLOCATION, it was large enough at some point to require non-resident index storage. The $INDEX_ALLOCATION records contain both active entries and potentially extensive slack space from previous directory states. A directory that once held hundreds of files and now holds three still has $INDEX_ALLOCATION records with slack from the removed entries.
You've built the foundations of artifact-level forensic analysis.
WF0 gave you the taxonomy, NTFS architecture, and the five-step methodology. WF1 took you inside the MFT at the binary level — every attribute, every timestamp, every edge case. From here, every artifact category gets the same raw-first treatment.
- WF2–WF10: every major Windows artifact decoded at binary level — USN Journal, Prefetch, Amcache, Shimcache, ShellBags, LNK, Jump Lists, SRUM, Event Logs, and the Registry hives
- INC-NE-2026-0915 (WF13) — Insider data exfiltration capstone. Work the complete investigation from USB history to OneDrive exfiltration evidence
- INC-NE-2026-1022 (WF14) — Ransomware capstone. Three-host triage (FIN01 → IT03 → FS01) across the 72-hour attack chain
- The lab pack — 25+ realistic evidence files in 10 formats, simulated KAPE triage pre-populated, both capstones deployable to your own VM
- Anti-forensic detection methodology — defeat timestomping, log clearing, and Prefetch deletion with cross-artifact correlation
Cancel anytime