In my previous posts about Stuxnet, I talked about the FileSystem Filter functionality of the Rootkit. I covered the idea of an “IO Request Packet” or IRP for short. IRPs are the general way for drivers to pass data to the lower layers in their device stacks. Filesystems often write to relatively slow backing stores (such as hard disks). To get an idea of the difference in timescale we are talking about, CPUs often operate in the microsecond domain, while hard disks operate in the millisecond domain. Due to this time scale difference, the Windows Engineers decided to provide an optimized I/O mechanism to write to such slow storage mediums. This caching mechanism is implemented in the Windows Cache Manager, and the FastIO infrastructure is the way to take advantage of it from a driver.
FastIO can be thought of as logically parallel to the IRP infrastructure in Windows, but with higher performance. Instead of waiting for each IRP to get to the disk, FastIO interacts with the Windows Cache Manager. The windows cache manager stores an in-memory cache of frequently accessed data on the disk (See chapters 9 and 10 of Windows Internals 5th edition by Mark Russinovich and David Solomon). This increases performance because on a cache lookup, the memory is hit (which has no moving parts and is fast) rather than the disk being hit (which has to seek to the correct sector, thereby incurring the cost of mechanical slowness). In addition to the disk not being hit on a read/write, FastIO also allows us to avoid the overhead incurred in synthesizing new IRPs to pass down the device stack.
The FastIO infrastructure is brought together by the FAST_IO_DISPATCH structure, which can be seen in wdm.h in the Windows Driver Development Kit. In the Rootkits book by Hoglund and Butler, they describe this structure as beginning with a size field, and containing all the function pointers for the FastIO functions supported by the driver. When attempting to call a FastIO function, the system first has to figure out whether or not the device in question supports FastIO. As a fallback, if the device does not support FastIO, an IRP is created and sent down the device stack.
I followed the Experiment in Windows Internals 4th Edition:
kd> !drvobj \filesystem\ntfs 2 Driver object (81fd0cc0) is for: \FileSystem\Ntfs DriverEntry: f847c680 Ntfs!DriverEntry DriverStartIo: 00000000 DriverUnload: 00000000 AddDevice: 00000000
Dispatch routines:  IRP_MJ_CREATE f841c200 Ntfs!NtfsFsdCreate  IRP_MJ_CREATE_NAMED_PIPE 804f2529 nt!IopInvalidDeviceRequest  IRP_MJ_CLOSE f841cda5 Ntfs!NtfsFsdClose  IRP_MJ_READ f8402687 Ntfs!NtfsFsdRead  IRP_MJ_WRITE f8403428 Ntfs!NtfsFsdWrite  IRP_MJ_QUERY_INFORMATION f841e53f Ntfs!NtfsFsdDispatchWait  IRP_MJ_SET_INFORMATION f84040b1 Ntfs!NtfsFsdSetInformation  IRP_MJ_QUERY_EA f841e53f Ntfs!NtfsFsdDispatchWait  IRP_MJ_SET_EA f841e53f Ntfs!NtfsFsdDispatchWait  IRP_MJ_FLUSH_BUFFERS f842da23 Ntfs!NtfsFsdFlushBuffers [0a] IRP_MJ_QUERY_VOLUME_INFORMATION f841d4e2 Ntfs!NtfsFsdDispatch [0b] IRP_MJ_SET_VOLUME_INFORMATION f841d4e2 Ntfs!NtfsFsdDispatch [0c] IRP_MJ_DIRECTORY_CONTROL f8422595 Ntfs!NtfsFsdDirectoryControl [0d] IRP_MJ_FILE_SYSTEM_CONTROL f84218d4 Ntfs!NtfsFsdFileSystemControl [0e] IRP_MJ_DEVICE_CONTROL f841d4e2 Ntfs!NtfsFsdDispatch [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL 804f2529 nt!IopInvalidDeviceRequest  IRP_MJ_SHUTDOWN f8414476 Ntfs!NtfsFsdShutdown  IRP_MJ_LOCK_CONTROL f84329e3 Ntfs!NtfsFsdLockControl  IRP_MJ_CLEANUP f841c4da Ntfs!NtfsFsdCleanup  IRP_MJ_CREATE_MAILSLOT 804f2529 nt!IopInvalidDeviceRequest  IRP_MJ_QUERY_SECURITY f841d4e2 Ntfs!NtfsFsdDispatch  IRP_MJ_SET_SECURITY f841d4e2 Ntfs!NtfsFsdDispatch  IRP_MJ_POWER 804f2529 nt!IopInvalidDeviceRequest  IRP_MJ_SYSTEM_CONTROL 804f2529 nt!IopInvalidDeviceRequest  IRP_MJ_DEVICE_CHANGE 804f2529 nt!IopInvalidDeviceRequest  IRP_MJ_QUERY_QUOTA f841e53f Ntfs!NtfsFsdDispatchWait [1a] IRP_MJ_SET_QUOTA f841e53f Ntfs!NtfsFsdDispatchWait [1b] IRP_MJ_PNP f846b3fc Ntfs!NtfsFsdPnp
Fast I/O routines: FastIoCheckIfPossible f8432bbb Ntfs!NtfsFastIoCheckIfPossible FastIoRead f841f4ce Ntfs!NtfsCopyReadA FastIoWrite f842f898 Ntfs!NtfsCopyWriteA FastIoQueryBasicInfo f8424db0 Ntfs!NtfsFastQueryBasicInfo FastIoQueryStandardInfo f8424c14 Ntfs!NtfsFastQueryStdInfo FastIoLock f8432e66 Ntfs!NtfsFastLock FastIoUnlockSingle f8432f26 Ntfs!NtfsFastUnlockSingle FastIoUnlockAll f84691b9 Ntfs!NtfsFastUnlockAll FastIoUnlockAllByKey f84692fd Ntfs!NtfsFastUnlockAllByKey AcquireFileForNtCreateSection f841d6f4 Ntfs!NtfsAcquireForCreateSection ReleaseFileForNtCreateSection f841d721 Ntfs!NtfsReleaseForCreateSection FastIoQueryNetworkOpenInfo f842ffc6 Ntfs!NtfsFastQueryNetworkOpenInfo AcquireForModWrite f846e918 Ntfs!NtfsAcquireFileForModWrite MdlRead f8430233 Ntfs!NtfsMdlReadA MdlReadComplete 8051e58f nt!FsRtlMdlReadCompleteDev PrepareMdlWrite f842f36d Ntfs!NtfsPrepareMdlWriteA MdlWriteComplete 805f28aa nt!FsRtlMdlWriteCompleteDev FastIoQueryOpen f8424ec5 Ntfs!NtfsNetworkOpenCreate AcquireForCcFlush f841d3db Ntfs!NtfsAcquireFileForCcFlush ReleaseForCcFlush f841d39c Ntfs!NtfsReleaseFileForCcFlush
As we can see in the section titled ” Fast I/O routines”, the NTFS drivers uses most of the FastIO functions. To learn more about the specific FastIO functions, check out:
By: Neil Sikka