📄 sfilter.c
字号:
fsFilterCallbacks.PreAcquireForModifiedPageWriter = SfPreFsFilterPassThrough;
fsFilterCallbacks.PostAcquireForModifiedPageWriter = SfPostFsFilterPassThrough;
fsFilterCallbacks.PreReleaseForModifiedPageWriter = SfPreFsFilterPassThrough;
fsFilterCallbacks.PostReleaseForModifiedPageWriter = SfPostFsFilterPassThrough;
status = (gSfDynamicFunctions.RegisterFileSystemFilterCallbacks)( DriverObject,
&fsFilterCallbacks );
if (!NT_SUCCESS( status )) {
DriverObject->FastIoDispatch = NULL;
ExFreePoolWithTag( fastIoDispatch, SFLT_POOL_TAG_FASTIO );
IoDeleteDevice( gSFilterControlDeviceObject );
return status;
}
}
}
#endif
// 当一个新的文件系统被装入或者当任何文件系统被卸载时,注册的回调函数
// SfFsNotification将被调用
// The registered callback routine "SfFsNotification" will be called
// whenever a new file systems is loaded or when any file system is
// unloaded.
//
// VERSION NOTE:
//
// On Windows XP and later this will also enumerate all existing file
// systems (except the RAW file systems). On Windows 2000 this does not
// enumerate the file systems that were loaded before this filter was
// loaded.
//
status = IoRegisterFsRegistrationChange( DriverObject, SfFsNotification );
if (!NT_SUCCESS( status )) {
KdPrint(( "SFilter!DriverEntry: Error registering FS change notification, status=%08x\n",
status ));
DriverObject->FastIoDispatch = NULL;
ExFreePoolWithTag( fastIoDispatch, SFLT_POOL_TAG_FASTIO );
IoDeleteDevice( gSFilterControlDeviceObject );
return status;
}
// 试图附着到合适的RAW文件系统设备对象,因为他们没有被IoRegisterFsRegistrationChange枚举
// Attempt to attach to the appropriate RAW file system device objects
// since they are not enumerated by IoRegisterFsRegistrationChange.
//
{
PDEVICE_OBJECT rawDeviceObject;
PFILE_OBJECT fileObject;
// 附着到RawDisk设备
// 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 );
}
// 附着到RawCdRom设备
// 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.
// 当发出卸载一个驱动请求,IO系统将缓冲那个信息且不真正调用这个例程直到下面状态发生:
- 所有属于这个过滤的设备对象在他们各自附着链的顶部
- 所有设备对象的句柄计数已经成为0
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 (;;) {
// 为这个驱动得到设备对象。如果没有了,就退出。注意这个例程应该被定义
// 因为这个例程仅为Windows XP及以后的OS编译。
// 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 );
// 首先遍历列表且断开每个设备。我们的控制设备对象没有DeviceExtension
// 且未附着到任何事情,因此不断开它。
// 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 );
}
}
// IO Manager当前不为每个未处理的IRPs增加设备对象的引用计数。这意味着无法知道
// 给定设备是否存在未处理的IRPs.我们将等待合理的时间完成这些IRPs。
// 象opLocks和目录改变通知的重负荷系统,可能发生问题
// 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;
}
// 删除设备对象,删除由IoEnumerateDeviceObjectList增加的引用计数。
// 注意删除直到引用计数降到0时才真正发生
// 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] );
}
}
// 释放我们的FastIO表
// Free our FastIO table
//
fastIoDispatch = DriverObject->FastIoDispatch;
DriverObject->FastIoDispatch = NULL;
ExFreePoolWithTag( fastIoDispatch, SFLT_POOL_TAG_FASTIO );
ExDeletePagedLookasideList(&gFsCtxLookAsideList);
ExDeletePagedLookasideList(&gFileContextLookAsideList);
ExDeletePagedLookasideList(&gFileNameLookAsideList);
ExDeleteNPagedLookasideList(&gReadWriteCompletionCtxLookAsideList);
ZwClose(gRuleFileHandle);
ExDeleteResourceLite(&gRulesResource);
if (gRules)
ExFreePoolWithTag(gRules, SFLT_POOL_TAG_MYSELF);
}
#endif
#if WINVER >= 0x0501
VOID
SfLoadDynamicFunctions (
VOID
)
/*++
Routine Description:
试图载入不是所有操作系统都支持的例程的函数指针。这些函数指针然后被存储于全局结构SpyDynamicFunctions中
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 ) );
// 对于每个我们想使用的例程,在kernel或HAL中查找他的地址。
// 如果不存在,在我们的SpyDynamicFunctions结构中的那个字段将被设置为NULL。
// 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:
基于可用的正确的例程读当前的OS版本
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;
// RtlGetVersion执行多于我们需要的事情,但如果可用我们使用它以显示如何使用它。
// RtlGetVersion和RtlVerifyVersionInfo允许我们当基于当前OS执行你的代码时执行正确的选择
// 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.
// 对于前者,这个历程创建一个设备对象且附着它到指定文件系统的设备对象。
// 这允许这个驱动过滤到那个文件系统的所有请求
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -