打个广告: http://hi.baidu.com/hu3167343
这是本人刚申请的百度空间, 大家快来加我好友啊, 哈哈.

最近学习了下文件微过滤驱动的框架, 确实比文件过滤系统简单N多啊.

1.DriverEntry
NTSTATUS
DriverEntry (
    __in PDRIVER_OBJECT DriverObject,
    __in PUNICODE_STRING RegistryPath
    )
{
    NTSTATUS status;  
    UNREFERENCED_PARAMETER( RegistryPath );

 //  注册一个过虑器
    status = FltRegisterFilter( DriverObject,
                                &FilterRegistration,
                                &gFilterHandle );

    if (NT_SUCCESS( status )) {
        //  开启过滤
        status = FltStartFiltering( gFilterHandle );

        if (!NT_SUCCESS( status )) {
            //  开启不成功则注销过滤器
            FltUnregisterFilter( gFilterHandle );
        }
    }
    return status;
}

这里的主要函数是FltRegisterFilter,  原型如下:
NTSTATUS
  FltRegisterFilter(
    IN PDRIVER_OBJECT  Driver, //在DriverEntry中传入的参数
    IN CONST FLT_REGISTRATION  *Registration, //微过滤器注册结构, 这个是最重要的参数
    OUT PFLT_FILTER  *RetFilter //微顾虑句柄, 通常保存在全局变量中
    ); 

FLT_REGISTRATION的结构如下:
typedef struct _FLT_REGISTRATION {
  USHORT  Size;   //结构的大小, 一般为sizeof(FLT_REGISTRATION)
  USHORT  Version;  //结构的版本, 一般写FLT_REGISTRATION_VERSION即可
  FLT_REGISTRATION_FLAGS  Flags;  //标志位, 一般填0
  CONST FLT_CONTEXT_REGISTRATION  *ContextRegistration;  
  CONST FLT_OPERATION_REGISTRATION  *OperationRegistration; //操作注册函数集, 这个域是最重要的
  PFLT_FILTER_UNLOAD_CALLBACK  FilterUnloadCallback;  //卸载回调函数
  PFLT_INSTANCE_SETUP_CALLBACK  InstanceSetupCallback; //实例绑定回调函数, 在这里可以决定绑定哪些卷, 可以为NULL
  ...
} FLT_REGISTRATION, *PFLT_REGISTRATION;

其中第5个域FLT_OPERATION_REGISTRATION 结构如下:
typedef struct _FLT_OPERATION_REGISTRATION {
  UCHAR  MajorFunction;     //IRP的主功能号
  FLT_OPERATION_REGISTRATION_FLAGS  Flags; //标志位, 一般填0即可, 在读写IRP中可能会有特殊, 具体参看MSDN
  PFLT_PRE_OPERATION_CALLBACK  PreOperation; //预操作回调函数
  PFLT_POST_OPERATION_CALLBACK  PostOperation; //操作后回调函数
  PVOID  Reserved1;
} FLT_OPERATION_REGISTRATION, *PFLT_OPERATION_REGISTRATION;

实例如下:
const FLT_OPERATION_REGISTRATION Callbacks[] = {
    { IRP_MJ_CREATE,
      0, 
      NPPreCreate,
      NPPostCreate },

    { IRP_MJ_OPERATION_END } //最后一项必须为这个, 否则过滤管理器,无法知道到底有多少个元素
};

const FLT_REGISTRATION FilterRegistration = {
    sizeof( FLT_REGISTRATION ),         //  Size
    FLT_REGISTRATION_VERSION,           //  Version
    0,                                  //  Flags
    NULL,                               //  Context
    Callbacks,                          //  Operation callbacks
    NPUnload,                           //  MiniFilterUnload
 NULL,         
 NULL,         
 NULL,        
 NULL,
    NULL,                             
    NULL,                              
    NULL                          
}

2.卸载例程:
NTSTATUS
NPUnload (
    __in FLT_FILTER_UNLOAD_FLAGS Flags
    )
{
    UNREFERENCED_PARAMETER( Flags );
    PAGED_CODE();
    //注销此过滤器
    FltUnregisterFilter( gFilterHandle );
    return STATUS_SUCCESS;
}

3.微过滤驱动与应用层通信
(1)在DriverEntry中建立一个通信端口
//建立一个默认安全的描述符
 status  = FltBuildDefaultSecurityDescriptor( &sd, FLT_PORT_ALL_ACCESS );          

RtlInitUnicodeString( &uniString, MINISPY_PORT_NAME );
InitializeObjectAttributes( &oa,
       &uniString,
       OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
       NULL,
       sd );

//建立一个通信端口
status = FltCreateCommunicationPort( gFilterHandle,
          &gServerPort,
          &oa,
          NULL,
          NPMiniConnect, //R3连接通信端口时的回调例程
          NPMiniDisconnect, //R3断开连接时的回调例程
          NPMiniMessage, //R3发送数据时的回调函数
          1 );


//最后释放安全描述符
FltFreeSecurityDescriptor( sd );

其中比较重要的函数是NPMiniMessage . 此函数在我们调用R3层函数FilterSendMessage时被调用.
函数原型如下:
NTSTATUS
NPMiniMessage (
    __in PVOID ConnectionCookie,
    __in_bcount_opt(InputBufferSize) PVOID InputBuffer,
    __in ULONG InputBufferSize,
    __out_bcount_part_opt(OutputBufferSize,*ReturnOutputBufferLength) PVOID OutputBuffer,
    __in ULONG OutputBufferSize,
    __out PULONG ReturnOutputBufferLength
)

其中在输入的参数中, InputBuffer 和 OutputBuffer需要注意. 这两个参数使用的都是用户模式下的地址,
过滤管理器已经帮我们做了ProbedForRead (对于InputBuffer) 和 ProbedForWrite (对于OutputBuffer)的操作.
以防止R3层传入无效的地址.
但是当我们从InputBuffer中取数据, 或者往OutputBuffer写数据时, 要对他们使用try-catch.
如下;
_try{
    memcpy(OutputBuffer, strPath, strlen(strPath));
}
_except(EXCEPTION_EXECUTE_HANDLER)
{
    KdPrint(("catch error\r\n"));



(2)NPUnload例程中关闭通信端口
FltCloseCommunicationPort( gServerPort );

(3)R3程序中
不是用我们常用的DeviceIoControl, 而是有了两个新的函数
连接端口:
HRESULT
WINAPI
  FilterConnectCommunicationPort(
    IN LPCWSTR  lpPortName,
    IN DWORD  dwOptions,
    IN LPVOID  lpContext OPTIONAL,
    IN DWORD  dwSizeOfContext,
    IN LPSECURITY_ATTRIBUTES  lpSecurityAttributes OPTIONAL,
    OUT HANDLE  *hPort
    ); 

发送和接收数据:
HRESULT
WINAPI
  FilterSendMessage(
    __in HANDLE  hPort,
    __in_bcount LPVOID  lpInBuffer,
    __in DWORD  dwInBufferSize,
    __out_bcount_part_opt LPVOID  lpOutBuffer,
    __in DWORD  dwOutBufferSize,
    __out LPDWORD  lpBytesReturned
    ); 

在使用FilterSendMessage函数时, 我遇到了一个问题. 就是当我们不需要输入参数而把lpInBuffer传入NULL, dwInBufferSize传入0, 此函数调用会失败, R0层中的NPMiniMessage函数不会被回调. 不知道这是我个人对这个函数参数的理解问题, 还是函数本来就是这样的, 求解释~

其他我就不再累述了, 函数具体用法请参看MSDN

下面是我学习文件微过滤驱动时的实验产物, MzfFileMon, 界面如下:


Bin如下:
MzfFileMonBin.rar

R0和R3代码如下:
MzfFileMonSrc.rar