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

