0x01 思路(原理)數組
驅動層文件保護的思路是經過minifilter過濾文件刪除相關的IRP,並將目標文件與被保護文件相比較,命中保護規則的話返回STATUS_ACCESS_DENIED拒絕訪問;也能夠進一步利用回調函數獲取的FLT_CALLBACK_DATA結構體解析文件刪除操做對應的發起者進程,與白名單進程(容許執行刪除操做的進程)相比較。ide
須要過濾的IRP類型:IRP_MJ_SET_INFORMATION與IRP_MJ_CREATE(或還有其餘類型IRP須要過濾,還沒有知)函數
IRP_MJ_SET_INFORMATION的產生緣由通常是請求設置文件屬性等等,好比ZwSetInformationFile函數能夠發起此IRP.這裏順帶說一句的是,許多驅動都用ZwSetInformationFile函數來實現強刪文件的,好比騰訊電腦管家中的TSSysKit.sys驅動中文件穿透操做的刪除文件就是調用ZwSetInformationFile函數將FileInformationClass設爲FileDispositionInformation且((PFILE_DISPOSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->DeleteFile設爲TRUE來達到刪除文件的目的(若是是強刪正在運行的文件,那麼還需將文件對象的SectionObjectPointer->ImageSectionObject和 SectionObjectPointer->DataSectionObject 兩個字段置零)。所以,對於IRP_MJ_SET_INFORMATION,應當檢查FileInformationClass是不是FileRenameInformation和FileShortNameInformation標誌。post
IRP_MJ_CREATE的產生緣由通常是請求打開文件句柄,文件對象以及其餘內核對象等等,好比ZwCreateFile函數能夠發起此IRP.若是ZwCreateFile函數指定了FILE_DELETE_ON_CLOSE標誌,那麼當最後一個文件句柄被NtClose關閉時,文件會被刪除,這也就是過濾IRP_MJ_CREATE的緣由。所以,對於IRP_MJ_CREATE,應當檢查是否有FILE_DELETE_ON_CLOSE 標誌指定。spa
0x01 源碼及註釋以下線程
1 #include <fltKernel.h> 2 //#include "FileDeleteProtect.h" 3 4 #define DEBUG 5 #ifdef DEBUG 6 #define DBG_PRINTF(_fmt, ...) DbgPrint(_fmt, __VA_ARGS__) 7 #else 8 #define DBG_PRINTF(_fmt, ...) { NOTHING; } 9 #endif 10 11 12 DRIVER_INITIALIZE DriverEntry; 13 14 NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath); 15 NTSTATUS Unload(_In_ FLT_FILTER_UNLOAD_FLAGS Flags); 16 FLT_PREOP_CALLBACK_STATUS PreAntiDelete(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext); 17 18 //過濾IRP的回調數組 19 CONST FLT_OPERATION_REGISTRATION Callbacks[] = { 20 { IRP_MJ_CREATE, 0, PreAntiDelete, NULL }, // DELETE_ON_CLOSE 標誌. 21 { IRP_MJ_SET_INFORMATION, 0, PreAntiDelete, NULL }, // FileDispositionInformation(Ex). 22 { IRP_MJ_OPERATION_END } 23 }; 24 25 CONST FLT_REGISTRATION FilterRegistration = { 26 sizeof(FLT_REGISTRATION), // Size 27 FLT_REGISTRATION_VERSION, // Version 28 0, // Flags 29 NULL, // ContextRegistration 30 Callbacks, // OperationRegistration 31 Unload, // FilterUnloadCallback 32 NULL, // InstanceSetupCallback 33 NULL, // InstanceQueryTeardownCallback 34 NULL, // InstanceTeardownStartCallback 35 NULL, // InstanceTeardownCompleteCallback 36 NULL, // GenerateFileNameCallback 37 NULL, // NormalizeNameComponentCallback 38 NULL // NormalizeContextCleanupCallback 39 }; 40 41 PFLT_FILTER Filter; 42 static UNICODE_STRING Protected = RTL_CONSTANT_STRING(L"EXE"); 43 44 NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { 45 46 UNREFERENCED_PARAMETER(RegistryPath); 47 48 NTSTATUS Status = FltRegisterFilter(DriverObject, &FilterRegistration, &Filter); 49 if (!NT_SUCCESS(Status)) { 50 DBG_PRINTF("Failed to register filter: <0x%08x>.\n", Status); 51 return Status; 52 } 53 54 Status = FltStartFiltering(Filter); 55 if (!NT_SUCCESS(Status)) { 56 DBG_PRINTF("Failed to start filter: <0x%08x>.\n", Status); 57 FltUnregisterFilter(Filter); 58 } 59 60 return Status; 61 } 62 63 NTSTATUS Unload(_In_ FLT_FILTER_UNLOAD_FLAGS Flags) { 64 UNREFERENCED_PARAMETER(Flags); 65 DBG_PRINTF("Unload called.\n"); 66 FltUnregisterFilter(Filter); 67 68 return STATUS_SUCCESS; 69 } 70 71 /* 72 * PreCallback的調用時機 73 * IRP_MJ_CREATE——ZwCreateFile 74 * IRP_MJ_SET_INFORMATION——ZwSetInformation. 75 */ 76 FLT_PREOP_CALLBACK_STATUS PreAntiDelete(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext) { 77 UNREFERENCED_PARAMETER(CompletionContext); 78 PAGED_CODE();//PreCallback的IRQL應當<= APC_LEVEL 79 80 FLT_PREOP_CALLBACK_STATUS Status = FLT_PREOP_SUCCESS_NO_CALLBACK;//再也不調用postoperation callback routine, 81 82 83 BOOLEAN IsDirectory;//目錄操做跳過,無論 84 NTSTATUS status = FltIsDirectory(FltObjects->FileObject, FltObjects->Instance, &IsDirectory); 85 if (NT_SUCCESS(status)) { 86 if (IsDirectory == TRUE) { 87 return Status; 88 } 89 } 90 91 if (Data->Iopb->MajorFunction == IRP_MJ_CREATE) { 92 if (!FlagOn(Data->Iopb->Parameters.Create.Options, FILE_DELETE_ON_CLOSE)) { 93 return Status; 94 } 95 } 96 97 98 if (Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION) { 99 switch (Data->Iopb->Parameters.SetFileInformation.FileInformationClass) { 100 case FileRenameInformation: 101 case FileRenameInformationEx: 102 case FileDispositionInformation: 103 case FileDispositionInformationEx: 104 case FileRenameInformationBypassAccessCheck: 105 case FileRenameInformationExBypassAccessCheck: 106 case FileShortNameInformation: 107 break; 108 default: 109 return Status; 110 } 111 } 112 113 /* 114 ZwCreateFile和ZwSetInformation函數都是運行在PASSIVE_LEVEL的,因此當前的線程上下文 115 應當就是ZwCreateFile或ZwSetInformation函數的調用者進程對應的線程的上下文Context, 116 因此這裏能夠判斷調用者進程是否在白名單中(若是存在白名單進程的話) 117 if (IoThreadToProcess(Data->Thread) == WhiteListProcess) { 118 return FLT_PREOP_SUCCESS_NO_CALLBACK; 119 } 120 */ 121 122 PFLT_FILE_NAME_INFORMATION FileNameInfo = NULL; 123 if (FltObjects->FileObject != NULL) { 124 status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &FileNameInfo); 125 if (NT_SUCCESS(status)) { 126 FltParseFileNameInformation(FileNameInfo); 127 //if (RtlCompareUnicodeString(&FileNameInfo->Name, &Protected, TRUE) == 0) { 128 if (RtlCompareUnicodeString(&FileNameInfo->Extension, &Protected, TRUE) == 0) { 129 DBG_PRINTF("Protecting file deletion/rename!"); 130 Data->IoStatus.Status = STATUS_ACCESS_DENIED; 131 Data->IoStatus.Information = 0; 132 Status = FLT_PREOP_COMPLETE; 133 } 134 // Clean up file name information. 135 FltReleaseFileNameInformation(FileNameInfo); 136 } 137 } 138 139 return Status; 140 }