Have you ever heard that solid-state drives destroy evidence? Let’s revisit the facts before going further.
When first solid-state drives appeared, there was no Trim command. There was no easy way for a drive to reclaim unused blocks of user data (i.e., data exposed to a host as drive contents) for the wear-leveling process.
To mitigate this problem, manufacturers did a clever trick: they began producing file-system-aware solid state drives!
Some articles deny the existence of such a trick, but the truth is that some ancient solid-state drives were capable of parsing a partition table and an NTFS file system to locate unallocated (free) clusters and reclaim their blocks for the wear-leveling process (thus, wiping remnant data in these clusters).
If you don’t believe me, watch this old talk (August 2008) from Scott Moulton (for me, the most interesting part is here: 1:43-2:43). How would you explain an issue with “wiped” unallocated space (and don’t forget about this table)?
Not convinced? See this slide from Neal Christiansen:
Still sceptical? Here is a screenshot:
This screenshot illustrates the “S-DEL” feature found in a firmware dump of the following solid-state drive: Corsair P64. It’s the same drive model as used by the authors of this paper: “Solid State Drives: The Beginning of the End for Current Practice in Digital Forensic Recovery?” (there were rumors that the authors used a vendor-specific software helper which provided Trim-like functionality but didn’t list this tool in the “EXPERIMENTAL ENVIRONMENT” section, but reverse engineering clearly shows that there is an NTFS parser inside the drive used for testing).
So, this is why solid-state drives were destroying evidence. But today, things are different. We have Trim and similar commands (UNMAP, Deallocate) and most operating systems support them. There is no need to support file systems in firmware of a solid-state drive.
On the drive side, the Trim command is implemented in two ways:
- After a logical block is reported as discarded using the Trim command, subsequent reads of this block return either old (pre-trim) data or something else, even if a host didn’t write to that block (“non-deterministic read after Trim”).
- After a logical block is reported as discarded using the Trim command, subsequent reads of this block return something that doesn’t change before the block gets overwritten by a host (“deterministic read after Trim”). Usually, null bytes are returned for a discarded (trimmed) logical block (“deterministic read zeros after Trim”). In this case, trimming a data block is very similar to wiping that block except that old (pre-trim) contents could survive on the physical layer (which is inaccessible to a host).
Here is a screenshot of how data is changed after the Trim command when the “deterministic read zeros after Trim” feature is in place (as a side note: it’s the same Samsung drive as described below):
If you heard stories about successful recovery of deleted data from solid-state drives, it’s likely that non-deterministic Trim was in play and trimmed data (or, at least, some part of it) could be read by a host (as easy as in the hard disk drive forensics).
Here is a quote from Belkasoft:
“I ran a test on my SSD drive, deleting 1000 files and running a data recovery tool 5 minutes after. The tool discovered several hundred files, but an attempt to recover returned a bunch of empty files filled with zeroes”, said one Belkasoft customer.
“We used Belkasoft Evidence Center to analyze an SSD drive obtained from the suspect’s laptop. We were able to recover 80% of deleted files in several hours after they’ve been deleted”, said another Belkasoft user.
Although some vendors claim to successfully recover trimmed data using the “techno” mode, this kind of technology isn’t available in most labs. Also, a list of drives supported by this technology is short.
Finally, there are notable exceptions for the Trim command:
- Many RAID controllers don’t support the Trim command.
- Many USB enclosures don’t support the Trim command.
- Many Linux distributions don’t issue the Trim command immediately (as soon as a file is deleted). Instead, unallocated space of a mounted file system is trimmed by a periodic job.
- Small (resident) files in NTFS file systems aren’t trimmed. The same applies to $MFT metadata about deleted files in general.
- Some blocks can be left untouched when formatting a drive (for example, blocks in the Microsoft reserved partition).
But these are just exceptions! I have seen examiners not even trying to recover deleted data from solid-state drives if the Trim support wasn’t explicitly disabled in an installed operating system. (There are no valid reasons for not even trying. Even if a drive properly implements the “deterministic read zeros after Trim” feature.)
But are we really sure that deleted data is actually discarded (trimmed) in all cases?
Actually, no, it isn’t.
The tests have been conducted using the following solid-state drives:
- Apple SSD AP0512 (located in a laptop: MacBook Pro “A1990”);
- Samsung 860 EVO (1 TB, SATA).
The operating system used in the tests was Windows 10 “20H1” (it was installed on each drive).
Both drives used in the tests implement the “deterministic read zeros after Trim” feature properly. This was validated by putting a Windows 10 installation on each drive into hibernation and then resuming. Before the resume, valid memory data could be observed in the hibernation file (hiberfil.sys). Right after the resume, the hibernation file contains null bytes (after the header) instead of memory data (such memory data is subject to in-file trimming and it’s known to survive on solid-state drives without the “deterministic read zeros after Trim” feature). The Samsung drive also reports the “deterministic read zeros after Trim” feature to a host (still, it was worth checking the implementation; an additional feature test was already shown on the screenshot above).
After using each operating system installation for some time, I found that there were decent amounts of meaningful data in unallocated space of the system volume. Some unallocated blocks (on both drives) contain data matching the format of registry transaction log files, while other blocks contain data similar to what is stored in the “ActivitiesCache.db-wal” file.
(As a side note: recovered chunks similar to described above have been observed when examining real-world data from an OCZ drive found in a laptop in one of my cases. But no “user files” could be recovered from unallocated space on that drive.)
A theory to explain this is the following: during the shutdown, a Windows 10 installation truncates some “system” files, but no Trim command is issued in time for affected data blocks (before the system turns off).
A simple test was conducted with the Apple drive to see if it’s true: right before the shutdown, a list of clusters allocated by files in question (“ntuser.dat.LOG1”, “ntuser.dat.LOG2”, and “ActivitiesCache.db-wal”) was obtained using the “fsutil file layout /v <…>” command.
Right after the shutdown, the status of these clusters was checked using the “ifind” tool. The clusters previously belonging to the “ntuser.dat.LOG2” file became marked as unallocated, but they contain valid registry transaction logs (24 4096-byte clusters in total, divided into two runs: 7 and 17 clusters respectively). The file size is reported as zero bytes.
The same story is with the “ActivitiesCache.db-wal” file. Its current file size is reported as zero bytes and its “previous clusters” contain data that looks valid (288 4096-byte clusters in total, divided into 21 runs, most runs contain 16 clusters)!
The “ntuser.dat.LOG1” file is intact.
The same test was repeated with the Samsung drive, it produced similar results. Here is a screenshot of a cluster which belonged to a transaction log file of the NTUSER hive:
Next, I did the test with the Samsung drive again, but additionally rebooted the machine before shutting it down. And similar results were observed again (except that some blocks have been allocated and reused by other files). So, this type of remnant data is not trimmed after the boot.
I also tried to truncate newly created files using Python, but the “removed part” of a truncated file is always zeroed out. So, the Trim command for a truncated block is expected to be issued (and the issue isn’t caused by simply truncating a file).
Finally, I repeated the original test twice with the Apple drive, but before shutting down, filled the system drive with large text files (containing a fixed byte pattern) and deleted them. As a result, this byte pattern is absent in unallocated clusters (data blocks were trimmed), but data from registry transaction log files is still present in some unallocated clusters (no trim here).
Update (2020-06-13): a BitLocker-encrypted system volume has the same behavior (unallocated clusters containing valid data after decryption).
It seems that the theory is valid. There is deleted data not trimmed by Windows 10.