SANS Digital Forensics and Incident Response Blog

NTFS $I30 Index Attributes: Evidence of Deleted and Overwritten Files

Daunting as it may seem, one of the most wonderful aspects of Windows forensics is its complexity. One of the fascinating aspects of digital forensics is how we often leverage conventional operating system features to provide information peripheral to their original design. One such feature is the Windows NTFS Index Attribute, also known as the $I30 file. Knowing how to parse $I30 attributes provides a fantastic means to identify deleted files, including those that have been wiped or overwritten.

A Simple Description of Index Attributes

Many popular file systems such as FAT and Unix store directory information as a simple flat file. Recognizing efficiency issues with lookups within large flat files, NTFS employed B-tree indexing for several of its building blocks, providing efficient storage of large data sets and very fast lookups. As forensic examiners, we can take advantage of the NTFS B-tree implementation as another source to identify files that once existed in a given directory.

Similar to Master File Table (MFT) entries in NTFS, index entries within the B-tree are not completely removed when file deletion occurs. Instead, they are marked as deleted using a corresponding $BITMAP attribute. Additionally, the size of index nodes can vary, particularly for large filenames, providing a type of slack that can hold previously existing filenames. Since B-tree nodes are regularly shuffled to keep the tree balanced, file name remnants are scattered and it is a common occurrence to find duplicate nodes referencing the same file. Of course, the flip side of re-balancing a B-tree is that it often results in data within unallocated nodes being overwritten. Thus while we commonly find evidence of long lost files within $I30 attributes, there is no guarantee they will be present.

Interestingly, NTFS directory index entries utilize a $FILE_NAME attribute type to store file information within the index. You may recall that this is the same attribute employed by the MFT and hence it provides a treasure trove of information about the file:

  • Full filename
  • Parent directory (useful if you recover a $I30 file in free space and do not know its origin)
  • File size
  • Creation Time
  • Modification Time
  • MFT Change Time
  • Access Time

Timestamps Found Within Index Attributes

A key distinction when reviewing timestamps stored within $I30 files is that these timestamps are $FILE_NAME attribute timestamps and not $STANDARD_INFORMATION timestamps that we regularly view in Windows Explorer, your favorite GUI forensics tool, and within timelines. This distinction deserves a blog post of its own, but suffice to say $FILE_NAME times are often updated in a much different (and even more arbitrary) set of circumstances. Fortunately, for $I30 files, I have observed that this set of timestamps tends to mirror those that are in $STANDARD_INFORMATION. Thus even if the original file no longer exists, we may still be able to identify its name, file size, and original timestamps!

$I30 Files in Practice

A few examples can better illustrate how useful these entries can be. I recently had a case where it appeared a large number of files were moved to the Recycle Bin, which was subsequently emptied and most of the corresponding INFO2 file was reallocated. The $I30 file still contained information on many of those files (albeit renamed according to the Recycle Bin schema). By analyzing the MFT Change Times of the $I30 index entries, I was able to determine when the user placed each file within the Recycle Bin, and collect a list of what types of files were "recycled" using their file extensions.

In a malware or intrusion case, $I30 entries provide knowledge of a file's existence and a separate and distinct set of timestamps to compare against for signs of tampering. This is a great example of why it is extremely difficult for malware or an anti-forensics tool to reliably change all of the corresponding timestamps within a file system.

Evidence may still be found in Index Attributes even if wiping or anti-forensics software has been employed. Figure 1 shows the parsed output for a $I30 file from the Windows directory. Two deleted index entries have been highlighted. In this example, a file named fgdump.exe was overwritten using a software tool named BCWipe. The original filename was overwritten with random characters (sqhyoeop.roy) and the Modified, Accessed, and Created time stamps were set to fictitious values. Since MFT Change Times cannot be directly modified via the Windows API, that timestamp still accurately reflects when the wipe occurred. Of course the interesting part of this example is that evidence of both the original file and the wiping artifacts are contained in the slack of the $I30 file.

Figure 1: Evidence Found in $I30 of Use of File Wiping Software
Figure 1: Evidence Found in $I30 of Use of File Wiping Software

Exporting NTFS Index Attributes

One of the primary reasons many examiners don't utilize index attribute files is because getting access to them is not always intuitive. I congratulate Access Data and their Forensic Toolkit (FTK) for clearly identifying $I30 indexes for as long as I can remember. Figure 2 shows what they look like in FTK. Simply right-click on the $I30 file to export from the image.


Figure 2: $I30 File as Shown in AccessData Forensic Toolkit
Figure 2: $I30 File as Shown in AccessData Forensic Toolkit

The Sleuth Kit (TSK) also does an excellent job with Index Attributes, although the interface takes a little practice. Figure 3 shows output from the TSK istat tool for a RECYCLER child directory. Near the bottom of the output we see the NTFS attribute list.


Figure 3: TSK istat Output Showing NTFS Attributes
Figure 3: TSK istat Output Showing NTFS Attributes

You may notice multiple attributes using the $I30 name in Figure 3. Brian Carrier's File System Forensic Analysis book dissects each of these attributes, and the simple explanation is they are all components of the overall Index Attribute [1]. To export the $I30 attribute from this directory, we use the icat tool from TSK and give it the MFT entry number of the directory along with the identifier for the $INDEX_ALLOCATION attribute, which in this case is "160-4" (Figure 4). This output is redirected into a file named, $I30.


Figure 4: Exporting a $I30 attribute using The Sleuth Kit
Figure 4: Exporting a $I30 attribute using The Sleuth Kit

To identify index attributes in EnCase, an EnScript is required. An Enscript ships within the stock Examples folder and is named, "Index buffer reader". This script can be pointed at a specific directory, a collection of tagged directories, or the entire file system. The results are nicely bookmarked and the entries are parsed within each bookmark's comments field. To export the $I30 file in EnCase, you first select the "Index Buffer" that you are interested in within the Tree Pane, select all within the View Pane, and right-click and select Export (Figure 5).


Figure 5: $I30 Parsing in EnCase
Figure 5: $I30 Parsing in EnCase

Parsing Index Attributes

The format of $I30 entries is well known and extensively documented. However, indexes commonly reach sizes in the hundreds of kilobytes and hold thousands of entries (theoretically they could have billions of entries). It is tiresome work to do the parsing by hand. Of the previously covered forensic suites, only EnCase has a native ability to parse the files, though the output is very difficult to use and analyze. Luckily, Willi Ballenthin recently released an open source tool that does an excellent job of parsing $I30 files [2]. It formats output as CSV, XML, or bodyfile (for inclusion into a timeline) and has a feature to search remnant space for slack entries. The tool is written in Python and sample command line follows:

python -d $I30 > $I30_Parse.csv

The resulting file can be opened and filtered in Excel (CSV output is the default). Notice the file names, file size, and four timestamps displayed in the output shown in Figure 6. Several deleted index node entries (slack) are also displayed within the output.


Figure 6: Output for an Exported $I30 Attribute
Figure 6: Output for an Exported $I30 Attribute


[1] File System Forensic Analysis, Brian Carrier (included with the SANS Forensics 508 Course)

[2] by Willi Ballenthin

[3] John McCash previously discussed Index Attributes in this blog post


Chad Tilbury, GCFA, has spent over twelve years conducting computer crime investigations ranging from hacking to espionage to multi-million dollar fraud cases. He teaches FOR408 Windows Forensics and FOR508 Advanced Computer Forensic Analysis and Incident Response for the SANS Institute. Find him on Twitter @chadtilbury or at


Posted September 20, 2011 at 5:31 PM | Permalink | Reply


Hi Chad,
Rocking post sir. I have been testing Willi's tool too. Per your statement
"A key distinction when reviewing timestamps stored within $I30 files is that these timestamps are $FILE_NAME attribute timestamps and not $STANDARD_INFORMATION timestamps that we regularly view in Windows Explorer''"
I was under the impression that the $I30 timestamps were $SI timestamps. The only reason was due to recent testing I was doing with Willi's tool.
In my testing, I changed the $SI timestamps with windows powershell to see the effects on the $I30. For example;
(get-item malicious.dll).creationtime=$(Get-Date "02/11/10 07:30")
(get-item malicious.dll).lastwritetime=$(Get-Date "02/11/10 07:30")
(get-item malicious.dll).lastaccesstime=$(Get-Date "02/11/10 07:30")
Typically this will only change the $SI time stamps in the $MFT but not the $FN attributes. The analysis of the $I30 showed the same behavior (they were changed with the exception of the record modified time. Consequently, I assumed they were $SI attributes.
Am I misguided?
Thanks in advance.

Posted September 21, 2011 at 5:19 AM | Permalink | Reply

Chad Tilbury

Hi Tim.
I'm pleased to see that our independent testing agrees. The NTFS structure used to record index entries is a $FILE_NAME attribute (separate and distinct from the $FILE_NAME attribute found in the Master File Table). Thus we can recover information like the file name, parent directory, and timestamps. However, the timestamps kept within the Index Attribute appear to be aligned with the MFT $STANDARD_INFORMATION attribute (as you describe). My intent was to point out that the same $FILE_NAME format is re-used by Index Attributes, but the timestamps are updated differently than we might expect.

Posted October 2, 2011 at 5:10 PM | Permalink | Reply

Chris Taylor

For those of you using encase v6 (v7 requires major rewrite of the script), there is a script on the page below that will also parse $I30 indexes. It was written because of two shortcomings found in the script Chad mentions: it doesn't account for fixups causing data to occasionally be incorrect and it only returns the fields the author thought were important. The script below returns all of the fields, which is a lot more than you need for a forensic investigation, but is vital for understanding what's going on in the index.

Posted October 2, 2011 at 5:16 PM | Permalink | Reply

Chris Taylor

You are both right! Within the index are structures that match the $FN attributes, which is what Chad is alluding to. But, the timestamps for every file in the index are updated to whatever that file's current times are anytime the index is rewritten. So, the index should contain relatively current times that match the file's $SI attibute's times.

Posted October 3, 2011 at 1:47 AM | Permalink | Reply

Chad Tilbury

Chris ''"
Thanks for weighing in. I look forward to trying out your EnScript!

Posted October 12, 2011 at 6:35 AM | Permalink | Reply

Yogesh Khatri

Good write up on $I30 and the timestamp issue, just yesterday someone emailed me about the same issue. It seems people have started to pay attention to this old artifact :-) with lots of scripts available now.
I too had written a script to parse $I30 files about a couple of years back as no scripts existed then. In addition to the usual $I30 files, it tries to make sense of the garbage (partial entries). The big additional feature is it also searches in MFT slack for old $I30 entries (where $I30 is now non resident).
For those wanting another free script here it is ( Output is available in a GUI, exportable to csv file.

Posted March 6, 2012 at 7:26 PM | Permalink | Reply

John McCash

Hey Chad! I found this a couple of weeks ago, and was using it on a case. I used bodyfile output, and then converted to more standardized csv with log2timeline. One thing I just noticed is that last access times seem to be coming out as [M] times'' Does Willi have two of the timestamp positions reversed, or am I or log2timeline mangling something?
John McCash

Posted April 14, 2012 at 5:17 AM | Permalink | Reply

Chad Tilbury

Willi did in fact have the timestamps swapped. Good catch! Please make sure you are working from the latest version on github.

Posted August 3, 2012 at 4:53 AM | Permalink | Reply

Jetico Technical Team

Hello Chad,
We are developers of BCWipe wiping software that you mentioned in your article.
We would like to inform you and anybody interested that we released BCWipe v6 in March,2012 and it can wipe B-tree structure and attributes of directories stored in MFT, including $I30 .
We would greatly appreciate if you re-do the tests with BCWipe v6 ''" try to parse
$I30 again and post the results here.

Posted August 10, 2012 at 5:47 PM | Permalink | Reply

Rob Lee

This is great information. Thank you for posting. We will try and do the experiment again.

Posted January 13, 2013 at 12:09 AM | Permalink


Chad has had 5 months to run the test with BCWipe Ver.6. I think it is safe to say that vers. 6 has rendered the $I30 formatting tools as well as this entire approach to forensics obsolete. I'm surprised Jetico does not have EnCase, FTK and the all latest forensic tools to do its own tests. I'm not going to wait for either of you. I'm going to do a brute force sector by sector search for attribute remnants.

Posted August 15, 2012 at 8:10 PM | Permalink | Reply


Hey Chad,
Found an $I30 in FTK and it was written roughly 30 seconds after a device was plugged into the computer via USB. Is FTK reading the $I30 from the external device or from the host computer?

Posted August 15, 2012 at 8:56 PM | Permalink | Reply

Chad Tilbury

Chris ''" The $I30 index is a NTFS attribute stored in the Master File Table ($MFT) entry for a directory. Assuming that your evidence is a hard drive image, you are seeing information parsed from the $MFT belonging to the volume mounted on the computer the hard drive was imaged from. NTFS attributes do not have Modified/Accessed/Changed/Created times like files and folders do. That being said, FTK chooses to display timestamps for $I30 files. $I30 timestamps in FTK correspond to the timestamps of the directory that owns the $I30 attribute (seen as the parent folder in FTK). Thus if you are looking at a modified time for the $I30, it could mean that something within the folder was changed. If you are looking at a creation time, it could mean the folder was created.

Posted September 17, 2013 at 4:00 PM | Permalink | Reply

Pradeepan Patra

Hi Chad,
Thanks a lot for such nice post.
By parsing $FILE_NAME attribute we are good to get the file name.
Whether its possible to get the complete path of the file also? What i mean is how the directory structure is maintained inside $MFT and how can we retrieve the complete path information for a file?

Posted September 25, 2013 at 11:36 PM | Permalink | Reply

Chad Tilbury

In allocated directories, you can easily determine full path of files due to where the $I30 index is found. If you carve INDX entries from unallocated space, the $FN structure used to store each entry includes the MFT record number of the parent folder. If you have to determine this by hand, Brian Carrier's File System Forensic Analysis book provides a comprehensive view of $FN attributes.

Posted October 16, 2013 at 2:57 PM | Permalink | Reply

AntiVirus Annihilates Viruses

Evidence of deleted files is very important for me!!!
Thank you very much!