zoukankan      html  css  js  c++  java
  • [内核驱动] VS2012+WDK 8.0 Minifilter实现指定扩展名文件拒绝访问

    转载:http://blog.csdn.net/C0ldstudy/article/details/51585708

    转载:http://blog.csdn.net/zj510/article/details/39344889

    转载:http://blog.csdn.net/zj510/article/details/39345479

    转载:http://www.cnblogs.com/js2854/archive/2010/11/03/HideDir.html

    转载:http://blog.csdn.net/Z18_28_19/article/details/12979743

    转载:https://bbs.pediy.com/thread-192118.htm

    转载:http://blog.csdn.net/u013761036/article/details/63254697

    转载:http://www.cnblogs.com/js2854/archive/2011/04/03/sysload.html

    转载:http://www.cnblogs.com/huangyong9527/archive/2012/09/07/2674720.html

    转载:http://blog.csdn.net/xum2008/article/details/5634903

    一.环境配置

    VS2012 + WDK 8.0

    WDK下载地址:https://developer.microsoft.com/zh-cn/windows/hardware/windows-driver-kit 

    二.安装WDK

    这样WDK就集成到VS里面

    三.创建文件过滤驱动工程

    建立工程后,首先会有两个工程,一个就是驱动工程,另外一个是package工程(这个是测试驱动安装的一个工程,对于我们来说其实没有什么用处,反正本人是没有使用过得,可以直接删除)。

       NTSTATUS DriverEntry (_In_ PDRIVER_OBJECT DriverObject,_In_ PUNICODE_STRING RegistryPath),这个类似C语言里面的main函数,这是驱动内核的入口函数

    DriverEntry函数中,通过FltRegisterFilter注册一个微过滤器;另一个是用FltStartFiltering开始过滤。FltRegisterFilter函数通过输入驱动对象和注册信息的结构返回微过滤器句柄,而FltStartFiltering函数实现开启过滤功能

    NTSTATUS
    DriverEntry (
        __in PDRIVER_OBJECT DriverObject,
        __in PUNICODE_STRING RegistryPath
        )
    {
        NTSTATUS status;
        PSECURITY_DESCRIPTOR sd;
        OBJECT_ATTRIBUTES oa;
        UNICODE_STRING uniString;         
        UNREFERENCED_PARAMETER( RegistryPath );
    
    //向过滤管理器注册一个过滤器
        status = FltRegisterFilter( DriverObject,
                                    &FilterRegistration,
                                    &gFilterHandle );
    
        ASSERT( NT_SUCCESS( status ) );
    //开启过滤行为
        if (NT_SUCCESS( status )) {
            status = FltStartFiltering( gFilterHandle );
        //如果开启失败,取消注册
            if (!NT_SUCCESS( status )) {
                FltUnregisterFilter( gFilterHandle );
            }
        }
       status=FltBuildDefaultSecurityDescriptor(&sd,FLT_PORT_ALL_ACCESS);                     
        RtlInitUnicodeString( &uniString, MINISPY_PORT_NAME );
    
        InitializeObjectAttributes( &oa,
                                    &uniString,
                                    OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,
                                    NULL,
                                    sd );
        FltFreeSecurityDescriptor( sd );    
        return status;
    }

    在注册过滤器时,使用了微过滤器注册结构,也就是FLT_REGISTRATION。

    CONST FLT_REGISTRATION FilterRegistration = {
    
        sizeof( FLT_REGISTRATION ),         //  Size
        FLT_REGISTRATION_VERSION,           //  Version
        0,                                  //  Flags
    
        NULL,                               //  Context
        Callbacks,                          //  Operation callbacks
    
        MyMiniFilterUnload,                           //  MiniFilterUnload
    
        MyMiniFilterInstanceSetup,                    //  InstanceSetup
        MyMiniFilterInstanceQueryTeardown,            //  InstanceQueryTeardown
        MyMiniFilterInstanceTeardownStart,            //  InstanceTeardownStart
        MyMiniFilterInstanceTeardownComplete,         //  InstanceTeardownComplete
    
        NULL,                               //  GenerateFileName
        NULL,                               //  GenerateDestinationFileName
        NULL                                //  NormalizeNameComponent
    
    };

    CallBacks最为重要,这是一个回调函数组,其中可以处理各种请求。请求过滤分为2种:请求完成之前操作和等待请求完成之后操作,分别在预操作回调和后操作回调函数中。CallBacks回调函数数组如下:

    当系统接收到标识为IRP_MJ_CREATE的IPR也就是试图生成或者打开文件时,自然就会调用到预操作函数与后操作函数。

    我们启用一个Write的过滤,如:

    CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
    
        { IRP_MJ_WRITE,
            0,
            MyMiniFilterPreOperation,
            MyMiniFilterPostOperation },
    #if 0 // TODO - List all of the requests to filter.
        { IRP_MJ_CREATE,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_CREATE_NAMED_PIPE,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_CLOSE,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_READ,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_WRITE,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_QUERY_INFORMATION,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_SET_INFORMATION,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_QUERY_EA,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_SET_EA,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_FLUSH_BUFFERS,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_QUERY_VOLUME_INFORMATION,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_SET_VOLUME_INFORMATION,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_DIRECTORY_CONTROL,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_FILE_SYSTEM_CONTROL,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_DEVICE_CONTROL,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_INTERNAL_DEVICE_CONTROL,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_SHUTDOWN,
          0,
          MyMiniFilterPreOperationNoPostOperation,
          NULL },                               //post operations not supported
    
        { IRP_MJ_LOCK_CONTROL,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_CLEANUP,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_CREATE_MAILSLOT,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_QUERY_SECURITY,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_SET_SECURITY,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_QUERY_QUOTA,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_SET_QUOTA,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_PNP,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_ACQUIRE_FOR_MOD_WRITE,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_RELEASE_FOR_MOD_WRITE,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_ACQUIRE_FOR_CC_FLUSH,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_RELEASE_FOR_CC_FLUSH,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_FAST_IO_CHECK_IF_POSSIBLE,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_NETWORK_QUERY_OPEN,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_MDL_READ,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_MDL_READ_COMPLETE,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_PREPARE_MDL_WRITE,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_MDL_WRITE_COMPLETE,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_VOLUME_MOUNT,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
        { IRP_MJ_VOLUME_DISMOUNT,
          0,
          MyMiniFilterPreOperation,
          MyMiniFilterPostOperation },
    
    #endif // TODO
    
        { IRP_MJ_OPERATION_END }
    };

    预操作回调函数:MyMiniFilterPreOperation函数第一个参数是回调数据包的指针,其中包含这个请求相关的全部信息。

    FLT_PREOP_CALLBACK_STATUS
    MyMiniFilterPreOperation (
        _Inout_ PFLT_CALLBACK_DATA Data,
        _In_ PCFLT_RELATED_OBJECTS FltObjects,
        _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
        )
    {
        char FileName[260] = "X:";//记录文件名  
        char FilePath[260] = "Y:";//记录相对路径(ParentDir)  
        char Ext[260] = "Z:";//记录扩展名  
        NTSTATUS status;  
        UNICODE_STRING uniString;
        PEPROCESS pEprocess = 0;
        PUNICODE_STRING uSProcessPath = NULL;
    
        PFLT_FILE_NAME_INFORMATION nameInfo;  
        UNREFERENCED_PARAMETER( FltObjects );  
        UNREFERENCED_PARAMETER( CompletionContext );  
        PAGED_CODE();          
        __try {                                                           
            status = FltGetFileNameInformation( Data,FLT_FILE_NAME_NORMALIZED|FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo );  
            if (NT_SUCCESS( status )) {  
                //DbgPrint("进入了
    ");  
                FltParseFileNameInformation( nameInfo );  
                if (NPUnicodeStringToChar(&nameInfo->Name, FileName)) { 
                    if (NPUnicodeStringToChar(&nameInfo->ParentDir, FilePath)){  
                        //输出文件名及相对路径  
                        DbgPrint("文件名:%s
    ",FileName);  
                        DbgPrint("文件路径:%s
    ",FilePath); 
                        //输出扩展名
                        NPUnicodeStringToChar(&nameInfo->Extension,Ext);
                        DbgPrint("文件扩展名:%s
    ",Ext); 
    
                        //
                        pEprocess = Data->Thread ? IoThreadToProcess(Data->Thread) : PsGetCurrentProcess();
                        //uSProcessPath = PsGetProcessFullName(pEprocess);//这里需要释放UNICODESTRING 的内存
    
                        GetSeLocateProcessImageName(pEprocess,&uSProcessPath);
                        DbgPrint("ProcFullName : %wZ
    ", uSProcessPath);
    
    
                        //判断文件路径或名字是否符合要求,若是满足要求则拒绝访问  
                        if (strstr(FileName, "txt") > 0) {  
                            Data->IoStatus.Status = STATUS_ACCESS_DENIED;                                                                     
                            Data->IoStatus.Information = 0;
                            FltReleaseFileNameInformation( nameInfo );  
                            return FLT_PREOP_COMPLETE;  
                        }  
                    }                          
    
                    FltReleaseFileNameInformation( nameInfo );          
                }                                      
            }}  
        __except(EXCEPTION_EXECUTE_HANDLER) {  
            DbgPrint("NPPreCreate EXCEPTION_EXECUTE_HANDLER
    ");                  
        }  
        return FLT_PREOP_SUCCESS_WITH_CALLBACK;
    }

    在预操作函数里,我用到NPUnicodeStringToChar函数和GetSeLocateProcessImageName,在此一并贴出来

    BOOLEAN NPUnicodeStringToChar(PUNICODE_STRING UniName, char Name[])
    {
        ANSI_STRING    AnsiName;            
        NTSTATUS    ntstatus;
        char*        nameptr;            
    
        __try {                                       
            ntstatus = RtlUnicodeStringToAnsiString(&AnsiName, UniName, TRUE);        
    
            if (AnsiName.Length < 260) {
                nameptr = (PCHAR)AnsiName.Buffer;
                //Convert into upper case and copy to buffer
                //strcpy(Name, _strupr(nameptr));    //将字符串转换成大写形式
                strcpy(Name,_strlwr(nameptr));//讲字符串转换成小写形式
                DbgPrint("NPUnicodeStringToChar : %s
    ", Name);    
            }              
            RtlFreeAnsiString(&AnsiName);         
        } 
        __except(EXCEPTION_EXECUTE_HANDLER) {
            DbgPrint("NPUnicodeStringToChar EXCEPTION_EXECUTE_HANDLER
    ");    
            return FALSE;
        }
        return TRUE;
    }
    
    //获取进程全路径
    PUNICODE_STRING GetSeLocateProcessImageName(PEPROCESS Process,PUNICODE_STRING *pImageFileName)
    {
        POBJECT_NAME_INFORMATION pProcessImageName = NULL;
        PUNICODE_STRING pTempUS = NULL;
        ULONG NameLength = 0;
        //Process->SeAuditProcessCreationInfo.ImageFileName->Name
        //win7 x86 offset = 0x1ec
        //if (NULL == Process->SeAuditProcessCreationInfo.ImageFileName)
        pProcessImageName = (POBJECT_NAME_INFORMATION)(*(ULONG*)((ULONG)Process + 0x1ec));
        if(pProcessImageName == NULL)
        {
            DbgPrint("Process->SeAuditProcessCreationInfo.ImageFileName == NULL 
    ");
            return NULL;
        }
        else
        {
            NameLength = sizeof(UNICODE_STRING) + pProcessImageName->Name.MaximumLength;
            pTempUS = ExAllocatePoolWithTag( NonPagedPool, NameLength, 'aPeS' );
            if (NULL != pTempUS) {
    
                RtlCopyMemory( 
                    pTempUS, 
                    &pProcessImageName->Name, 
                    NameLength 
                    );
    
                pTempUS->Buffer = (PWSTR)(((PUCHAR) pTempUS) + sizeof(UNICODE_STRING));
                *pImageFileName = pTempUS;
                DbgPrint("Path:%wZ
    ",&pProcessImageName->Name); 
                return *pImageFileName;
            }
            return NULL;
        }
    
    }

    后操作回调函数:在一般的情况下,后操作回调函数在文件新建不成功的时候取消之前的操作,本次项目中没有相关实践,就没有做过多的修改和研究。

    FLT_POSTOP_CALLBACK_STATUS
    MiniFilterPostOperation (
        _Inout_ PFLT_CALLBACK_DATA Data,
        _In_ PCFLT_RELATED_OBJECTS FltObjects,
        _In_opt_ PVOID CompletionContext,
        _In_ FLT_POST_OPERATION_FLAGS Flags
        )
    {
        UNREFERENCED_PARAMETER( Data );
        UNREFERENCED_PARAMETER( FltObjects );
        UNREFERENCED_PARAMETER( CompletionContext );
        UNREFERENCED_PARAMETER( Flags );
    
        PT_DBG_PRINT( PTDBG_TRACE_ROUTINES,
                      ("MiniFilter!MiniFilterPostOperation: Entered
    ") );
    
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    好了,选择Win 7 Debug直接编译。

    然后。。。。  报错了,没有关系,查看出错原因,无外乎一些警告被当做错误,或者一些函数参数没有被使用,导致编译不过,这些都是因为安全警告等级太高了,我们的解决方法:

    然后把MyMinifilter.inf和MyMiniFilter.sys考到虚拟机上。注意VS2012不支持了XP了,所以我们找一个win7 32位虚拟机。因为win7 64位虚拟机需要签名,为了省去签名这一步,先用win7 32位

    右键点击inf文件安装。之后运行cmd,(注意需要用Administrator运行)。输入命令sc start myminifilter

    这样就可以把minifilter驱动起来。

     

     我们需要查看驱动运行过程的打印信息,用DebugView这个软件。

     用Administrator运行DebugView(注意勾上Enable verbose kernel output)这样我们用start,stop命令的时候就可以看到一下log

    可是实际情况却没有看到log。这个是因为inf文件需要稍微改一下。

    修改inf文件

    现在暂时只需要修改Altitude,看下图,其实就是把注释掉的代码启用。

     

     再次安装驱动运行驱动服务,用记事本打开一个txt文本

    可见阻止txt格式的文件打开了。

    后记:当下次打开虚拟机时,发现驱动不拦截了,原来是我驱动开始类型默认是SERVICE_DEMAND_START,这种是按需启动的驱动程序

          SERVICE_SYSTEM_START 是随着操作系统启动而启动,如果想要驱动下次系统启动还生效,可以选择这种类型。

  • 相关阅读:
    使用 asp.net mvc和 jQuery UI 控件包
    ServiceStack.Redis 使用教程
    HTC T8878刷机手册
    Entity Framework CodeFirst 文章汇集
    2011年Mono发展历程
    日志管理实用程序LogExpert
    使用 NuGet 管理项目库
    WCF 4.0路由服务Routing Service
    精进不休 .NET 4.0 (1) asp.net 4.0 新特性之web.config的改进, ViewStateMode, ClientIDMode, EnablePersistedSelection, 控件的其它一些改进
    精进不休 .NET 4.0 (7) ADO.NET Entity Framework 4.0 新特性
  • 原文地址:https://www.cnblogs.com/chechen/p/7760832.html
Copyright © 2011-2022 走看看