• [内核驱动] 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 是随着操作系统启动而启动,如果想要驱动下次系统启动还生效,可以选择这种类型。

  • 相关阅读:
    openresty开发系列35--openresty执行流程之5内容content阶段
    openresty开发系列34--openresty执行流程之4访问阶段
    openresty开发系列33--openresty执行流程之3重写rewrite和重定向
    [转] Dangers of using dlsym() with RTLD_NEXT
    fork failed because of Out Of Memory
    gdb 拾穗
    原子变量的性能问题
    blktrace + blkparse + btt 分析IO
    [转] 利用BLKTRACE分析IO性能
    使用perf + FlameGraph生成进程火焰图
  • 原文地址:https://www.cnblogs.com/chechen/p/7760832.html
Copyright © 2020-2023  润新知