FLT_PREOP_CALLBACK_STATUS PRE_MJ_CREATE(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID *CompletionContext) { NTSTATUS status; PFLT_FILE_NAME_INFORMATION nameInfo = NULL; status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); if (!NT_SUCCESS(status)) { status = FltGetFileNameInformationUnsafe(FltObjects->FileObject, FltObjects->Instance, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); } if (nameInfo) { // block access if (wcsstr(nameInfo->Name.Buffer, L"your_file.exe") != NULL) { Data->IoStatus.Status = STATUS_NO_SUCH_FILE; Data->IoStatus.Information = 0; return FLT_PREOP_COMPLETE; } FltReleaseFileNameInformation(nameInfo); } return FLT_PREOP_SUCCESS_NO_CALLBACK; }
NTSTATUS GenerateFileName(IN PFLT_INSTANCE Instance, IN PFILE_OBJECT FileObject, IN PFLT_CALLBACK_DATA CallbackData, IN FLT_FILE_NAME_OPTIONS NameOptions, OUT PBOOLEAN CacheFileNameInformation, OUT PFLT_NAME_CONTROL FileName ) //上层的minifilter过滤驱动的名字请求进行处理 { NTSTATUS Status = STATUS_UNSUCCESSFUL; PFILE_OBJECT StreamObject = FileObject; PFLT_FILE_NAME_INFORMATION FileNameInformation = NULL; BOOLEAN bEncryptResource = FALSE; PFCB Fcb = FileObject->FsContext; PCCB Ccb = FileObject->FsContext2; FsRtlEnterFileSystem(); try { if(IsMyFakeFcb(FileObject)) { ExAcquireResourceSharedLite(Fcb->EncryptResource,TRUE); bEncryptResource = TRUE; if(BooleanFlagOn(Fcb->FcbState,SCB_STATE_SHADOW_CLOSE) || Ccb->StreamFileInfo.StreamObject == NULL) { try_return (Status = STATUS_FILE_DELETED); } else { StreamObject = Ccb->StreamFileInfo.StreamObject; } } ClearFlag(NameOptions,FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER); if(FlagOn(NameOptions,FLT_FILE_NAME_NORMALIZED)) { ClearFlag(NameOptions,FLT_FILE_NAME_NORMALIZED); SetFlag(NameOptions,FLT_FILE_NAME_OPENED); } if (CallbackData) { PFILE_OBJECT TemFileObject = CallbackData->Iopb->TargetFileObject; CallbackData->Iopb->TargetFileObject = StreamObject; FltSetCallbackDataDirty(CallbackData); Status = FltGetFileNameInformation(CallbackData,NameOptions, &FileNameInformation); CallbackData->Iopb->TargetFileObject = TemFileObject; FltClearCallbackDataDirty(CallbackData); } else { Status = FltGetFileNameInformationUnsafe(StreamObject,Instance, NameOptions, &FileNameInformation); } if(!NT_SUCCESS(Status)) { try_return (Status); } Status = FltCheckAndGrowNameControl(FileName, FileNameInformation->Name.Length); if(!NT_SUCCESS(Status)) { try_return (Status); } RtlCopyUnicodeString(&FileName->Name, &FileNameInformation->Name); if(FileNameInformation != NULL) { FltReleaseFileNameInformation(FileNameInformation); } Status = STATUS_SUCCESS; try_exit: NOTHING; } finally { if(bEncryptResource) { ExReleaseResourceLite( Fcb->EncryptResource ); } } FsRtlExitFileSystem(); return Status; }
EXTERN_C static NTSTATUS ScvnpScavenge(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects) { PAGED_CODE(); // Ignore system threads. Thus, this program does not support activities of // kernel mode code. if (PsIsSystemThread(PsGetCurrentThread())) { return STATUS_SUCCESS; } const auto operationType = FltGetIrpName(Data->Iopb->MajorFunction); PFLT_FILE_NAME_INFORMATION fileNameInformation = nullptr; auto status = FltGetFileNameInformationUnsafe( FltObjects->FileObject, FltObjects->Instance, FLT_FILE_NAME_NORMALIZED, &fileNameInformation); if (!NT_SUCCESS(status)) { // This error is expected to happen and okay to ignore it. if (status != STATUS_FILE_DELETED) { LOG_ERROR_SAFE("%-25s : FltGetFileNameInformationUnsafe failed (%08x)", operationType, status); } return status; } status = FltParseFileNameInformation(fileNameInformation); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("%-25s : FltParseFileNameInformation failed (%08x) for %wZ", operationType, status, &fileNameInformation->Name); FltParseFileNameInformation(fileNameInformation); return status; } // Ignore directories BOOLEAN isDirectory = FALSE; status = FltIsDirectory(FltObjects->FileObject, FltObjects->Instance, &isDirectory); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("%-25s : FltIsDirectory failed (%08x) for %wZ", operationType, status, &fileNameInformation->Name); FltParseFileNameInformation(fileNameInformation); return status; } if (isDirectory) { FltParseFileNameInformation(fileNameInformation); return status; } // Go through a white list if (ScvnpIsWhiteListedFile(&fileNameInformation->Name)) { FltParseFileNameInformation(fileNameInformation); return status; } // Get a file size (etc). FILE_STANDARD_INFORMATION fileInfo = {}; status = FltQueryInformationFile(FltObjects->Instance, FltObjects->FileObject, &fileInfo, sizeof(fileInfo), FileStandardInformation, nullptr); if (!NT_SUCCESS(status)) { // This error is expected to happen and okay to ignore it. if (status != STATUS_FILE_DELETED) { LOG_ERROR_SAFE("%-25s : FltQueryInformationFile failed (%08x) for %wZ", operationType, status, &fileNameInformation->Name); } FltParseFileNameInformation(fileNameInformation); return status; } // Ignore if the file is empty if (fileInfo.EndOfFile.QuadPart == 0) { FltParseFileNameInformation(fileNameInformation); return status; } // Ignore if the file size is greater than 4GB if (fileInfo.EndOfFile.HighPart != 0) { FltParseFileNameInformation(fileNameInformation); return STATUS_FILE_TOO_LARGE; } const auto targetFileSize = fileInfo.EndOfFile.LowPart; // Read entire contents of the file onto non paged memory. Thus, it may fail // to handle a file larger than the amount of available memory. const auto buffer = FltAllocatePoolAlignedWithTag( FltObjects->Instance, NonPagedPoolNx, targetFileSize, SCVN_POOL_TAG_NAME); if (!buffer) { LOG_ERROR_SAFE( "%-25s : FltAllocatePoolAlignedWithTag failed (%lu bytes) for %wZ", operationType, targetFileSize, &fileNameInformation->Name); goto End; } status = ScvnpReadFile(Data, FltObjects, buffer, targetFileSize); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("%-25s : ScvnpReadFile failed (%08x) for %wZ", operationType, status, &fileNameInformation->Name); goto End; } // Calculate SHA1 of the written data. UCHAR sha1Hash[20] = {}; status = ScvnpGetSha1(sha1Hash, buffer, targetFileSize); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("%-25s : ScvnpGetSha1 failed (%08x) for %wZ", operationType, status, &fileNameInformation->Name); goto End; } wchar_t sha1HashW[41] = {}; for (auto i = 0; i < RTL_NUMBER_OF(sha1Hash); ++i) { const auto outW = sha1HashW + i * 2; RtlStringCchPrintfW(outW, 3, L"%02x", sha1Hash[i]); } // Copy the read file contents to the out put folder as <SHA1>.bin. wchar_t outPathW[260]; status = RtlStringCchPrintfW(outPathW, RTL_NUMBER_OF(outPathW), L"%s\\%s.bin", SCVNP_OUT_DIRECTORY_PATH, sha1HashW); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("%-25s : RtlStringCchPrintfW failed (%08x) for %wZ", operationType, status, &fileNameInformation->Name); goto End; } status = ScvnpWriteFile(FltObjects, outPathW, buffer, targetFileSize, FILE_CREATE); if (status == STATUS_DELETE_PENDING) { status = STATUS_SUCCESS; goto End; } if (status == STATUS_OBJECT_NAME_COLLISION) { // The same SHA1 is already there LOG_INFO_SAFE("%-25s for %wZ (dup with %S, %lu bytes, %wZ)", operationType, &fileNameInformation->FinalComponent, sha1HashW, targetFileSize, &fileNameInformation->Name); status = STATUS_SUCCESS; goto End; } if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("%-25s : ScvnpWriteFile failed (%08x) for %wZ", operationType, status, &fileNameInformation->Name); goto End; } // Done LOG_INFO_SAFE("%-25s for %wZ (saved as %S, %lu bytes, %wZ)", operationType, &fileNameInformation->FinalComponent, sha1HashW, targetFileSize, &fileNameInformation->Name); End: if (buffer) { FltFreePoolAlignedWithTag(FltObjects->Instance, buffer, SCVN_POOL_TAG_NAME); } if (fileNameInformation) { FltParseFileNameInformation(fileNameInformation); } return status; }
EXTERN_C static NTSTATUS ScvnpReadFile(_In_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Out_ void *Buffer, _In_ ULONG BufferSize) { PAGED_CODE(); // Use an existing file object when it is NOT IRP_MJ_CLEANUP. if (Data->Iopb->MajorFunction != IRP_MJ_CLEANUP) { LARGE_INTEGER byteOffset = {}; auto status = FltReadFile(FltObjects->Instance, FltObjects->FileObject, &byteOffset, BufferSize, Buffer, FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET, nullptr, nullptr, nullptr); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("FltReadFile failed (%08x)", status); return status; } return status; } PFILE_OBJECT fileObject = nullptr; // Make a new file object since the file is already out of the current IO // path. PFLT_FILE_NAME_INFORMATION fileNameInformation = nullptr; auto status = FltGetFileNameInformationUnsafe( FltObjects->FileObject, FltObjects->Instance, FLT_FILE_NAME_NORMALIZED, &fileNameInformation); if (!NT_SUCCESS(status)) { return status; } OBJECT_ATTRIBUTES objAttr = RTL_INIT_OBJECT_ATTRIBUTES( &fileNameInformation->Name, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE); HANDLE fileHandle = nullptr; IO_STATUS_BLOCK ioStatus = {}; status = FltCreateFile( FltObjects->Filter, FltObjects->Instance, &fileHandle, GENERIC_READ, &objAttr, &ioStatus, nullptr, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, nullptr, 0, 0); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("FltCreateFile failed (%08x) for %wZ", status, &fileNameInformation->Name); goto End; } status = ObReferenceObjectByHandle(fileHandle, 0, nullptr, KernelMode, reinterpret_cast<void **>(&fileObject), nullptr); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("ObReferenceObjectByHandle failed (%08x) for %wZ", status, &fileNameInformation->Name); goto End; } status = FltReadFile(FltObjects->Instance, fileObject, nullptr, BufferSize, Buffer, 0, nullptr, nullptr, nullptr); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("FltReadFile failed (%08x) for %wZ", status, &fileNameInformation->Name); goto End; } End: if (fileObject) { ObDereferenceObject(fileObject); } if (fileHandle) { FltClose(fileHandle); } if (fileNameInformation) { FltReleaseFileNameInformation(fileNameInformation); } return status; }
NTSTATUS NcGetFileNameInformation( _In_opt_ PFLT_CALLBACK_DATA Data, _In_opt_ PFILE_OBJECT FileObject, _In_opt_ PFLT_INSTANCE Instance, _In_ FLT_FILE_NAME_OPTIONS NameOptions, _Outptr_ PFLT_FILE_NAME_INFORMATION *FileNameInformation ) /*++ Routine Description: This function is a wrapper to call the correct variant of FltGetFileNameInformation depending on the information we happen to have available. Arguments: Data - Pointer to the callback data structure associated with a request. This is optional, but if not specified, FileObject and Instance must be supplied. FileObject - Pointer to the file object to query a name on. Optional, but if not supplied, Data must be supplied. Instance - Pointer to the instance of our filter to query the name on. Optional, but if not supplied, Data must be supplied. NameOptions - FLT_FILE_NAME_* flags for this request. FileNameInformation - On output, contains the file name information resulting from this query. On failure, contents are undefined. On success, caller is responsible for releasing this with FltReleaseFileNameInformation. Return Value: Returns the status of the operation. --*/ { NTSTATUS Status; PAGED_CODE(); FLT_ASSERT( Data || FileObject ); *FileNameInformation = NULL; if (ARGUMENT_PRESENT( Data )) { Status = FltGetFileNameInformation( Data, NameOptions, FileNameInformation ); } else if (ARGUMENT_PRESENT( FileObject )) { Status = FltGetFileNameInformationUnsafe( FileObject, Instance, NameOptions, FileNameInformation ); // // This should never happen, as either Data or FileObject must be non-NULL. // } else { FLT_ASSERT( FALSE ); Status = STATUS_INVALID_PARAMETER; } return Status; }