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; }
NTSTATUS GingkoRead ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS status = STATUS_SUCCESS; PVOID pBuff = NULL; BOOLEAN GingkoFile = FALSE; PGINGKO_OBJECT pGingkoObject = NULL; PIO_STACK_LOCATION irpsp = NULL; PFILE_OBJECT FileObject = NULL; SharedNotificationPtr snf = NULL; PGINGKO_PROCESS_LIST pProcessList = NULL; PGINGKO_DEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension; if ( IS_GINGKO_CONTROL_DEVICE_OBJECT(DeviceObject) ) { //KdPrint( ("READ: Read Gingko Control Device...") ); Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return STATUS_INVALID_DEVICE_REQUEST; } REDFISH_NETWORK_DISPATCH( DeviceObject, Irp ); if( IsGingkoServerProcess() || PsIsSystemThread(KeGetCurrentThread()) ) { return GingkoPassThrough( DeviceObject, Irp ); } snf = GingkoReferenceSharedNotification(); if( gGingkoServerStarted == FALSE || snf == NULL ) { return GingkoPassThrough( DeviceObject, Irp ); } GingkoDereferenceSharedNotification( snf ); irpsp = IoGetCurrentIrpStackLocation(Irp); FileObject = irpsp->FileObject; if( FsRtlIsPagingFile( FileObject ) ) { KdPrint(("This is a Paging file: %wZ.\n", &(FileObject->FileName))); } //RtlInitUnicodeString( &TempName, L"\\GingkoDebug\\dbgview.chm" ); //if( RtlCompareUnicodeString( &TempName, &FileObject->FileName, TRUE ) == 0 ) //{ // LARGE_INTEGER OriginalOffset = irpsp->Parameters.Read.ByteOffset; // long OriginalLength = irpsp->Parameters.Read.Length; // KdPrint(("Read DbgView: %I64d (L: %08x, H: %08x) Lenght: %08x\n", OriginalOffset.QuadPart, OriginalOffset.LowPart, // OriginalOffset.HighPart, OriginalLength)); //} if( FindWriteFileObject( FileObject, IoGetRequestorProcessId(Irp), &pGingkoObject, FALSE ) ) { NTSTATUS status = 0L; if( pGingkoObject != NULL ) //&& pGingkoObject->Queue.CryptoInfo != NULL && ( pGingkoObject->Permission & 0x800F0000 | pGingkoObject->Permission & 0x8000F000 ) ) { if( irpsp->Parameters.Read.Length > 0L ) { if( !Irp->MdlAddress ) { __try{ ProbeForRead( Irp->UserBuffer, irpsp->Parameters.Read.Length, 1); IoAllocateMdl( Irp->UserBuffer, irpsp->Parameters.Read.Length, FALSE, FALSE, Irp ); if( Irp->MdlAddress ) { MmProbeAndLockPages( Irp->MdlAddress, UserMode, IoReadAccess ); } }__except(EXCEPTION_EXECUTE_HANDLER) { KdPrint(("Exception Code: %08x. PassThrough. The Write Length is %d, Offset: %I64d.\n", GetExceptionCode(), irpsp->Parameters.Read.Length, irpsp->Parameters.Read.ByteOffset )); if( Irp->MdlAddress ) { IoFreeMdl( Irp->MdlAddress ); Irp->MdlAddress = NULL; } } } } status = EncryptedIoQueueAddIrp (&pGingkoObject->Queue, Irp); if( status != STATUS_PENDING ) TCCompleteDiskIrp ( Irp, status, 0 ); return status; }