Encrypted, but never modified: memory-mapped writes leave NTFS timestamps untouched
Summary
When a file is rewritten through a memory-mapped view on Windows, NTFS does not update its last-write time or its change time. We measured this on Windows 11 (build 26300, NTFS): files whose entire content was replaced with ciphertext kept the timestamps they had as plaintext, with or without FlushViewOfFile, with or without FlushFileBuffers, and two minutes later.
Ransomware families have used memory-mapped I/O for years. The consequence that gets less attention is forensic and defensive: any tool or investigation that decides “what changed” by looking at timestamps does not see these files as changed at all.
The change journal does see them. In our tests every rewritten file has a DATA_OVERWRITE record in the USN journal, and for mapped writes that record is newer than the file’s own last-write time. That gap separated mapped rewrites from ordinary ones in every file we tested.
We found this while building Sparta Defend’s ransomware protection, and we have addressed it in the product.
What Microsoft documents
The MapViewOfFile documentation contains one sentence on the subject:
“When modifying a file through a mapped view, the last modification timestamp may not be updated automatically. If required, the caller should use SetFileTime to set the timestamp.”
Microsoft Learn: MapViewOfFile
That is written for application developers: if your program uses mapped files and you care about the timestamp, set it yourself. It does not say how often “may not” happens, and it does not consider the case where the program writing through the view is an attacker who has no reason to call SetFileTime.
Memory-mapped encryption by ransomware is also documented. Sophos described LockFile using memory-mapped I/O in 2021, noting that the encrypted data is written to disk by the System process rather than by the ransomware, and that Maze and WastedLocker used the same technique (Sophos). That analysis is about evading behavioural detection. We did not find published work on what the technique does to file timestamps, or on how to recognise it after the fact.
What we found
While building Sparta Defend’s ransomware protection, we tested it against a simulated encryptor that works through mapped views. An early version of one component relied on the last-write time to tell which files had changed. It missed every file the simulator encrypted: the content was ciphertext (entropy 7.997 bits per byte), and the timestamps still showed the moment the files had been created as plaintext, 40 minutes earlier.
We then measured the behaviour on its own, outside our product, with a control group.
Method
A small C program creates four groups of 12 files, 64 KiB each, with the same plaintext. After a three-second pause, it rewrites every file in place with the same keystream, using a different method per group:
| Group | How the file is rewritten |
|---|---|
| Control | ReadFile, then WriteFile over the same bytes |
| Mapped + flush | CreateFileMapping, MapViewOfFile, rewrite in memory, FlushViewOfFile, UnmapViewOfFile, CloseHandle |
| Mapped, no flush | the same without FlushViewOfFile, leaving the dirty pages to the system |
| Mapped + flush + FlushFileBuffers | the same as mapped + flush, plus FlushFileBuffers on the file handle before closing it |
For every file it records LastWriteTime and ChangeTime (FILE_BASIC_INFO) right after creation, right after the rewrite, and again 120 seconds later. It also records content entropy before and after, to prove that the rewrite reached the disk, and every USN journal record for the file written after the rewrite began.
Results
Windows 11, build 26300, NTFS, 48 files:
| Group | LastWriteTime changed | ChangeTime changed | Entropy before → after | USN DATA_OVERWRITE | USN record newer than LastWriteTime |
|---|---|---|---|---|---|
| Control (WriteFile) | 12 / 12 | 12 / 12 | 4.19 → 8.00 | 12 / 12 | 0 / 12 |
| Mapped + flush | 0 / 12 | 0 / 12 | 4.21 → 8.00 | 12 / 12 | 12 / 12 |
| Mapped, no flush | 0 / 12 | 0 / 12 | 4.21 → 8.00 | 12 / 12 | 12 / 12 |
| Mapped + flush + FlushFileBuffers | 0 / 12 | 0 / 12 | 4.21 → 8.00 | 12 / 12 | 12 / 12 |
The result was identical across two separate runs, and nothing changed in the 120 seconds after the rewrite. The control group confirms that the measurement works: an ordinary write updates both timestamps every time.
In practice “may not be updated” meant “was never updated” in every case we tested, including the cases where the program explicitly flushed the data.
Why it matters
- Change-based scanning. File integrity monitoring, backup verification and incremental malware scans often re-examine only the files whose last-write time moved. A file encrypted through a mapped view never qualifies.
- Incident timelines. Timeline tools built on
$STANDARD_INFORMATIONtimestamps show encrypted files as last modified when they were still intact. The encryption does not appear in the timeline at all. - Size does not help. In-place encryption also leaves the file size unchanged, so neither of the two cheapest signals (time, size) moves.
Recognising it after the fact
For investigators, the USN change journal fills the gap the timestamps leave. It recorded DATA_OVERWRITE for every rewritten file in our tests, whichever method was used. What sets mapped writes apart is the order: a DATA_OVERWRITE record that is newer than the file’s own LastWriteTime is a strong sign that the file was changed through a mapped view. That gap appeared in 12 of 12 mapped rewrites and in 0 of 12 ordinary ones.
Attackers often delete the journal (fsutil usn deletejournal), but deleting it is itself a well-known indicator of compromise.
Sparta Defend
Sparta Defend’s ransomware protection does not depend on file timestamps, and a file encrypted through a mapped view is detected. We do not publish the details of our detection logic.
Reproducing it
The test program (mmap_ts.c, about 400 lines of C, no dependencies) only creates and rewrites files inside the directory you give it. Build it with MSVC and run it from an elevated prompt so the USN journal can be read:
cl /O2 mmap_ts.c mmap_ts.exe <empty_directory> 12 3 120