Copy-paste strange behavior in windows11

I have a minifilter that monitors IRP_MJ_WRITE notifications. I’m interested to capture every file written by user-mode applications, so in my preWrite callback, I used to ignore notifications that came from System.

if (PsInitialSystemProcess == PsGetCurrentProcess())
{
    goto Leave;
}

This code worked well and among other write operations, I was also able to intercept every copy-paste operation made by explorer.exe.

0: kd> k
 # Child-SP          RetAddr               Call Site
00 fffff582`15e295f0 fffff802`53794a5d     MyDriver!MyMinifilter::FilterPreWrite+0x182 
01 fffff582`15e29690 fffff802`537945a0     FLTMGR!FltpPerformPreCallbacks+0x2fd
02 fffff582`15e297a0 fffff802`53794112     FLTMGR!FltpPassThroughInternal+0x90
03 fffff582`15e297d0 fffff802`53793efe     FLTMGR!FltpPassThrough+0x162
04 fffff582`15e29850 fffff802`52646f79     FLTMGR!FltpDispatch+0x9e
05 fffff582`15e298b0 fffff802`52bfe5e5     nt!IofCallDriver+0x59
06 fffff582`15e298f0 fffff802`52c5bb46     nt!IopSynchronousServiceTail+0x1a5
07 fffff582`15e29990 fffff802`527e7d15     nt!NtWriteFile+0x676
08 fffff582`15e29a90 00007ff9`afd1c1c4     nt!KiSystemServiceCopyEnd+0x25
09 00000000`05b1ce98 00007ff9`ad78512d     ntdll!NtWriteFile+0x14
0a 00000000`05b1cea0 00007ff9`ad7a5450     KERNELBASE!WriteFile+0xfd
0b 00000000`05b1cf10 00007ff9`ad79dd85     KERNELBASE!BaseCopyStream+0x4d28
0c 00000000`05b1e140 00007ff9`ad7e12db     KERNELBASE!BasepCopyFileExW+0x7c5
0d 00000000`05b1e7c0 00007ff9`ad0fb838     KERNELBASE!CopyFile2+0xeb
0e 00000000`05b1e880 00007ff9`ad0f7073     windows_storage!CFSTransfer::_PerformCopyFileWithRetry+0xa4
0f 00000000`05b1e910 00007ff9`ad101587     windows_storage!CFSTransfer::CopyItem+0x1f3
10 00000000`05b1e970 00007ff9`ad024e53     windows_storage!CDelegatingTransfer::CopyItem+0xc7
11 00000000`05b1ea30 00007ff9`ad01664f     windows_storage!CCopyOperation::_CreateDestinationOrCopyItemWithRetry+0xef
12 00000000`05b1eb00 00007ff9`acc5124f     windows_storage!CCopyOperation::Do+0x10f
13 00000000`05b1ec00 00007ff9`acc4f63f     windows_storage!CCopyWorkItem::_DoOperation+0x9b
14 00000000`05b1ece0 00007ff9`acc4fd3a     windows_storage!CCopyWorkItem::_SetupAndPerformOp+0x2a3
15 00000000`05b1efd0 00007ff9`acc4dda8     windows_storage!CCopyWorkItem::ProcessWorkItem+0x152
16 00000000`05b1f280 00007ff9`acc55953     windows_storage!CRecursiveFolderOperation::Do+0x1a8
17 00000000`05b1f320 00007ff9`acc55476     windows_storage!CFileOperation::_EnumRootDo+0x253
18 00000000`05b1f3c0 00007ff9`acc56d0c     windows_storage!CFileOperation::PrepareAndDoOperations+0x1ce
19 00000000`05b1f490 00007ff9`ae1f24e9     windows_storage!CFileOperation::PerformOperations+0x10c
1a 00000000`05b1f4f0 00007ff9`ae1f1518     SHELL32!CFSDropTargetHelper::_MoveCopyHIDA+0x269
1b 00000000`05b1f5a0 00007ff9`ae1f3077     SHELL32!CFSDropTargetHelper::_Drop+0x1e8
1c 00000000`05b1fa80 00007ff9`aeafdce5     SHELL32!CFSDropTargetHelper::s_DoDropThreadProc+0x37
1d 00000000`05b1fab0 00007ff9`af257bd4     shcore!_WrapperThreadProc+0xf5
1e 00000000`05b1fb90 00007ff9`afceced1     KERNEL32!BaseThreadInitThunk+0x14
1f 00000000`05b1fbc0 00000000`00000000     ntdll!RtlUserThreadStart+0x21
0: kd> !process -1 0
PROCESS ffffd90d7c00e400
    SessionId: 1  Cid: 0eac    Peb: 008cf000  ParentCid: 0e94
    DirBase: 32c51002  ObjectTable: ffff958f10d58180  HandleCount: 2210.
    Image: explorer.exe

Starting from windows 11 22H2 , I stopped catching explorer’s copy-paste operations, after debugging the issue it turns out that these PreWrite operations are now being carried out by a separate System thread (and not under explorer.exe context):

kd> k
 # Child-SP          RetAddr               Call Site
00 ffff8080`d5bc65a0 fffff802`2d4b7276     MyDriver!MyMinifilter::FilterPreWrite+0x182 
01 ffff8080`d5bc66a0 fffff802`2d4b6ce1     FLTMGR!FltpPerformPreCallbacksWorker+0x3a6
02 ffff8080`d5bc67b0 fffff802`2d4b5cf2     FLTMGR!FltpPassThroughInternal+0xd1
03 ffff8080`d5bc6800 fffff802`2d4b5992     FLTMGR!FltpPassThrough+0x172
04 ffff8080`d5bc6860 fffff802`29ada1f5     FLTMGR!FltpDispatch+0x142
05 ffff8080`d5bc68c0 fffff802`2a002180     nt!IofCallDriver+0x65
06 ffff8080`d5bc6900 fffff802`29a5afe2     nt!IopSynchronousServiceTail+0x1e0
07 ffff8080`d5bc69b0 fffff802`29b59c35     nt!IopQueueCopyWrite+0x32
08 ffff8080`d5bc6a00 fffff802`29a4c057     nt!ExpWorkerThread+0x155
09 ffff8080`d5bc6bf0 fffff802`29c32ea4     nt!PspSystemThreadStartup+0x57
0a ffff8080`d5bc6c40 00000000`00000000     nt!KiStartSystemThread+0x34
kd> !process -1 0
PROCESS ffff8582f3e9b040
    SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 001ae000  ObjectTable: ffff9a8053e8bf00  HandleCount: 3614.
    Image: System

The solution was simple, I’m now checking PFLT_CALLBACK_DATA->Thread argument to detect who actually initiated the operation (and whether or not it came from user-mode).
However I’m still curious to understand what has been changed?
Are you guys familiar with this new nt!IopQueueCopyWrite symbol? I could only find it in Win11 builds (I’m using build 25267).

Windows 10 symbols:

0: kd> x nt!IopQueue*
fffff802`5264b840 nt!IopQueueThreadIrp (void)
fffff802`526e75d4 nt!IopQueueWorkItemProlog (void)
fffff802`527158e0 nt!IopQueueIrpToFileObject (void)

Windows 11 symbols:

kd> x nt!IopQueue*
fffff802`29b81f40 nt!IopQueueInvalidateBusRelationsRequest (void)
fffff802`29ada240 nt!IopQueueThreadIrp (void)
fffff802`29ae3790 nt!IopQueueWorkItemProlog (void)
fffff802`29a159b0 nt!IopQueueIrpToFileObject (void)
fffff802`2a1b6c10 nt!IopQueueDeviceResetEvent (IopQueueDeviceResetEvent)
fffff802`29a5afb0 nt!IopQueueCopyWrite (IopQueueCopyWrite)

Why this I/O operation is performed by a System thread and not by the process that initiated it?

Thanks a lot!

What does the original (Explorer thread) stack look like in w11?

I’m surprised you didn’t see writes from the system process in Explorer, it
does not use write-through or no-buffering, so cached writes would end up
being flushed via System process even before.

Dejan.

This is the explorer thread stack in win11:

00 ffff8080`d8443d60 fffff802`29abfae3     nt!KiSwapContext+0x76
01 ffff8080`d8443ea0 fffff802`29c3951e     nt!KiDispatchInterrupt+0x863
02 ffff8080`d8443f30 fffff802`29ae3c66     nt!KiDpcInterrupt+0x38e
03 ffff8080`d84440c0 fffff802`29a36bb6     nt!ExQueueWorkItem+0x1a6
04 ffff8080`d8444120 fffff802`29aee7be     nt!IopCopyCompleteReadIrp+0x176
05 ffff8080`d84441c0 fffff802`29aed657     nt!IopfCompleteRequest+0x114e
06 ffff8080`d84442c0 fffff802`2e27ebf8     nt!IofCompleteRequest+0x17
07 ffff8080`d84442f0 fffff802`2e27e06f     Ntfs!NtfsExtendedCompleteRequestInternal+0x1a8
08 ffff8080`d8444380 fffff802`2e27bac5     Ntfs!NtfsCommonRead+0x21df
09 ffff8080`d84444e0 fffff802`29ada1f5     Ntfs!NtfsFsdRead+0x265
0a ffff8080`d8444640 fffff802`2d4b7e2b     nt!IofCallDriver+0x65
0b ffff8080`d8444680 fffff802`2d4b59ab     FLTMGR!FltpLegacyProcessingAfterPreCallbacksCompleted+0x15b
0c ffff8080`d84446f0 fffff802`29ada1f5     FLTMGR!FltpDispatch+0x15b
0d ffff8080`d8444750 fffff802`2a002180     nt!IofCallDriver+0x65
0e ffff8080`d8444790 fffff802`29eda003     nt!IopSynchronousServiceTail+0x1e0
0f ffff8080`d8444840 fffff802`29ed9114     nt!IopReadFile+0x513
10 ffff8080`d8444940 fffff802`29c45505     nt!NtCopyFileChunk+0x2f4
11 ffff8080`d8444a70 00007ffe`bcf91a44     nt!KiSystemServiceCopyEnd+0x25
12 00000000`09c1c0e8 00007ffe`ba4238b8     ntdll!NtCopyFileChunk+0x14
13 00000000`09c1c0f0 00007ffe`ba41d07d     KERNELBASE!BaseCopyStream+0x4f64
14 00000000`09c1e2c0 00007ffe`ba506e7c     KERNELBASE!BasepCopyFileExW+0x95d
15 00000000`09c1e920 00007ffe`b87cc47b     KERNELBASE!CopyFile2+0x18c
16 00000000`09c1ea10 00007ffe`b87c578e     windows_storage!CFSTransfer::_PerformCopyFileWithRetry+0x9f
17 00000000`09c1eaa0 00007ffe`b87d6322     windows_storage!CFSTransfer::CopyItem+0x1ee
18 00000000`09c1eb10 00007ffe`b86cbf45     windows_storage!CDelegatingTransfer::CopyItem+0xd2
19 00000000`09c1ebd0 00007ffe`b86bbab7     windows_storage!CCopyOperation::_CreateDestinationOrCopyItemWithRetry+0xfd
1a 00000000`09c1eca0 00007ffe`b8255064     windows_storage!CCopyOperation::Do+0x107
1b 00000000`09c1ed90 00007ffe`b825410d     windows_storage!CCopyWorkItem::_DoOperation+0x9c
1c 00000000`09c1ee60 00007ffe`b82535f4     windows_storage!CCopyWorkItem::_SetupAndPerformOp+0x2f9
1d 00000000`09c1f170 00007ffe`b824ff6c     windows_storage!CCopyWorkItem::ProcessWorkItem+0x1b8
1e 00000000`09c1f420 00007ffe`b8259642     windows_storage!CRecursiveFolderOperation::Do+0x1dc
1f 00000000`09c1f4c0 00007ffe`b8258fe7     windows_storage!CFileOperation::_EnumRootDo+0x332
20 00000000`09c1f560 00007ffe`b8250dda     windows_storage!CFileOperation::PrepareAndDoOperations+0x1cf
21 00000000`09c1f630 00007ffe`bc9f5b47     windows_storage!CFileOperation::PerformOperations+0xfa
22 00000000`09c1f680 00007ffe`bc9f47be     SHELL32!CFSDropTargetHelper::_MoveCopyHIDA+0x2b7
23 00000000`09c1f740 00007ffe`bc9f6ad6     SHELL32!CFSDropTargetHelper::_Drop+0x1fa
24 00000000`09c1fc20 00007ffe`bb2b700f     SHELL32!CFSDropTargetHelper::s_DoDropThreadProc+0x56
25 00000000`09c1fc80 00007ffe`bbbb3d2d     shcore!_WrapperThreadProc+0x10f
26 00000000`09c1fd60 00007ffe`bcf3d838     KERNEL32!BaseThreadInitThunk+0x1d
27 00000000`09c1fd90 00000000`00000000     ntdll!RtlUserThreadStart+0x28

We can see it’s the same stack as in win10 until KERNELBASE!BaseCopyStream. The change is that it calls ntdll!NtCopyFileChunk (which was added in win11 22H2) instead of KERNELBASE!WriteFile. We can see further in the stack the call to nt!ExQueueWorkItem and this explains the behavior we saw.

I don’t suppose that they have done anything sensible like poke explorer’s PETHREAD into the cbd?

See https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/km-file-copy for a description of the new mechanism.