The million dollar question of any interview for a DFIR role. What happens when a file is deleted, what changes occur, and how one can still find evidence of the file's existence after the file was deleted.
I personally heard this question in interviews for every role that required experience in digital forensics. Next, by frequency, are "the meaning of file timestamps" and "how to detect file timestamp tampering", which I plan to cover in future posts.
Technical assumptions
Before we dive into the details, this article assumes a fair level of familiarity with NTFS data structures and with the digital forensic field. If you find terms or concepts here that you do not understand, check the references at the end, where I list the books I have used many times during investigations.
Since the question was always asked about Windows, I will limit the scope to Windows 7 and later with NTFS 3.1.
One caveat before we start: the deletion path changed in Windows 10 1709. If you are testing this on a modern build you will see different behaviour than the classic answer describes. I cover that below.
Deep dive
First let us review how a file can be removed. In the first scenario a logged-on user deletes the file by selecting it and pressing delete, or right-clicks and deletes it, sending it to the Recycle Bin folder for that user account.
In the second scenario the file is deleted with shift and delete, or cut and paste to a different volume. This is also how most desktop applications, and the operating system itself, transparently delete files that never appear in the user's Recycle Bin.
The first scenario is the more complex, so let us take that one. Our user has just deleted secret_file.txt from the Desktop.
The Recycle Bin: the $R file
The original file is renamed and moved to the Recycle Bin folder corresponding to the account used to delete it.
At NTFS level this is a modification of the $FILE_NAME attribute, to reflect the new parent folder (now that user's Recycle Bin) and the new name, $R followed by six characters, retaining the original extension. That naming applies only when the file was deleted directly. If the file sat inside a folder structure and one of the parent folders was deleted, it keeps its original name.
Note that the file is moved, not copied, so the $MFT entry and the data clusters are the same ones. This matters: at this point nothing has been destroyed.
The Recycle Bin: the $I file
At the same time a $I file, the pair of the $R file above, is created in the same folder. It records the original path, the original size, and the deletion timestamp, so the OS can put the file back if the user restores it.
The format has two versions and it is worth knowing which you are looking at. Version 1, on Vista through Windows 8.1, is a fixed 544 bytes with the original path in a fixed-size field. Version 2, from Windows 10, is variable length and carries an explicit path-length field. A parser written for one will silently misread the other.
Traces of what caused the deletion will also appear in Explorer shellbags, registry entries and event logs. We will not cover those here, but keep them in the picture.
What happens at NTFS level
From the moment the user empties the Recycle Bin, the following steps are also valid for the second scenario, the shift and delete.
$MFT: the in-use flag
The in-use flag, bytes 22 to 23 of the $MFT entry header, is set to zero to indicate the entry is no longer allocated. Bit 0 is the in-use bit and bit 1 marks a directory, so a deleted directory reads 0x02 rather than 0x00.
$MFT: the sequence number
The sequence number, bytes 16 to 17 of the same header, is incremented.
This is more useful than it first appears. Directory index entries and other references store a file reference made of the record number plus the sequence number. When you find an index entry whose sequence number no longer matches the record it points at, you are looking at a record that has since been reused by a different file. That single comparison tells you whether the metadata you are reading still belongs to the file you are chasing.
$MFT: resident data
If the file is small enough, its content lives inside the MFT record itself rather than in clusters on disk. The record is typically 1024 bytes, but after the header and the $STANDARD_INFORMATION and $FILE_NAME attributes, the space left for resident $DATA is a few hundred bytes in practice, not the full 1024.
For those files, recovering the record recovers the file. Not the name and the timestamps, the actual content.
$LogFile
The $LogFile records the change. The operation used for file deletion is DeallocateFileRecordSegment.
Read it in pairs. NTFS journals redo and undo for each operation, and the deletion of a file appears alongside DeleteIndexEntryAllocation or DeleteIndexEntryRoot for the parent directory, and bitmap operations for the freed clusters. Taken together those give you the order of events, not just the fact of them.
The $LogFile is also a place to recover resident file content, because the undo record has to contain enough to put things back.
The limitation is time. $LogFile normally holds minutes or hours, depending on how busy the system is.
$UsnJrnl:$J
The USN journal is far more verbose than $LogFile and normally covers one or more days.
When exporting the alternate data stream $J, make sure you specify the full path including the attribute name. To find deleted files after parsing, look for the reason flags FILE_DELETE (0x00000200) and CLOSE (0x80000000).
One detail that trips people up: USN reason flags accumulate across the life of a handle and are written out together. You are usually looking for a single record carrying FILE_DELETE|CLOSE, not two separate events.
Delete on close, and what changed in Windows 10
Using Procmon you can see that for file deletion the operation executed is CreateFile with the Delete on Close option set. The classic behaviour is that the file enters a delete-pending state: the directory entry survives until the last handle closes, and any attempt to open it in the meantime returns access denied.
From Windows 10 1709 this is no longer the whole story. Windows added POSIX delete semantics, FILE_DISPOSITION_POSIX_SEMANTICS, which unlink the name immediately while the file data persists until the last handle closes. Explorer uses it. If you are reproducing the classic answer on a current build and the behaviour does not match the textbook, this is why.
$Bitmap
$Bitmap is modified to mark the volume clusters associated with the file as available again. If the file was resident there are no clusters to free, so $Bitmap is not touched, which is itself a small signal about the size of what was deleted.
$I30: where the names survive
The $I30 index allocation and index root attribute of the parent folder may change, because the directory contents are stored as a B-tree. Depending on where the entry sat in the tree, the filename may or may not be removed from the index on deletion.
This is the part I would want a candidate to reach on their own: even when the entry is removed from the tree, the bytes frequently remain in index slack.
INDX records are allocated in fixed-size blocks and the tree only rewrites what it needs to. Entries that were logically removed, and entries from earlier states of the directory, sit in the unused space after the last valid entry. Parsing that slack recovers filenames, sizes and the full set of $FILE_NAME timestamps for files whose MFT records were reused long ago.
In practice this is often the last place a deleted filename survives on a busy system.
Volume Shadow Copies
Everything above concerns the live volume. Shadow copies preserve earlier states of the same structures, so a file deleted after the last snapshot still exists, intact, inside it. Worth checking before concluding that something is unrecoverable.
SSD and TRIM: what actually happens
Most laptops now use solid state disks, and from Windows 7 the OS issues the TRIM command when a file is deleted. This is where the classic answer is most often stated incorrectly, including in my own earlier version of it.
TRIM does not remove anything from the $MFT. It informs the SSD controller that a set of logical block addresses is no longer in use. The controller is then free to erase those blocks during garbage collection, and reads of them typically return zeros afterwards. That destroys the data.
The MFT record is a separate matter. It is marked unallocated exactly as described above and it persists until the file system reuses it. So on an SSD you will routinely find yourself able to prove that a file existed, with its name, size and timestamps, while being unable to recover a single byte of its content. That asymmetry is the answer worth giving.
Before assuming any of it, check whether TRIM was actually enabled: fsutil behavior query DisableDeleteNotify. A returned value of 0 means TRIM is on. It is off more often than people expect, and it does not apply at all to volumes reached over the network or to some virtual disk configurations.
HDD
On a spinning disk the file may still be present, with the modifications described above, for far longer. Seconds, minutes, hours or days, depending on how busy the system is, which is what gives a forensic examination room to work.
Putting it together
If I had to answer this in an interview in one breath, in the order I would actually pull the evidence: $MFT for the record and the sequence number, $I30 including slack for names the MFT no longer holds, $UsnJrnl for the day, $LogFile for the minutes and for resident content, $I files in the Recycle Bin for original paths, and shadow copies for anything that predates all of it.
And then the part that separates a good answer from a complete one: say what you could not have seen. On an SSD with TRIM enabled, the absence of content is not evidence that the file was empty.
Conclusion
There are a number of implications when deleting a file in a Windows system. Answering a question like this is meant to show a sound understanding of how NTFS works at a deep level, and knowing where the standard answer is wrong is a large part of that.
I hope you found it useful. If you have questions, or would like to see more content like this, get in touch.
References
- Windows forensics Forensic Examination of Windows Supported File Systems amazon.com/dp/1497358353
- Windows forensics Brian Carrier, File System Forensic Analysis amazon.com/dp/0321268172
- TRIM General presentation en.wikipedia.org/wiki/Trim_(computing)
- TRIM Windows API: sending TRIM and UNMAP hints to storage media docs.microsoft.com/windows/win32/w8cookbook
- TRIM Activate, deactivate and query TRIM status with fsutil behavior docs.microsoft.com/windows-server/administration/windows-commands/fsutil-behavior