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 PtInstanceSetup ( __in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_SETUP_FLAGS Flags, __in DEVICE_TYPE VolumeDeviceType, __in FLT_FILESYSTEM_TYPE VolumeFilesystemType ) { PDEVICE_OBJECT devObj = NULL; PVOLUME_CONTEXT ctx = NULL; PFILE_FS_SIZE_INFORMATION VolumeBuffer = NULL; NTSTATUS status = STATUS_SUCCESS; ULONG retLen; PUNICODE_STRING workingName; USHORT size; IO_STATUS_BLOCK IoStatus; UCHAR volPropBuffer[sizeof(FLT_VOLUME_PROPERTIES)+512]; PFLT_VOLUME_PROPERTIES volProp = (PFLT_VOLUME_PROPERTIES)volPropBuffer; PAGED_CODE(); UNREFERENCED_PARAMETER( Flags ); UNREFERENCED_PARAMETER( VolumeDeviceType ); UNREFERENCED_PARAMETER( VolumeFilesystemType ); try { //我们在卷上下文中保存扇区大小跟一个资源,用卷上下文完成vcb的工作 status = FltAllocateContext( FltObjects->Filter, FLT_VOLUME_CONTEXT, sizeof(VOLUME_CONTEXT), NonPagedPool, &ctx ); if (!NT_SUCCESS(status)) { leave; } status = FltGetVolumeProperties( FltObjects->Volume, volProp, sizeof(volPropBuffer), &retLen ); if (!NT_SUCCESS(status)) { leave; } ASSERT((volProp->SectorSize == 0) || (volProp->SectorSize >= MIN_SECTOR_SIZE)); if(volProp->SectorSize > MAX_SECTOR_SIZE) { DbgPrint("不支持这么大的扇区的磁盘 %d \n",volProp->SectorSize ); status = STATUS_UNSUCCESSFUL; leave; } ctx->SectorSize = max(volProp->SectorSize ,MIN_SECTOR_SIZE); ctx->VolResource = X70FsdAllocateResource(); ctx->DeviceType = volProp->DeviceType; VolumeBuffer = FltAllocatePoolAlignedWithTag(FltObjects->Instance,NonPagedPool,sizeof(FILE_FS_SIZE_INFORMATION),'clu'); if(VolumeBuffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; leave; } status = FltQueryVolumeInformation( FltObjects->Instance, &IoStatus, VolumeBuffer, sizeof(FILE_FS_SIZE_INFORMATION), FileFsSizeInformation ); if (NT_SUCCESS(status)) { ctx->SectorsPerAllocationUnit = VolumeBuffer->SectorsPerAllocationUnit; } else { ctx->SectorsPerAllocationUnit = 1; //网络设备会返回失败。 } FltIsVolumeWritable(FltObjects->Volume,&ctx->IsWritable ); status = FltSetVolumeContext( FltObjects->Volume, FLT_SET_CONTEXT_KEEP_IF_EXISTS, ctx, NULL ); if (status == STATUS_FLT_CONTEXT_ALREADY_DEFINED) { status = STATUS_SUCCESS; } } finally { if (ctx != NULL) { FltReleaseContext( ctx ); } if(VolumeBuffer != NULL) { FltFreePoolAlignedWithTag(FltObjects->Instance,VolumeBuffer,'clu'); } } return status; }
NTSTATUS File_UpdateEntireFileByFileObject( __in PFLT_CALLBACK_DATA Data, __in PFLT_RELATED_OBJECTS FltObjects, __in PFILE_OBJECT FileObject, __in PSTREAM_CONTEXT pStreamCtx, __in PVOLUME_CONTEXT pVolCtx ) { NTSTATUS status = STATUS_SUCCESS ; PUCHAR Buffer = NULL ; LARGE_INTEGER ReadWriteOffset = {0} ; BOOLEAN EndOfFile = FALSE; ULONG uReadBytes = 0 ; ULONG uWriteBytes = 0 ; ULONG uAllocateBufferSize = 1024*64 ; ULONG uReadWriteLength = 0 ; ULONG uOffset = 0 ; LARGE_INTEGER FileSize = {0} ; PFILE_FLAG psFileFlag = NULL ; KIRQL OldIrql ; try{ //判断分配空间长度是否SectorSize对齐 if ((uAllocateBufferSize % pVolCtx->SectorSize) != 0) {//由于SectorSize目前为512bytes,故暂时先返回失败,以后可以对AllocateBufferSize进行调整 status = ERR_CORE_LENGTH_NOT_ALIGNED ; __leave ; } Buffer = FltAllocatePoolAlignedWithTag(FltObjects->Instance,PagedPool, uAllocateBufferSize, FILEFLAG_POOL_TAG); if (!Buffer) { status = STATUS_INSUFFICIENT_RESOURCES; __leave ; } //allocate local file flag buffer psFileFlag = (PFILE_FLAG)ExAllocatePoolWithTag(NonPagedPool, FILE_FLAG_LENGTH, FILEFLAG_POOL_TAG) ; if (NULL == psFileFlag) { status = STATUS_INSUFFICIENT_RESOURCES ; __leave ; } RtlCopyMemory(psFileFlag, g_psFileFlag, FILE_FLAG_LENGTH) ; //实际上这里应该是当前文件自身的flag //set current file size into file flag buffer File_GetFileSize(Data, FltObjects, &FileSize) ; psFileFlag->FileValidLength= FileSize.QuadPart ; //calculate padded file size if (FileSize.QuadPart % SECTOR_SIZE) {//file size is not multiply of sector size FileSize.QuadPart = FileSize.QuadPart + (SECTOR_SIZE - FileSize.QuadPart % SECTOR_SIZE) + FILE_FLAG_LENGTH ; } else {//file size is multiply of sector size FileSize.QuadPart += FILE_FLAG_LENGTH ; } RtlCopyMemory(psFileFlag->FileKeyHash, pStreamCtx->szKeyHash, HASH_SIZE) ; while (TRUE) { status = File_ReadWriteFile(IRP_MJ_READ, FltObjects->Instance, FileObject, &ReadWriteOffset, uAllocateBufferSize, Buffer, &uReadBytes, FLTFL_IO_OPERATION_NON_CACHED|FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET) ; if (!NT_SUCCESS(status)) break; if (0 == uReadBytes) break; if (KeGetCurrentIrql() > PASSIVE_LEVEL) ExAcquireSpinLock(&pVolCtx->FsCryptSpinLock, &OldIrql); else ExAcquireFastMutex(&pVolCtx->FsCtxTableMutex) ; ///if (data_crypt(pVolCtx->aes_ctr_ctx, Buffer, uOffset, uReadBytes)) ///{ /// if (KeGetCurrentIrql() > PASSIVE_LEVEL) /// ExReleaseSpinLock(&pVolCtx->FsCryptSpinLock, OldIrql) ; /// else /// ExReleaseFastMutex(&pVolCtx->FsCtxTableMutex) ; /// break ; ///} if (KeGetCurrentIrql() > PASSIVE_LEVEL) ExReleaseSpinLock(&pVolCtx->FsCryptSpinLock, OldIrql) ; else ExReleaseFastMutex(&pVolCtx->FsCtxTableMutex) ; if (uReadBytes < uAllocateBufferSize) EndOfFile = TRUE; status = File_ReadWriteFile(IRP_MJ_WRITE, FltObjects->Instance, FileObject, &ReadWriteOffset, uReadBytes, Buffer, &uWriteBytes, FLTFL_IO_OPERATION_NON_CACHED|FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET) ; if (!NT_SUCCESS(status)) break; if (EndOfFile) break; uOffset += uAllocateBufferSize ; ReadWriteOffset.QuadPart += uAllocateBufferSize ; RtlZeroMemory(Buffer, uAllocateBufferSize) ; } // write file flag ReadWriteOffset.QuadPart = FileSize.QuadPart - FILE_FLAG_LENGTH ; File_ReadWriteFile(IRP_MJ_WRITE, FltObjects->Instance, FileObject, &ReadWriteOffset, FILE_FLAG_LENGTH, psFileFlag, &uWriteBytes, FLTFL_IO_OPERATION_NON_CACHED|FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET) ; } finally{ if (Buffer) { FltFreePoolAlignedWithTag(FltObjects->Instance, Buffer, FILEFLAG_POOL_TAG); Buffer = NULL ; } if (psFileFlag) { ExFreePoolWithTag(psFileFlag, FILEFLAG_POOL_TAG) ; psFileFlag = NULL ; } } return status; }