VOID PtOperationStatusCallback ( __in PCFLT_RELATED_OBJECTS FltObjects, __in PFLT_IO_PARAMETER_BLOCK ParameterSnapshot, __in NTSTATUS OperationStatus, __in PVOID RequesterContext ) /*++ Routine Description: This routine is called when the given operation returns from the call to IoCallDriver. This is useful for operations where STATUS_PENDING means the operation was successfully queued. This is useful for OpLocks and directory change notification operations. This callback is called in the context of the originating thread and will never be called at DPC level. The file object has been correctly referenced so that you can access it. It will be automatically dereferenced upon return. This is non-pageable because it could be called on the paging path Arguments: FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance, its associated volume and file object. RequesterContext - The context for the completion routine for this operation. OperationStatus - Return Value: The return value is the status of the operation. --*/ { UNREFERENCED_PARAMETER( FltObjects ); PT_DBG_PRINT( PTDBG_TRACE_ROUTINES, ("PassThrough!PtOperationStatusCallback: Entered\n") ); PT_DBG_PRINT( PTDBG_TRACE_OPERATION_STATUS, ("PassThrough!PtOperationStatusCallback: Status=%08x ctx=%p IrpMj=%02x.%02x \"%s\"\n", OperationStatus, RequesterContext, ParameterSnapshot->MajorFunction, ParameterSnapshot->MinorFunction, FltGetIrpName(ParameterSnapshot->MajorFunction)) ); }
VOID PtOperationStatusCallback( _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PFLT_IO_PARAMETER_BLOCK ParameterSnapshot, _In_ NTSTATUS OperationStatus, _In_ PVOID RequesterContext) { UNREFERENCED_PARAMETER(FltObjects); KdPrint(("PassThrough!PtOperationStatusCallback: Entered\n")); KdPrint(("PassThrough!PtOperationStatusCallback: Status=%08x ctx=%p IrpMj=%02x.%02x \"%s\"\n", OperationStatus, RequesterContext, ParameterSnapshot->MajorFunction, ParameterSnapshot->MinorFunction, FltGetIrpName(ParameterSnapshot->MajorFunction))); }
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; }