NTSTATUS File_GetFileStandardInfo( __in PFLT_CALLBACK_DATA Data, __in PFLT_RELATED_OBJECTS FltObjects, __in PLARGE_INTEGER FileAllocationSize, __in PLARGE_INTEGER FileSize, __in PBOOLEAN bDirectory ) { NTSTATUS status = STATUS_SUCCESS ; FILE_STANDARD_INFORMATION sFileStandardInfo ; //修改为向下层Call status = FltQueryInformationFile(FltObjects->Instance, FltObjects->FileObject, &sFileStandardInfo, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation, NULL ) ; if (NT_SUCCESS(status)) { if (NULL != FileSize) *FileSize = sFileStandardInfo.EndOfFile ; if (NULL != FileAllocationSize) *FileAllocationSize = sFileStandardInfo.AllocationSize ; if (NULL != bDirectory) *bDirectory = sFileStandardInfo.Directory ; } return status ; }
NTSTATUS File_GetFileSize( __in PFLT_CALLBACK_DATA Data, __in PFLT_RELATED_OBJECTS FltObjects, __in PLARGE_INTEGER FileSize ) { NTSTATUS status; FILE_STANDARD_INFORMATION fileInfo ; //修改为向下层Call status = FltQueryInformationFile(FltObjects->Instance, FltObjects->FileObject, &fileInfo, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation, NULL ) ; if (NT_SUCCESS(status)) { FileSize->QuadPart = fileInfo.EndOfFile.QuadPart ; } else { FileSize->QuadPart = 0 ; } return status; }
NTSTATUS File_GetFileOffset( __in PFLT_CALLBACK_DATA Data, __in PFLT_RELATED_OBJECTS FltObjects, __out PLARGE_INTEGER FileOffset ) { NTSTATUS status; FILE_POSITION_INFORMATION NewPos; //修改为向下层Call status = FltQueryInformationFile(FltObjects->Instance, FltObjects->FileObject, &NewPos, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation, NULL ) ; if(NT_SUCCESS(status)) { FileOffset->QuadPart = NewPos.CurrentByteOffset.QuadPart; } return status; }
/*--------------------------------------------------------- 函数名称: FileGetStandardInformation 函数描述: 非重入获取文件基本信息 输入参数: pfiInstance 过滤器实例 pfoFileObject 文件对象 pnAllocateSize 申请大小 pnFileSize 文件大小 pbDirectory 是否是目录 输出参数: 返回值: STATUS_SUCCESS 成功 否则返回相应状态 其他: 后三项参数为可选,不需要查询置为NULL即可 更新维护: 2011.4.3 最初版本 2011.4.9 修改为使用FltXXX版本 ---------------------------------------------------------*/ NTSTATUS FileGetStandardInformation( __in PFLT_INSTANCE pfiInstance, __in PFILE_OBJECT pfoFileObject, __inout_opt PLARGE_INTEGER pnAllocateSize, __inout_opt PLARGE_INTEGER pnFileSize, __inout_opt BOOLEAN *pbDirectory ) { //返回值 NTSTATUS status; PFILE_STANDARD_INFORMATION psiFileStandardInformation; // //首先分配内存 准备查询 如果失败 返回资源不足 // psiFileStandardInformation = (PFILE_STANDARD_INFORMATION) ExAllocatePoolWithTag(NonPagedPool,sizeof(FILE_STANDARD_INFORMATION),MEM_FILE_TAG); if( !psiFileStandardInformation ){ return STATUS_INSUFFICIENT_RESOURCES; } // //查询信息 如果成功就筛选信息,否则直接返回 // status = FltQueryInformationFile( pfiInstance,//实例 防止重入 pfoFileObject, (PVOID)psiFileStandardInformation, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation, NULL//不需要了解返回了多少数据 ); if(NT_SUCCESS(status)){ if(pnAllocateSize){ *pnAllocateSize = psiFileStandardInformation ->AllocationSize; } if(pnFileSize){ *pnFileSize = psiFileStandardInformation -> EndOfFile; } if(pbDirectory != NULL){ *pbDirectory = psiFileStandardInformation -> Directory; } } ExFreePool(psiFileStandardInformation); 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; }
NTSTATUS CopyFile( PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PUNICODE_STRING pCompleteFileName ) { NTSTATUS status; UNICODE_STRING tempDeletedFilePath; OBJECT_ATTRIBUTES tempDeletedObject; IO_STATUS_BLOCK ioStatusTempDeleted; LARGE_INTEGER allocate; FILE_STANDARD_INFORMATION fileStandardInformation; HANDLE tempDeletedHandle; ULONG returnedLength; allocate.QuadPart = 0x10000; InitializeObjectAttributes( &tempDeletedObject, pCompleteFileName, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = FltQueryInformationFile( FltObjects->Instance, Data->Iopb->TargetFileObject, &fileStandardInformation, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation, &returnedLength ); if(NT_SUCCESS(status)) { allocate.QuadPart = fileStandardInformation.AllocationSize.QuadPart; } else { DbgPrint("CaptureFileMonitor: ERROR - Could not get files allocation size\n"); return status; } status = FltCreateFile( FltObjects->Filter, NULL, &tempDeletedHandle, GENERIC_WRITE, &tempDeletedObject, &ioStatusTempDeleted, &allocate, FILE_ATTRIBUTE_NORMAL, 0, FILE_CREATE, FILE_NON_DIRECTORY_FILE, NULL, 0, 0 ); if(NT_SUCCESS(status)) { PVOID handleFileObject; PVOID pFileBuffer; LARGE_INTEGER offset; ULONG bytesRead = 0; ULONG bytesWritten = 0; offset.QuadPart = 0; status = ObReferenceObjectByHandle( tempDeletedHandle, 0, NULL, KernelMode, &handleFileObject, NULL); if(!NT_SUCCESS(status)) { DbgPrint("CaptureFileMonitor: ERROR - ObReferenceObjectByHandle - FAILED - %08x\n", status); return status; } pFileBuffer = ExAllocatePoolWithTag(NonPagedPool, 65536, FILE_POOL_TAG); if(pFileBuffer != NULL) { ObReferenceObject(Data->Iopb->TargetFileObject); do { IO_STATUS_BLOCK IoStatusBlock; bytesWritten = 0; status = FltReadFile( FltObjects->Instance, Data->Iopb->TargetFileObject, &offset, 65536, pFileBuffer, FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET, &bytesRead , NULL, NULL ); if(NT_SUCCESS(status) && bytesRead > 0) { /* You can't use FltWriteFile here */ /* Instance may not be the same instance we want to write to eg a flash drive writing a file to a ntfs partition */ status = ZwWriteFile( tempDeletedHandle, NULL, NULL, NULL, &IoStatusBlock, pFileBuffer, bytesRead, &offset, NULL ); if(NT_SUCCESS(status)) { //DbgPrint("WriteFile: FltReadFile - %08x\n", status); } /* status = FltWriteFile( FltObjects->Instance, handleFileObject, &offset, bytesRead, pFileBuffer, FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET, &bytesWritten, NULL, NULL ); */ } else { //DbgPrint("CopyFile: FltReadFile - %08x\n", status); break; } offset.QuadPart += bytesRead; } while(bytesRead == 65536); ObDereferenceObject(Data->Iopb->TargetFileObject); ExFreePoolWithTag(pFileBuffer, FILE_POOL_TAG); } ObDereferenceObject(handleFileObject); FltClose(tempDeletedHandle); } else { if(status != STATUS_OBJECT_NAME_COLLISION) { DbgPrint("CaptureFileMonitor: ERROR - FltCreateFile FAILED - %08x\n",status); return status; } } return STATUS_SUCCESS; }