[內核驅動] 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("進入了\r\n");  
            FltParseFileNameInformation( nameInfo );  
            if (NPUnicodeStringToChar(&nameInfo->Name, FileName)) { 
                if (NPUnicodeStringToChar(&nameInfo->ParentDir, FilePath)){  
                    //輸出文件名及相對路徑  
                    DbgPrint("文件名:%s\r\n",FileName);  
                    DbgPrint("文件路徑:%s\r\n",FilePath); 
                    //輸出擴展名
                    NPUnicodeStringToChar(&nameInfo->Extension,Ext);
                    DbgPrint("文件擴展名:%s\r\n",Ext); 

                    //
                    pEprocess = Data->Thread ? IoThreadToProcess(Data->Thread) : PsGetCurrentProcess();
                    //uSProcessPath = PsGetProcessFullName(pEprocess);//這里需要釋放UNICODESTRING 的內存

                    GetSeLocateProcessImageName(pEprocess,&uSProcessPath);
                    DbgPrint("ProcFullName : %wZ\n", 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\n");                  
    }  
    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\n", Name);    
        }              
        RtlFreeAnsiString(&AnsiName);         
    } 
    __except(EXCEPTION_EXECUTE_HANDLER) {
        DbgPrint("NPUnicodeStringToChar EXCEPTION_EXECUTE_HANDLER\n");    
        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 \n");
        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\n",&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\n") );

    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 是隨着操作系統啟動而啟動,如果想要驅動下次系統啟動還生效,可以選擇這種類型。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM