EXTERN_C static NTSTATUS ScvnpWriteFile(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ const wchar_t *OutPathW, _In_ void *Buffer, _In_ ULONG BufferSize, _In_ ULONG CreateDisposition) { PAGED_CODE(); UNICODE_STRING outPath = {}; RtlInitUnicodeString(&outPath, OutPathW); OBJECT_ATTRIBUTES objAttr = RTL_INIT_OBJECT_ATTRIBUTES( &outPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE); HANDLE fileHandle = nullptr; IO_STATUS_BLOCK ioStatus = {}; auto status = FltCreateFile( FltObjects->Filter, FltObjects->Instance, &fileHandle, GENERIC_WRITE, &objAttr, &ioStatus, nullptr, FILE_ATTRIBUTE_NORMAL, 0, CreateDisposition, FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, nullptr, 0, 0); if (status == STATUS_OBJECT_NAME_COLLISION || status == STATUS_DELETE_PENDING) { return status; } if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("FltCreateFile failed (%08x) for %S", status, OutPathW); return status; } PFILE_OBJECT fileObject = nullptr; status = ObReferenceObjectByHandle(fileHandle, 0, nullptr, KernelMode, reinterpret_cast<void **>(&fileObject), nullptr); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("ObReferenceObjectByHandle failed (%08x) for %S", status, OutPathW); goto End; } status = FltWriteFile(FltObjects->Instance, fileObject, nullptr, BufferSize, Buffer, 0, nullptr, nullptr, nullptr); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("FltWriteFile failed (%08x) for %S", status, OutPathW); goto End; } End: if (fileObject) { ObDereferenceObject(fileObject); } if (fileHandle) { FltClose(fileHandle); } return status; }
/*--------------------------------------------------------- 函数名称: FileCreateForHeaderWriting 函数描述: 在文件被打开前先通过该对象打开文件 输入参数: pfiInstance 过滤器实例 pfniFileNameInformation 文件名信息 phFileHandle 保存文件句柄的空间 输出参数: phFileHandle 文件句柄 返回值: STATUS_SUCCESS 成功 STATUS_OBJECT_NAME_NOT_FOUND 未查询到名称 其他: 如果查询名称失败(根本无名称)将返回 STATUS_OBJECT_NAME_NOT_FOUND 打开后需要使用FltClose关闭文件 更新维护: 2011.5.2 最初版本 ---------------------------------------------------------*/ NTSTATUS FileCreateForHeaderWriting( __in PFLT_INSTANCE pfiInstance, __in PUNICODE_STRING puniFileName, __out HANDLE * phFileHandle ) { //对象属性,用于打开文件时使用 OBJECT_ATTRIBUTES oaObjectAttributes; //文件路径长度 ULONG ulPathLength; //返回的Io状态 IO_STATUS_BLOCK ioStatusBlock; //返回的状态 NTSTATUS statusRet; // //填充数据 // InitializeObjectAttributes( &oaObjectAttributes, puniFileName, OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE, NULL, NULL ); // //为了兼容Windows Xp,使用FltCreateFile // return FltCreateFile( pfltGlobalFilterHandle, pfiInstance, phFileHandle, FILE_READ_DATA|FILE_WRITE_DATA, &oaObjectAttributes, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0, IO_IGNORE_SHARE_ACCESS_CHECK ); }
BOOLEAN getSizeModified( _In_ PFLT_INSTANCE instance, _In_ PUNICODE_STRING fileName, _Inout_ LONGLONG *size, _Inout_ LONGLONG *modified ) { NTSTATUS status; HANDLE FileHandle = NULL; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatus; FILE_BASIC_INFORMATION basicFileInfo; FILE_STANDARD_INFORMATION standardFileInfo; InitializeObjectAttributes(&objectAttributes, fileName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, NULL, NULL); status = FltCreateFile( ClaimsmanData.Filter, instance, &FileHandle, FILE_READ_DATA | FILE_READ_ATTRIBUTES, &objectAttributes, &ioStatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0, IO_NO_PARAMETER_CHECKING ); if (!NT_SUCCESS(status)) { return FALSE; } status = ZwQueryInformationFile(FileHandle, &ioStatus, &basicFileInfo, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (!NT_SUCCESS(status)) { ZwClose(FileHandle); return FALSE; } status = ZwQueryInformationFile(FileHandle, &ioStatus, &standardFileInfo, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); if (!NT_SUCCESS(status)) { ZwClose(FileHandle); return FALSE; } *modified = (basicFileInfo.ChangeTime.QuadPart - DIFF_TO_UNIX_EPOCH) / 10000; *size = standardFileInfo.EndOfFile.QuadPart; ZwClose(FileHandle); return TRUE; }
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 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; }
/*--------------------------------------------------------- 函数名称: FileCreateByObjectNotCreated 函数描述: 在文件被打开前先通过该对象打开文件 输入参数: pfiInstance 过滤器实例 pfoFileObject 文件对象 pfpParameters IRP参数 phFileHandle 保存文件句柄的空间 ulDesiredAccess 期望的权限 输出参数: phFileHandle 文件句柄 返回值: STATUS_SUCCESS 成功 STATUS_OBJECT_NAME_NOT_FOUND 未查询到名称 其他: 如果查询名称失败(根本无名称)将返回 STATUS_OBJECT_NAME_NOT_FOUND 如果要同传入的文件对象权限一致,ulDesiredAccess 可以置为NULL 打开后需要使用FltClose关闭文件 更新维护: 2011.5.2 最初版本 2011.7.28 修改了部分参数 2012.1.2 Bug:返回值为成功打开,但句柄无效 ---------------------------------------------------------*/ NTSTATUS FileCreateByObjectNotCreated( __in PFLT_INSTANCE pfiInstance, __in PFLT_FILE_NAME_INFORMATION pfniFileNameInformation, __in PFLT_PARAMETERS pfpParameters, __in_opt ULONG ulDesiredAccess, __out HANDLE * phFileHandle ) { //读取的数据内容 用于同加密标识比较 WCHAR wBufferRead[ENCRYPTION_HEAD_LOGO_SIZE] = {0}; //文件属性 ULONG FileAttributes; //共享权限 ULONG ShareAccess; //打开处理 ULONG CreateDisposition; //打开选项 ULONG CreateOptions; //对象属性,用于打开文件时使用 OBJECT_ATTRIBUTES oaObjectAttributes; //文件路径长度 ULONG ulPathLength; //返回的Io状态 IO_STATUS_BLOCK ioStatusBlock; //返回的状态 NTSTATUS statusRet; // //填充数据 // InitializeObjectAttributes( &oaObjectAttributes, &pfniFileNameInformation->Name, OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE, NULL, NULL ); CreateDisposition = pfpParameters->Create.Options>>24; CreateOptions = pfpParameters->Create.Options & 0x00ffffff; ShareAccess = pfpParameters->Create.ShareAccess; FileAttributes = pfpParameters->Create.FileAttributes; // //保存访问权限的值 如果没有设置 // if(!ulDesiredAccess){ ulDesiredAccess = pfpParameters -> Create.SecurityContext -> DesiredAccess; } // //为了兼容Windows Xp,使用FltCreateFile // return FltCreateFile( pfltGlobalFilterHandle, pfiInstance, phFileHandle, ulDesiredAccess, &oaObjectAttributes, &ioStatusBlock, NULL, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, NULL, NULL, IO_IGNORE_SHARE_ACCESS_CHECK ); }
NTSTATUS FmmOpenMetadata ( __in PFMM_INSTANCE_CONTEXT InstanceContext, __in BOOLEAN CreateIfNotPresent ) /*++ Routine Description: This routine opens or creates the Fmm metadata on the specified instance. Arguments: InstanceContext - Supplies the instance context for this instance. CreateIfNotPresent - Supplies if the directory entry must be created if it is not present Return Value: Returns the status of this operation. Note: The caller must hold the instance context resource exclusive when this routine is called. --*/ { OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatus; UNICODE_STRING fileName; NTSTATUS status; ULONG length; PAGED_CODE(); DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: Opening metadata file ... (Volume = %p, CreateIfNotPresent = %X)\n", InstanceContext->Volume, CreateIfNotPresent) ); status = STATUS_SUCCESS; fileName.Buffer = NULL; // // Get the volume name and construct the full metadata filename. // length = FMM_DEFAULT_VOLUME_NAME_LENGTH + FMM_METADATA_FILE_NAME_LENGTH; #pragma warning(push) #pragma warning(disable:4127) // Conditional expression is constant while (TRUE) { #pragma warning(pop) fileName.MaximumLength = (USHORT)length; status = FmmAllocateUnicodeString( &fileName ); if (!NT_SUCCESS( status )) { goto FmmOpenMetadataCleanup; } status = FltGetVolumeName( InstanceContext->Volume, &fileName, &length ); if (NT_SUCCESS( status )) { status = RtlAppendUnicodeToString( &fileName, FMM_METADATA_FILE_NAME ); if (NT_SUCCESS( status )) { break; } } else { DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS | DEBUG_TRACE_ERROR, ("[Fmm]: Failed to get volume name (Volume = %p, Status = 0x%x)\n", InstanceContext->Volume, status) ); } if (status != STATUS_BUFFER_TOO_SMALL) { goto FmmOpenMetadataCleanup;; } // // Free the filename buffer since a bigger one will be allocated // above // FmmFreeUnicodeString( &fileName ); length += FMM_METADATA_FILE_NAME_LENGTH; } // // Initialize the object attributes and open the file. // InitializeObjectAttributes( &objectAttributes, &fileName, OBJ_KERNEL_HANDLE, NULL, NULL ); RetryFltCreateFile: DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: Calling FltCreateFile for metadata file %wZ (Volume = %p, Status = 0x%x)\n", &fileName, InstanceContext->Volume, status) ); // // Mark the beginning of a file system operation // FmmBeginFileSystemOperation( InstanceContext ); status = FltCreateFile( Globals.Filter, InstanceContext->Instance, &InstanceContext->MetadataHandle, FILE_ALL_ACCESS, &objectAttributes, &ioStatus, (PLARGE_INTEGER) NULL, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, FILE_SHARE_READ, (CreateIfNotPresent ? FILE_OPEN_IF : FILE_OPEN), 0L, NULL, 0L, 0 ); // // Mark the end of a file system operation // FmmEndFileSystemOperation( InstanceContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS | DEBUG_TRACE_ERROR, ("[Fmm]: FltCreateFile failure for metadata file %wZ (Volume = %p, Status = 0x%x)\n", &fileName, InstanceContext->Volume, status) ); if (CreateIfNotPresent && (status == STATUS_OBJECT_PATH_NOT_FOUND)) { // // We need to create the metadata file and the creation failed // because the SystemVolumeInformation folder does not exist. // So, create the folder and try again. // DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: Creating SystemVolumeInformation folder for metadata file %wZ (Volume = %p, Status = 0x%x)\n", &fileName, InstanceContext->Volume, status) ); // // Mark the beginning of a file system operation // FmmBeginFileSystemOperation( InstanceContext ); status = FltCreateSystemVolumeInformationFolder( InstanceContext->Instance ); // // Mark the end of a file system operation // FmmEndFileSystemOperation( InstanceContext ); if (NT_SUCCESS( status )) { // // We have sucessfully created the SystemVolumeInformation folder // Try to create the metadata file again // goto RetryFltCreateFile; } else { DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS | DEBUG_TRACE_ERROR, ("[Fmm]: FltCreateSystemVolumeInformationFolder failure for metadata file %wZ (Volume = %p, Status = 0x%x)\n", &fileName, InstanceContext->Volume, status) ); } } goto FmmOpenMetadataCleanup; } // // Retrieve the FileObject from the handle created // status = ObReferenceObjectByHandle( InstanceContext->MetadataHandle, STANDARD_RIGHTS_REQUIRED, *IoFileObjectType, KernelMode, &InstanceContext->MetadataFileObject, NULL ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS | DEBUG_TRACE_ERROR, ("[Fmm]: Failure to get file object from handle for metadata file %wZ (Volume = %p, Status = 0x%x)\n", &fileName, InstanceContext->Volume, status) ); goto FmmOpenMetadataCleanup; } if (ioStatus.Information == FILE_CREATED) { // // New metadata was created // DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: Created new metadata file %wZ (Volume = %p, Status = 0x%x)\n", &fileName, InstanceContext->Volume, status) ); // // The filter may want to do some initialization on the newly created // metadata file here like adding a header to the file // } else { // // Existing metadata was opened // DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: Opened existing metadata file %wZ (Volume = %p, Status = 0x%x)\n", &fileName, InstanceContext->Volume, status) ); // // The filter may want to do some sanity checks on the metadata file here // like validating the header of the file // } // // Here the filter may read the metadata contents and initialize // its in memory data structures with the data from the metadata // file // FmmOpenMetadataCleanup: if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS | DEBUG_TRACE_ERROR, ("[Fmm]: Failed to open metadata (Volume = %p, Status = 0x%x)\n", InstanceContext->Volume, status) ); // // CLose the handle and dereference the file object // if (InstanceContext->MetadataHandle) { // // Mark the beginning of a file system operation // FmmBeginFileSystemOperation( InstanceContext ); FltClose( InstanceContext->MetadataHandle ); // // Mark the end of a file system operation // FmmEndFileSystemOperation( InstanceContext ); InstanceContext->MetadataHandle = NULL; if (InstanceContext->MetadataFileObject) { ObDereferenceObject( InstanceContext->MetadataFileObject ); InstanceContext->MetadataFileObject = NULL; } } } else { DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: Metadata successfully opened (Volume = %p)\n", InstanceContext->Volume) ); // // Set flags to indicate successful open of filter metadata // SetFlag( InstanceContext->Flags, INSTANCE_CONTEXT_F_METADATA_OPENED ); } if (fileName.Buffer != NULL) { FmmFreeUnicodeString( &fileName ); } return status; }