首先声明本帖首发于赏金论坛,希望大家能多多关注这个正在成长的论坛www.sgoldcn.com
看了很久的文件系统过滤驱动相关教程,但一直抓不住过滤驱动代码的大框架,一直在过滤驱动的代码中找不到北。偶然看到了一篇英文版教程,读后豁然开朗,学习的过程中记录了以下文字,拿出来与大家分享。
感谢作者,原作地址(http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx)
代码是那篇英文教程的,代码注释换成了我自己的理解。这些代码忽略掉了请多细节,非常有助于快速掌握过滤驱动框架,不会像读sfilter那样拘泥于细节而找不着北,在掌握了整个框架之后再去读sfilter是个不错的选择。
简洁的文件系统过滤驱动框架:
1. DriverEntry中设置初始化例程、卸载例程、需要过滤的IRP例程、快速IO例程,完成卸载例程。最重要的是最后一步:注册文件系统变更消息例程。
2. 完成文件系统变更消息例程,其中需要完成挂载设备与解挂载设备的例程。挂载时需要枚举当前文件系统中已经存在的卷设备并也将自身挂载到他们之上。
3. 处理IRP例程。包括普通IRP例程与快速IO例程。
开始编写:
1. 在DriverEntry中设置IRP例程,注册系统变更消息例程、卸载例程等。这里暂时只处理IRP_MJ_CREATE,在FsFilterDispatchCreate只打印出路径信息。
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING pRegistryPath
)
{
NTSTATUS status = STATUS_SUCCESS;
int i = 0;
//保存驱动对象到全局变量
g_FsFilterDriverObject = DriverObject;
//初始化例程
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverObject->MajorFunction = FsFilterDispatchPassThrough;
}
//卸载例程
DriverObject->DriverUnload = FsFilterUnload;
//在这个Demo里,只过滤IRP_MJ_CREATE
DriverObject->MajorFunction[IRP_MJ_CREATE] = FsFilterDispatchCreate;
//FastIO分发函数
DriverObject->FastIoDispatch = &g_fastIoDispatch;
//注册文件系统变更消息例程
status = IoRegisterFsRegistrationChange(DriverObject,FsFilterNotificationCallback);
if (!NT_SUCCESS(status))
{
KdPrint(("IoRegisterFsRegistrationChange Error!"));
return status;
}
return STATUS_SUCCESS;
}
VOID FsFilterUnload(
IN PDRIVER_OBJECT DriverObject)
{
ULONG numDevices = 0;
ULONG i = 0;
LARGE_INTEGER interval;
PDEVICE_OBJECT devList[DEVOBJ_LIST_SIZE];
interval.QuadPart = (5 * DELAY_ONE_SECOND);
//注销系统变更例程
IoUnregisterFsRegistrationChange(DriverObject,FsFilterNotificationCallback);
//循环Detach所有设备并删除
for (;;)
{
IoEnumerateDeviceObjectList(DriverObject,devList,sizeof(devList),&numDevices);
if (0 == numDevices)
break;
numDevices = min(numDevices,RTL_NUMBER_OF(devList));
for (i = 0; i < numDevices; i++)
{
//Detach并删除设备
FsFilterDetachFromDevice(devList);
ObDereferenceObject(devList);
}
//延时5秒,保证所有IRP都完成
KeDelayExecutionThread(KernelMode,FALSE,&interval);
}
}
//当文件系统被激活或被注销时会调用此回调函数
VOID FsFilterNotificationCallback (
IN struct _DEVICE_OBJECT *DeviceObject,
IN BOOLEAN FsActive
)
{
if (FsActive)
{
//FsActive == TRUE 被激活
FsFilterAttachToFileSystemDevice(DeviceObject);
}
else
{
//FsActive == FALSE 被注销
FsFilterDetachFromFileSystemDevice(DeviceObject);
}
}
//文件系统激活回调函数
NTSTATUS FsFilterAttachToFileSystemDevice (
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT filterDeviceObject = NULL;
//检测我们的设备是否已经挂载,防止重复挂载
if (!FsFilterIsAttachedToDevice(DeviceObject))
{
//开始挂载
status = FsFilterAttachToDevice(DeviceObject,&filterDeviceObject);
if (!NT_SUCCESS(status))
{
return status;
}
//枚举文件系统上已有的所有卷设备并挂载
status = FsFilterEnumerateFileSystemVolumes(DeviceObject);
if (!NT_SUCCESS(status))
{
FsFilterDetachFromDevice(filterDeviceObject);
return status;
}
}
return STATUS_SUCCESS;
}
//挂载设备
NTSTATUS FsFilterAttachToDevice(
IN PDEVICE_OBJECT DeviceObject,
OUT PDEVICE_OBJECT* pFilterDeviceObject
)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT filterDeviceObject = NULL;
PFSFILTER_DEVICE_EXTENSION pDevExt = NULL;
ULONG i = 0;
//防止重复挂载
ASSERT(!FsFilterIsAttachedToDevice(DeviceObject));
//创建过滤设备
status = IoCreateDevice(g_FsFilterDriverObject,sizeof(FSFILTER_DEVICE_EXTENSION),NULL,DeviceObject->DeviceType,0,FALSE,&filterDeviceObject);
if (!NT_SUCCESS(status))
{
return status;
}
pDevExt = (PFSFILTER_DEVICE_EXTENSION)filterDeviceObject->DeviceExtension;
//复制标志位
if (FlagOn(DeviceObject->Flags,DO_BUFFERED_IO))
{
SetFlag(filterDeviceObject->Flags,DO_BUFFERED_IO);
}
if (FlagOn(DeviceObject->Flags,DO_DIRECT_IO))
{
SetFlag(filterDeviceObject->Flags,DO_DIRECT_IO);
}
if (FlagOn(DeviceObject->Characteristics,FILE_DEVICE_SECURE_OPEN))
{
SetFlag(filterDeviceObject->Characteristics,FILE_DEVICE_SECURE_OPEN);
}
//如果挂载失败说明是设备对象还没有完成初始化,这种情况一般发生在卷正在被装入的时候过滤驱动被加载
//所以用for循环,失败后可以再次尝试挂载
for (i = 0; i < 8; i++)
{
LARGE_INTEGER interval;
//正式挂载设备
status = IoAttachDeviceToDeviceStackSafe(filterDeviceObject,DeviceObject,&pDevExt->AttachedToDeviceObject);
if (NT_SUCCESS(status))
{
break;
}
//延时5秒,给设备足够的时间完成初始化
interval.QuadPart = (500 * DELAY_ONE_MILLISECOND);
KeDelayExecutionThread(KernelMode, FALSE, &interval);
}
if (!NT_SUCCESS(status))
{
//失败则清理现场
IoDeleteDevice(filterDeviceObject);
filterDeviceObject = NULL;
}
else
{
//设置正在初始化的标志
ClearFlag(filterDeviceObject->Flags, DO_DEVICE_INITIALIZING);
if (NULL != pFilterDeviceObject)
{
*pFilterDeviceObject = filterDeviceObject;
}
}
return status;
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课