FileSpy Project
User Guide
Last updated: April 6, 2001
FileSpy is a tool that aids Installable File System (IFS) filter driver writers in understanding the I/O that is occurring in the system. It allows the user to monitor both local and network drives to see what types of IRP and Fast I/O operation are executing in the system.
FileSpy was also developed as a useful example of how to write an IFS filter driver. This driver sits in the I/O stack and records the relevant information for the I/O operations that are happening, such as the starting time, the completion time, return status, etc. The filter driver was developed using the sfilter example code as a base, so you should see some similarity in their structure. The main differences between these two example filters are:
1. The sfilter example consists of only a kernel mode driver. FileSpy has both user mode and kernel mode components. The kernel mode driver watches and records the meaningful I/O activity and then passes up to the user mode application when data is requests. The user mode application then displays this data to the user through the screen or by writing the log data to a file.
2. Sfilter connects to all devices in the system as soon as the device is created and stay connected for as long as the system is running. FileSpy connects to a device only when directed to by the user application or through a parameter in the registry. It disconnects from the device when told to do so by the I/O Manager. Do to the design of the I/O architecture, the user cannot directly tell the FileSpy driver to detach from the device. When the kernel driver receives the command to disconnect, it just stops logging information for that device. FileSpy can only truly detach from a device when commanded to do so by the I/O Manager.
3. Sfilter doesn’t actually do anything – it just shows a driver writer how to hook into all the possible places to watch IRP and Fast I/O communication. FileSpy logs the I/O communication traffic in the system while trying to minimize its affect on the performance of the system. The user application works with the kernel mode driver to display the I/O traffic to the user.
The FileSpy project can be broken down into four components:
1. Kernel-mode filter driver, FileSpy.sys
2. User-mode application, FileSpy.exe
3. Install method, FileSpy.inf
The kernel-mode filter driver is responsible for monitoring all the activity in the I/O subsystem and recording information on the activity along the IRP and Fast I/O paths for specified devices. The filter driver maintains a list of log records for each of the I/O operations it sees and then, at the request of the user application, passes the log data up to the user application.
The filter driver consists of the following files:
FileSpy.h |
Contains all the structures, types and constant definitions that are shared between the kernel mode driver, FileSpy.sys, and the user mode executable, FileSpy.exe. |
FspyKern.h |
Contains all the structures, types, constants, global variables, and function prototypes that are only visible within the kernel mode driver. |
FileSpy.c |
Contains the implementation for the driver entry point and all the callback routines this driver registers so that it is notified of I/O activity while the system is running. |
FSpyLib.c |
Contains the implementation for the FileSpy helper routines. The routines provide the functionality of: · Attaching to a device · Detaching from a device · Listing all the devices we are currently monitoring · Manage the cache of filenames we keep while the system is monitoring I/O activity. · Create, pass up and delete log records containing relevant information on the I/O activity seen. |
makefile, |
Files used to tell the build tool how to create FileSpy.sys. |
params.txt |
Input file for regini.exe to set the registry settings appropriately for communicating application parameters to the kernel mode driver. |
The user-mode application is responsible for controlling the kernel-mode filter driver and translating the log records that are returned by the driver to the user in a human-readable way (either to the screen or to a file). The user application uses a simple command shell to allow the user to communicate he/her directions to the driver.
The user application consists of the following files:
fSpyLog.h |
Contains the structures, prototypes and constant definitions that are visible only to the user application. |
fSpyLog.c |
Contains the implementation for retrieving the log records from the kernel driver and displaying the log records to the user either through the screen or through a file. |
FSpyUser.c |
Contains the implementation for the main function of the user application that opens the FileSpy device, starts up the thread that continually queries the kernel mode driver for new log records, and interprets the user’s commands to the application. |
makefile, |
Files used to tell the build tool how to create FileSpy.exe. |
To run the user application:
· Build the user application’s executable, FileSpy.exe.
· The application has to modes, running mode and command mode. In running mode, the application prints any log output that it has collected to the screen if it is supposed to be outputting information to the screen. In command mode, the user is able to direct the behavior of the kernel driver through a series of command switches defined below. When the application begins, it is in running mode. To change to command mode when currently in running mode, hit Enter. A > prompt should appear to signify the application is in command mode.
· The following commands are available at the command line or in command mode.
/a <drive> |
Attaches monitor to <drive>, where <drive> is a valid drive letter in the system (e.g., C:). |
/d <drive> |
Detaches monitor to <drive>, where <drive> is a valid drive letter in the system (e.g., C:) that the monitor has previously attached to. |
Note: The monitor may not truly detach from the device when it receives the /d command because a filter driver can only detach from a device when it can guarantee that it is on the top of the I/O stack. This is only going to occur when the filter driver receives the detach command from the I/O Manager. When the user application tells the kernel driver to detach from a device, the kernel monitor stops logging the data for that device. Also note: Shutting down the user application does not cause the kernel monitor to detach from all the drives. The kernel driver will stop logging the I/O operations that it is seeing, but if the user restarts the user application, the kernel monitor will continue logging to the devices that it was attached to when the user application last stopped. The kernel driver will only reset these attachments to system devices when the system is rebooted. |
|
/h |
Lists statistics on hash table used to store file names. |
/l |
Lists all the drives that the kernel driver is monitoring. |
/s |
Toggles on and off showing the logging output to the screen. When the application is started, the default behavior is to show logging output to the screen. |
/f [<filename>] |
Toggles on and off writing the logging output to a file. If issuing the /f command will toggle on writing output to a file, the required <filename> specifies the output file name. If the /f command will toggle off the writing output to a file, the <filename> is ignored and not required. By default, the logging output is not stored to a file. |
go|g |
Exits the user from command mode and will allow the user application to show logging output on the screen again if the program is set to do so. |
Exit |
Shuts down the user application. |
The logging information that is output either to the screen and/or to a file (as specified by the user commands) is the same. (Note: We do log different information for I/O operations along the Irp path versus I/O operations along the Fast I/O path.) The only difference is that the fields are tab-delimited when writing to file to make the data easier to analyze. The data written to the screen has been compacted to make it easier to read (although you still want your Command Window to be extra wide).
If the memory limit is hit when logging I/O operations, a message saying that the system is out of memory will appear in the log. The user can see how many I/O operations were not logged by looking at the sequence numbers of the log records once the memory pressure has been relieved.
The exact format of the data output in each case is described below:
These fields appear from left to right, across the screen.
I |
Designates that this is an I/O operation along the Irp path. |
Sequence Number |
The sequence number for this operation. |
Originating Time |
The time this I/O operation began. |
Completion Time |
The time this I/O operation ended. |
Processes Id and Thread Id |
The process and thread id for the thread that originated this I/O operation. These values are in processId.threaded format. |
Irp Major Code and Irp Minor Code Names |
The name of the Irp major code for this operation. The name of the Irp minor code for this operation, if there is one (the screen display has this on a separate line). |
DeviceObject |
The pointer value representing the Device Object for this operation. |
FileObject |
The pointer value representing the File Object for this operation. |
Return Status and Information |
The numeric values for both the return status and return Information fields (look in ntstatus.h to see the description for the return value). These values are in the status:information format. |
Irp Flags |
The numeric value for the Irp flags |
Interpretation of Common Irp flags |
Four columns with either a letter or a “-“ to designate different Irp flags being set; N – NoCache flag was set P – Paging IO flag was set S – Synchronous Api flag was set Y – Synchronous Paging IO flag was set |
Name |
If available, the name of the file. |
These fields appear from left to right, across the screen.
F |
Designates that this is an I/O operation along the FastIO path. |
Sequence Number |
The sequence number for this operation. |
Originating Time |
The time this I/O operation began. |
Completion Time |
The time this I/O operation ended. |
Processes Id and Thread Id |
The process and thread id for the thread that originated this I/O operation. These values are shown in the format processId.threadId. |
Fast I/O Operation Name |
The name type of Fast I/O operation. |
DeviceObject |
If available, the pointer value representing the Device Object for this operation. |
FileObject |
If available, the pointer value representing the File Object for this operation. |
Return Status |
The numeric value for the return status for this operation (look in ntstatus.h to see the description for the return value). |
Wait |
If available, “T” if this Fast I/O operation was called with the Wait parameter set to TRUE, and “F” if the wait parameter was set to FALSE. |
Length |
If available, the number of bytes in the operation. |
File Offset |
If available, the offset into the file for this operation. |
Name |
If available, the name of the file. |
These fields appear from left to right, across the screen.
O |
Designates that this is an operation along the FsFilter Operation path. |
Sequence Number |
The sequence number for this operation. |
Originating Time |
The time this I/O operation began. |
Completion Time |
The time this I/O operation ended. |
Processes Id and Thread Id |
The process and thread id for the thread that originated this I/O operation. These values are shown in the format processId.threadId. |
FsFilter Operation Name |
The name type of FsFilter operation. |
DeviceObject |
If available, the pointer value representing the Device Object for this operation. |
FileObject |
If available, the pointer value representing the File Object for this operation. |
Return Status |
The numeric value for the return status for this operation (look in ntstatus.h to see the description for the return value). |
Name |
If available, the name of the file. |
FileSpy now comes with an INF that will install the filter driver and the user mode control program. To install, do the following:
This will make the necessary registry updates to register the FileSpy service, place filespy.sys in the %SystemRoot%\system32\drivers directory, place filespy.exe in %SystemRoot%\filespy directory and add the following registry entries:
[HKEY_LOCAL_MACHINE]\System\CurrentControlSet\Services\FileSpy
MaxRecords |
DWORD |
The maximum number of log records to have outstanding at any one time. Default=500. |
MaxNames |
DWORD |
The maximum number of name buffers to have outstanding at any one time. Default=500. |
AttachMode |
DWORD |
Specify how you want FileSpy to attach to volumes. 1. Attach on demand. 2. Attach to ALL volumes when the filter loads. This does not mean that volumes are being logged, that happens when a user explicitly requests it. This is used to control attachment order with other filters. Default=2 |
To uninstall the kernel-mode driver for FileSpy, you need to run “sc delete filespy”. This will remove the service from the system. After running this program, you will need to reboot the machine to complete the removal of FileSpy.