文件过滤驱动Sfilter学习笔记

转载自:http://mzf2008.blog.163.com/blog/static/3559978620114156433999/


1.DriverEntry例程
(1)创建过滤驱动的控制设备, 以后我们的IO控制码就是发到这个设备上面

//这里的设备名与普通设备有所不同.
//当然, 最简单的可以直接写成 L"\\Device\\Filemontor";(FileMon中是这么写的, 调试过可行)
RtlInitUnicodeString( &nameString, L"\\FileSystem\\Filters\\FileMonitor" );
status = IoCreateDevice( DriverObject,
       0,                     //has no device extension  
            //这是与其他Attach到别的设备上的设备的不同之处 
       &nameString,
       FILE_DEVICE_DISK_FILE_SYSTEM,
       FILE_DEVICE_SECURE_OPEN,
       FALSE,
       &gSFilterControlDeviceObject );

if (status == STATUS_OBJECT_PATH_NOT_FOUND) {

 RtlInitUnicodeString( &nameString, L"\\FileSystem\\FileMonitor" );
 status = IoCreateDevice( DriverObject,
        0,                      
        &nameString,
        FILE_DEVICE_DISK_FILE_SYSTEM,
        FILE_DEVICE_SECURE_OPEN,
        FALSE,
        &gSFilterControlDeviceObject );
}

//创建符号链接
RtlInitUnicodeString(&syblnkString, L"\\DosDevices\\FileMonitor");
status = IoCreateSymbolicLink( &syblnkString, &nameString );

if (!NT_SUCCESS(status)) {

 IoDeleteSymbolicLink( &syblnkString );
 status = IoCreateSymbolicLink( &syblnkString, &nameString );
 
 if (!NT_SUCCESS(status)) {

  KdPrint(("创建符号链接失败~\n"));
  IoDeleteDevice(gSFilterControlDeviceObject);
  return status;
 }
}

(2)设置例程
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {

 DriverObject->MajorFunction[i] = SfDispatch;
}
DriverObject->MajorFunction[IRP_MJ_CREATE] = SfCreate;

DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = SfFsControl;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SfCleanupClose;

(3)调用IoRegisterFsRegistrationChange函数来通知我们文件系统的加载和卷的mount.


2.SfCreate 例程
(1)sfilter的原版中是这么写的
if (IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject)) {

 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
 Irp->IoStatus.Information = 0;
 IoCompleteRequest( Irp, IO_NO_INCREMENT );
 return STATUS_INVALID_DEVICE_REQUEST;
}

这样写的后果是我们用CreateFile函数在R3下打开此控制设备符号链接的时候失败
我刚开始学习文件过滤驱动的时候对此不是很了解, CreateFile老是失败, 
起初还以为是符号链接名写错了, 后来参看了FileMon的代码才反应过来

于是修改如下:
if (IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject)) {
  
 Irp->IoStatus.Status = STATUS_SUCCESS;
 Irp->IoStatus.Information = FILE_OPENED;
 IoCompleteRequest( Irp, IO_NO_INCREMENT );
 return STATUS_SUCCESS;
}

(2)根据不同软件的需要, 编写此函数的接下来部分
[1]比如我们要阻止病毒在Windows目录下创建文件, 那么我们就要在此文件还没创建的时候得到此文件的全路径.
要在这个时候得到文件的路径, 楚狂人也说了有点麻烦. 下面提供一个函数给大家, 用于在文件创建前得到路径.
BOOLEAN MzfGetFileFullPathPreCreate(PFILE_OBJECT pFile, PUNICODE_STRING path )
{
  NTSTATUS status;
  POBJECT_NAME_INFORMATION pObjName = NULL;
  WCHAR buf[256] = {0};
  void *obj_ptr = NULL;
  ULONG ulRet = 0;
  BOOLEAN bSplit = FALSE;

  if (pFile == NULL) return FALSE;
  if (pFile->FileName.Buffer == NULL) return FALSE;

  pObjName = (POBJECT_NAME_INFORMATION)buf;

  if (pFile->RelatedFileObject != NULL)
   obj_ptr = (void *)pFile->RelatedFileObject;
  else
   obj_ptr = (void *)pFile->DeviceObject;

  status = ObQueryNameString(obj_ptr, pObjName, 256*sizeof(WCHAR), &ulRet);
  if (status == STATUS_INFO_LENGTH_MISMATCH)
  {
    pObjName = (POBJECT_NAME_INFORMATION)ExAllocatePool(NonPagedPool, ulRet);

    if (pObjName == NULL)  return FALSE;

    RtlZeroMemory(pObjName, ulRet);

    status = ObQueryNameString(obj_ptr, pObjName, ulRet, &ulRet);
    if (!NT_SUCCESS(status)) return FALSE;
  }

 //拼接的时候, 判断是否需要加 '\\'
 if (pFile->FileName.Length > 2 && 
  pFile->FileName.Buffer[0] != L'\\' &&
  pObjName->Name.Buffer[pObjName->Name.Length/sizeof(WCHAR) -1] != L'\\')
  bSplit = TRUE;
 
 ulRet = pObjName->Name.Length + pFile->FileName.Length;

 if (path->MaximumLength < ulRet)  return FALSE;

 RtlCopyUnicodeString(path, &pObjName->Name);
 if (bSplit)
  RtlAppendUnicodeToString(path, L"\\");

 RtlAppendUnicodeStringToString(path, &pFile->FileName);

 if ((void*)pObjName != (void*)buf)
  ExFreePool(pObjName);

 return TRUE;
}

至此, 得到了文件的路径以后, 我们就可以做出判断了, 如果要阻止文件创建, 
那么直接用IoCompleteRequest函数结束此IRP即可, 否则下发
IoSkipCurrentIrpStackLocation( Irp );
return IoCallDriver( ((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->AttachedToDeviceObject, Irp );

[2]要是像FileMon那样只是记录系统中创建了哪些文件的话, 我们可以设置此函数的完成例程.
然后等文件创建完成了之后, 只要调用 IoQueryFileDosDeviceName 函数即可知道文件的全路径了.

设置完成例程如下:
{
 KEVENT waitEvent;
 KeInitializeEvent( &waitEvent, NotificationEvent, FALSE );

 IoCopyCurrentIrpStackLocationToNext( Irp );
 IoSetCompletionRoutine(Irp, SfCreateCompletion, &waitEvent, TRUE, TRUE, TRUE );
 status = IoCallDriver( ((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->AttachedToDeviceObject, Irp );

 if (STATUS_PENDING == status) {

  NTSTATUS localStatus = KeWaitForSingleObject(&waitEvent, Executive, KernelMode, FALSE, NULL);
  ASSERT(STATUS_SUCCESS == localStatus);
 }
 //此处文件已经创建完成了, 我们可以调用IoQueryFileDosDeviceName函数得到文件的全路径

 //最后结束此IRP
 status = Irp->IoStatus.Status;
 IoCompleteRequest( Irp, IO_NO_INCREMENT );
 return status;
}

3.SfDispatch例程
在此例程中要判断是不是我们的控制设备, 如果使我们的控制设备, 则要处理相应的IO控制码.
否则, 下发此IRP
NTSTATUS SfDispatch ( IN PDEVICE_OBJECT DeviceObject,  IN PIRP Irp )
{
 NTSTATUS status = STATUS_SUCCESS;
    PIO_STACK_LOCATION irpStack;
    
    if (IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject)) {

        Irp->IoStatus.Information = 0;
        irpStack = IoGetCurrentIrpStackLocation( Irp );
  
        switch (irpStack->MajorFunction) {
   
  case IRP_MJ_DEVICE_CONTROL:
   // 此函数用来执行相应的控制码
   status = SpyCommonDeviceIoControl( Irp->AssociatedIrp.SystemBuffer,
                                                   irpStack->Parameters.DeviceIoControl.InputBufferLength,
                                                   Irp->AssociatedIrp.SystemBuffer,
                                                   irpStack->Parameters.DeviceIoControl.OutputBufferLength,
                                                   irpStack->Parameters.DeviceIoControl.IoControlCode,
                                                   &Irp->IoStatus );
   break;
   
  case IRP_MJ_CLEANUP
   status = STATUS_SUCCESS;
   break;
   
  default:
   status = STATUS_INVALID_DEVICE_REQUEST;
        }
  
        Irp->IoStatus.Status = status;
        IoCompleteRequest( Irp, IO_NO_INCREMENT );
        return status;
    }
 
 //不是我们的控制设备则下发此IRP
    return SfPassThrough( DeviceObject, Irp );
}


IO控制码也可以在FASTIO例程的SfFastIoDeviceControl函数中处理,如下:
当然, 最简单的还是在FASTIO例程中返回FALSE. 这样, 系统便会调用我们上面的SfDispatch函数.
if (IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject)) {
  
        SpyCommonDeviceIoControl( InputBuffer,
   InputBufferLength,
   OutputBuffer,
   OutputBufferLength,
   IoControlCode,
   IoStatus );
  
        return TRUE;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个 JQGrid 插件中的搜索框(search dialog)的配置参数说明,具体含义如下: - recreateFilter: 是否重新创建过滤器。 - drag: 是否允许拖拽。 - sField: 搜索字段名称。 - sValue: 搜索值名称。 - sOper: 搜索操作符名称。 - sFilter: 过滤器名称。 - loadDefaults: 是否从 grid 的 postData 中加载默认过滤器(仅适用于多重搜索)。 - beforeShowSearch: 在搜索框显示之前触发的事件。 - afterShowSearch: 在搜索框显示之后触发的事件。 - onInitializeSearch: 初始化搜索框时触发的事件。 - afterRedraw: 重新绘制搜索框时触发的事件。 - afterChange: 当搜索条件发生变化时触发的事件。 - sortStrategy: 排序策略。 - closeAfterSearch: 是否在搜索后关闭搜索框。 - closeAfterReset: 是否在重置搜索条件后关闭搜索框。 - closeOnEscape: 是否允许使用 ESC 键关闭搜索框。 - searchOnEnter: 是否在按下回车键时进行搜索。 - multipleSearch: 是否允许多重搜索。 - multipleGroup: 是否允许多重分组。 - top: 搜索框距离顶部的距离。 - left: 搜索框距离左侧的距离。 - jqModal: 是否使用 jqModal。 - modal: 是否使用 modal。 - resize: 是否允许调整大小。 - width: 搜索框的宽度。 - height: 搜索框的高度。 - dataheight: 数据区域的高度。 - showQuery: 是否显示搜索查询条件。 - errorcheck: 是否进行错误检查。 - sopt: 搜索操作符选项。 - stringResult: 是否返回字符串结果。 - onClose: 在搜索框关闭时触发的事件。 - onSearch: 在搜索时触发的事件。 - onReset: 在重置搜索条件时触发的事件。 - toTop: 是否将搜索框置于顶部。 - overlay: 重叠度。 - columns: 搜索框中的列。 - tmplNames: 模板名称。 - tmplFilters: 模板过滤器。 - tmplLabel: 模板标签。 - showOnLoad: 是否在加载时显示搜索框。 - layer: 层级。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值