📄 sfilter.c
字号:
DriverObject->FastIoDispatch = NULL;
ExFreePoolWithTag( fastIoDispatch, SFLT_POOL_TAG_FASTIO );
IoDeleteDevice( gSFilterControlDeviceObject );
return status;
}
//
// Attempt to attach to the appropriate RAW file system device objects
// since they are not enumerated by IoRegisterFsRegistrationChange.
//
{
PDEVICE_OBJECT rawDeviceObject;
PFILE_OBJECT fileObject;
//
// Attach to RawDisk device
//
RtlInitUnicodeString( &nameString, L"\\Device\\RawDisk" );
status = IoGetDeviceObjectPointer(
&nameString,
FILE_READ_ATTRIBUTES,
&fileObject,
&rawDeviceObject );
if (NT_SUCCESS( status )) {
SfFsNotification( rawDeviceObject, TRUE );
ObDereferenceObject( fileObject );
}
//
// Attach to the RawCdRom device
//
RtlInitUnicodeString( &nameString, L"\\Device\\RawCdRom" );
status = IoGetDeviceObjectPointer(
&nameString,
FILE_READ_ATTRIBUTES,
&fileObject,
&rawDeviceObject );
if (NT_SUCCESS( status )) {
SfFsNotification( rawDeviceObject, TRUE );
ObDereferenceObject( fileObject );
}
}
//
// Clear the initializing flag on the control device object since we
// have now successfully initialized everything.
//
ClearFlag( gSFilterControlDeviceObject->Flags, DO_DEVICE_INITIALIZING );
return STATUS_SUCCESS;
}
#if DBG && WINVER >= 0x0501
VOID
DriverUnload (
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
This routine is called when a driver can be unloaded. This performs all of
the necessary cleanup for unloading the driver from memory. Note that an
error can NOT be returned from this routine.
When a request is made to unload a driver the IO System will cache that
information and not actually call this routine until the following states
have occurred:
- All device objects which belong to this filter are at the top of their
respective attachment chains.
- All handle counts for all device objects which belong to this filter have
gone to zero.
WARNING: Microsoft does not officially support the unloading of File
System Filter Drivers. This is an example of how to unload
your driver if you would like to use it during development.
This should not be made available in production code.
Arguments:
DriverObject - Driver object for this module
Return Value:
None.
--*/
{
PSFILTER_DEVICE_EXTENSION devExt;
PFAST_IO_DISPATCH fastIoDispatch;
NTSTATUS status;
ULONG numDevices;
ULONG i;
LARGE_INTEGER interval;
# define DEVOBJ_LIST_SIZE 64
PDEVICE_OBJECT devList[DEVOBJ_LIST_SIZE];
ASSERT(DriverObject == gSFilterDriverObject);
//
// Log we are unloading.
//
SF_LOG_PRINT( SFDEBUG_DISPLAY_ATTACHMENT_NAMES,
("SFilter!DriverUnload: Unloading driver (%p)\n",
DriverObject) );
//
// Don't get anymore file system change notifications.
//
IoUnregisterFsRegistrationChange( DriverObject, SfFsNotification );
//
// Free the name buffer lookaside list.
//
ExDeletePagedLookasideList( &gSfNameBufferLookasideList );
//
// This is the loop that will go through all of the devices we are attached
// to and detach from them. Since we don't know how many there are and
// we don't want to allocate memory (because we can't return an error)
// we will free them in chunks using a local array on the stack.
//
for (;;) {
//
// Get what device objects we can for this driver. Quit if there
// are not any more. Note that this routine should always be
// defined since this routine is only compiled for Windows XP and
// later.
//
ASSERT( NULL != gSfDynamicFunctions.EnumerateDeviceObjectList );
status = (gSfDynamicFunctions.EnumerateDeviceObjectList)(
DriverObject,
devList,
sizeof(devList),
&numDevices);
if (numDevices <= 0) {
break;
}
numDevices = min( numDevices, DEVOBJ_LIST_SIZE );
//
// First go through the list and detach each of the devices.
// Our control device object does not have a DeviceExtension and
// is not attached to anything so don't detach it.
//
for (i=0; i < numDevices; i++) {
devExt = devList[i]->DeviceExtension;
if (NULL != devExt) {
IoDetachDevice( devExt->NLExtHeader.AttachedToDeviceObject );
}
}
//
// The IO Manager does not currently add a reference count to a device
// object for each outstanding IRP. This means there is no way to
// know if there are any outstanding IRPs on the given device.
// We are going to wait for a reasonable amount of time for pending
// IRPs to complete.
//
// WARNING: This does not work 100% of the time and the driver may be
// unloaded before all IRPs are completed. This can easily
// occur under stress situations and if a long lived IRP is
// pending (like opLocks and directory change notifications).
// The system will fault when this IRP actually completes.
// This is a sample of how to do this during testing. This
// is not recommended for production code.
//
interval.QuadPart = (5 * DELAY_ONE_SECOND); //delay 5 seconds
KeDelayExecutionThread( KernelMode, FALSE, &interval );
//
// Now go back through the list and delete the device objects.
//
for (i=0; i < numDevices; i++) {
//
// See if this is our control device object. If not then cleanup
// the device extension. If so then clear the global pointer
// that references it.
//
if (NULL != devList[i]->DeviceExtension) {
SfCleanupMountedDevice( devList[i] );
} else {
ASSERT(devList[i] == gSFilterControlDeviceObject);
gSFilterControlDeviceObject = NULL;
}
//
// Delete the device object, remove reference counts added by
// IoEnumerateDeviceObjectList. Note that the delete does
// not actually occur until the reference count goes to zero.
//
IoDeleteDevice( devList[i] );
ObDereferenceObject( devList[i] );
}
}
//
// Free our FastIO table
//
fastIoDispatch = DriverObject->FastIoDispatch;
DriverObject->FastIoDispatch = NULL;
ExFreePoolWithTag( fastIoDispatch, SFLT_POOL_TAG_FASTIO );
}
#endif
#if WINVER >= 0x0501
VOID
SfLoadDynamicFunctions (
VOID
)
/*++
Routine Description:
This routine tries to load the function pointers for the routines that
are not supported on all versions of the OS. These function pointers are
then stored in the global structure SpyDynamicFunctions.
This support allows for one driver to be built that will run on all
versions of the OS Windows 2000 and greater. Note that on Windows 2000,
the functionality may be limited.
Arguments:
None.
Return Value:
None.
--*/
{
UNICODE_STRING functionName;
RtlZeroMemory( &gSfDynamicFunctions, sizeof( gSfDynamicFunctions ) );
//
// For each routine that we would want to use, lookup its address in the
// kernel or HAL. If it is not present, that field in our global
// SpyDynamicFunctions structure will be set to NULL.
//
RtlInitUnicodeString( &functionName, L"FsRtlRegisterFileSystemFilterCallbacks" );
gSfDynamicFunctions.RegisterFileSystemFilterCallbacks = MmGetSystemRoutineAddress( &functionName );
RtlInitUnicodeString( &functionName, L"IoAttachDeviceToDeviceStackSafe" );
gSfDynamicFunctions.AttachDeviceToDeviceStackSafe = MmGetSystemRoutineAddress( &functionName );
RtlInitUnicodeString( &functionName, L"IoEnumerateDeviceObjectList" );
gSfDynamicFunctions.EnumerateDeviceObjectList = MmGetSystemRoutineAddress( &functionName );
RtlInitUnicodeString( &functionName, L"IoGetLowerDeviceObject" );
gSfDynamicFunctions.GetLowerDeviceObject = MmGetSystemRoutineAddress( &functionName );
RtlInitUnicodeString( &functionName, L"IoGetDeviceAttachmentBaseRef" );
gSfDynamicFunctions.GetDeviceAttachmentBaseRef = MmGetSystemRoutineAddress( &functionName );
RtlInitUnicodeString( &functionName, L"IoGetDiskDeviceObject" );
gSfDynamicFunctions.GetDiskDeviceObject = MmGetSystemRoutineAddress( &functionName );
RtlInitUnicodeString( &functionName, L"IoGetAttachedDeviceReference" );
gSfDynamicFunctions.GetAttachedDeviceReference = MmGetSystemRoutineAddress( &functionName );
RtlInitUnicodeString( &functionName, L"RtlGetVersion" );
gSfDynamicFunctions.GetVersion = MmGetSystemRoutineAddress( &functionName );
}
VOID
SfGetCurrentVersion (
VOID
)
/*++
Routine Description:
This routine reads the current OS version using the correct routine based
on what routine is available.
Arguments:
None.
Return Value:
None.
--*/
{
if (NULL != gSfDynamicFunctions.GetVersion) {
RTL_OSVERSIONINFOW versionInfo;
NTSTATUS status;
//
// VERSION NOTE: RtlGetVersion does a bit more than we need, but
// we are using it if it is available to show how to use it. It
// is available on Windows XP and later. RtlGetVersion and
// RtlVerifyVersionInfo (both documented in the IFS Kit docs) allow
// you to make correct choices when you need to change logic based
// on the current OS executing your code.
//
versionInfo.dwOSVersionInfoSize = sizeof( RTL_OSVERSIONINFOW );
status = (gSfDynamicFunctions.GetVersion)( &versionInfo );
ASSERT( NT_SUCCESS( status ) );
gSfOsMajorVersion = versionInfo.dwMajorVersion;
gSfOsMinorVersion = versionInfo.dwMinorVersion;
} else {
PsGetVersion( &gSfOsMajorVersion,
&gSfOsMinorVersion,
NULL,
NULL );
}
}
#endif
VOID
SfFsNotification (
IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN FsActive
)
/*++
Routine Description:
This routine is invoked whenever a file system has either registered or
unregistered itself as an active file system.
For the former case, this routine creates a device object and attaches it
to the specified file system's device object. This allows this driver
to filter all requests to that file system. Specifically we are looking
for MOUNT requests so we can attach to newly mounted volumes.
For the latter case, this file system's device object is located,
detached, and deleted. This removes this file system as a filter for
the specified file system.
Arguments:
DeviceObject - Pointer to the file system's device object.
FsActive - Boolean indicating whether the file system has registered
(TRUE) or unregistered (FALSE) itself as an active file system.
Return Value:
None.
--*/
{
PNAME_CONTROL devName;
PAGED_CODE();
//
// Display the names of all the file system we are notified of
//
devName = NLGetAndAllocateObjectName( DeviceObject,
&gSfNameBufferLookasideList );
if (devName == NULL) {
SF_LOG_PRINT( SFDEBUG_DISPLAY_ATTACHMENT_NAMES,
("SFilter!SfFsNotification: Not attaching to %p, insufficient resources.\n",
DeviceObject) );
return;
}
SF_LOG_PRINT( SFDEBUG_DISPLAY_ATTACHMENT_NAMES,
("SFilter!SfFsNotification: %s %p \"%wZ\" (%s)\n",
(FsActive) ? "Activating file system " : "Deactivating file system",
DeviceObject,
&devName->Name,
GET_DEVICE_TYPE_NAME(DeviceObject->DeviceType)) );
//
// Handle attaching/detaching from the given file system.
//
if (FsActive) {
SfAttachToFileSystemDevice( DeviceObject, devName );
} else {
SfDetachFromFileSystemDevice( DeviceObject );
}
//
// We're done with name (SfAttachToFileSystemDevice copies the name to
// the device extension) so free it.
//
NLFreeNameControl( devName, &gSfNameBufferLookasideList );
}
/////////////////////////////////////////////////////////////////////////////
//
// IRP Handling Routines
//
/////////////////////////////////////////////////////////////////////////////
NTSTATUS
SfPassThrough (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the main dispatch routine for the general purpose file
system driver. It simply passes requests onto the next driver in the
stack, which is presumably a disk file system.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -