This tutorial provides you with easy to understand steps for a simple file system filter driver development. As a result, obtained demo driver is intended to print names of open files to debug output.
This article would be interesting for developers with basic Windows driver experience as well as C/C++ knowledge. In addition, it could be also useful to people without Windows driver development deep understanding.
Leader of Driver Team
Windows file system filter driver is called during each file system I/O operation (create, read, write, rename, etc.). Therefore, it is able to modify behavior of file system. File system filter drivers are comparable to legacy drivers, although they require several special development steps. Security, backup and snapshot software, as well as anti-viruses use such drivers.
First, in order to develop a file system filter driver, you need WDK or IFS Kit from the Microsoft website to build any file system filter driver. You also have to set the %WINDDK% environment variable to the path, where you have installed WDK/IFS Kit.
Attention: Even the smallest error in file system driver can cause BSOD or instability of the system.
It is an access point of any driver, including file system filter one. The first thing we should do is storing
DriverObject as a global variable (we'll use it later).
The next step of developing file system filter driver is populating the IRP dispatch table with function pointers to IRP handlers. We have a generic pass-through IRP handler (it sends request further) in our filter driver. We will also need a handler for
IRP_MJ_CREATE to retrieve names of the open files. IRP handlers implementation will be considered later.
File system filter driver requires fast-IO dispatch table. Not setting it up would lead to crash of the system. Fast- IO is a different way to initiate I/O operations (by the way, faster than IRP). Fast- IO operations are always synchronous. If fast- IO handler returns FALSE, then we cannot use fast- IO way. In this case, IRP will be created.
While developing file system filter driver, we should register a notification about file system changes. It is crucial to track if file system is being activated or deactivated to perform attaching/detaching of our file system filter driver. Below you can see the way of tracking file system changes.
The final part of the file system driver initialization is setting an unload routine. It will help you to load or unload file system filter driver multiple times without need to restart OS. Nonetheless, this driver becomes unloadable just for debugging purposes, because it is impossible to unload file system filters in a safe way. It is not recommended to perform it in production code.
Driver unload routine cleans up resources and deallocates them. The next step of file system driver development is unregistering the notification for file system changes.
After doing that, you should loop through created devices, detach, and remove them. Then wait for 5 seconds until all outstanding IRPs are completed. Notice that it is a debug only solution. It works for the greater number of cases, but there is no guarantee for all of them.
The only responsibility of this IRP handler is to pass requests further to next driver. Next driver object is stored in our device extension.
Every file create operation invokes this IRP handler. After grabbing a filename from
PFILE_OBJECT, we print it to debug output. After that, we call the pass-through handler, which we have described above. Notice that a valid file name exists in
PFILE_OBJECT only until the file create operation is finished! There also exist relative opens as well as opens by id. In third-party resources, you can find more details about file names retrieving in those cases.
As not all of the fast-IO routines should be implemented by the underlying file system, we have to test the fast-IO dispatch table validity for the next driver, using the following macro:
Unlike IRP requests, passing through fast-IO requests requires a huge amount of code, because there is its own set of parameters for each fast-IO function. Below you can find a common pass-through function example:
That is a specific fast-IO request, which we should handle ourselves without calling next driver. We should delete our filter device after detaching it from file system device stack. Below you can find code example demonstrating the way to easily manage it:
Common file system consists of control device and volume ones. Volume devices are attached to the storage device stack. Control device is registered as a file system.
Figure 1 - Common file system devices
There is a callback that is being invoked for all active file systems each time file system has earlier registered or unregistered itself as active one. It is a great place for attaching or detaching our file system filter device. When file system activates itself, we are attaching to its control device (in case if we are not already attached), enumerating its volume devices and attaching to them too. While deactivating file system, we examine its control device stack, find our device, and detach it. Detaching from file system volume devices is performed in FsFilterFastIoDetachDevice routine, which was described earlier.
This file contains helper routines for attaching, detaching, and checking if our filter is already attached.
In order to perform attaching, we should call
IoCreateDevice to create new device object with device extension, and then propagate device object flags from the device object we are trying to attach to (
DO_BUFFERED_IO, DO_DIRECT_IO, FILE_DEVICE_SECURE_OPEN). Then we call
IoAttachDeviceToDeviceStackSafe in a loop with delay in the case of failure. Our attachment request can fail, as the device object has not finished initialization. It can happen if we try to mount the volume only filter. After attaching, we save “attached to” device object to the device extension and clear
DO_DEVICE_INITIALIZING flag. Below you can see the device extension:
Detaching is rather simple. From the device extension, we get the device, we attached to, and call IoDetachDevice and IoDeleteDevice.
In order to check if we are attached to a device or not, we have to iterate through the device stack using IoGetAttachedDeviceReference and
IoGetLowerDeviceObject, and then look for our device there. We can differentiate our devices by comparing device driver object with our driver one (
The utility, which builds the driver, uses sources and makefile files. These files contain project settings and source file names.
Content of the sources file:
TARGETNAME = FsFilter TARGETPATH = obj TARGETTYPE = DRIVER DRIVERTYPE = FS SOURCES = \ Main.c \ IrpDispatch.c \ AttachDetach.c \ Notification.c \ FastIo.c
The makefile is standard:
MSVC makefile project build command line is:
call $(WINDDK)\bin\setenv.bat $(WINDDK) chk wxp cd /d $(ProjectDir) build.exe –I
We will use sc.exe (sc – service control) to manage our driver. We can use this command-line utility to query or modify the installed services database. It is shipped with Windows XP and higher, or you can find it in Windows SDK/DDK.
To install the file system filter driver, call:
sc create FsFilter type= filesys binPath= c:\FSFilter.sys
Thus, there will be created a new service entry with the
FsFilter name, its service type is filesystem and binary path is c:\FsFilter.sys.
To start file system filter driver, call:
sc start FsFilter
FsFilter service will be started.
To stop the file system filter driver, call:
sc stop FsFilter
FsFilter service will be stopped.
In order to uninstall file system filter driver, call:
sc delete FsFilter
This command instructs service manager to remove service entry with the
Put all those commands into a single batch file to make driver testing easier. Below there is a listing of Install.cmd command file:
sc create FsFilter type= filesys binPath= c:\FsFilter.sys sc start FsFilter pause sc stop FsFilter sc delete FsFilter pause
This part of the article is the most interesting and demonstrative. Now we are going to show how the file system filter works. For this purpose, we will use Sysinternals DebugView for Windows to monitor debug output as well as OSR Device Tree to overview devices and drivers.
First, let’s build the driver. After that, copy obtained FsFilter.sys file and Install.cmd script to the root of the C disk.
Figure 2 – File system filter driver and the install script on the C disk.
Run Install.cmd, which installs and starts the file system driver, and then waits for user input.
Figure 3 - The file system filter driver is successfully installed and started.
Now we should start the DebugView utility.
Figure 4 - Debug output monitoring.
Now we can see what files were opened! It means that our filter works. Now we should run the device tree utility and locate our driver there.
Figure 5 - Our filter driver in the device tree.
There are various devices created by our driver. Let’s open the NTFS driver and consider the device tree:
Figure 6 - Our filter is attached to NTFS.
We are attached now. Let’s consider other file systems.
Figure 7 - Our filter is also attached to other file systems.
Finally, press any key to continue our install script, so it could stop and uninstall the driver.
Figure 8 - Our file system filter driver is stopped and uninstalled.
Press F5 to refresh the device tree list:
Figure 9 - Our filter devices are no longer in the device tree.
Our file system filter disappeared and the system is running just as before.
The file system filter driver described above is very simple, it lacks a number of functions, required for a common driver. The idea of this article was to show the easiest way to create file system filter driver, that’s why we described simple and easy-to-understand development process. You can write
IRP_MJ_FILE_SYSTEM_CONTROL handler of your own to track the newly arrived volumes.
Our tutorial provides you with simple steps for simple file system filter driver development. It shows how to install, start, stop, and uninstall it using a command line. Other file system filter driver issues are also discussed there. We considered file system device stack with attached filters and learned the way to monitor debug output from the driver. You can use the sources of this article as a skeleton for your own file system filter driver, and if needed modify its behavior according to your needs.
- File System Filter Drivers
- Content for File System or File System Filter Developers
- Windows NT File System Internals (OSR Classic Reprints) (Paperback)
- sfilter DDK sample
Download source files of the sample project.
Ready to hire experienced driver development team to work on your project like file system filter driver development? Just contact us and we will provide you all details!