阅读:6805回复:5
突破FltQueryInformation / FltSetInformation / FltReadFile / FltWriteFile 的PASSIVE_LEVEL限制
[ 原创 ] [ http://hi.baidu.com/devxa/blog ]
由于工作原因要经常和Minifilter框架打交道, 使用过Minifilter框架的应该都知道 FltQueryInformation / FltSetInformation / FltReadFile / FltWriteFile 这四个关键 接口只能在PASSIVE_LEVEL级别使用, 但是有时你可能会有这样的想法: 比如,我想在 PAGING_IO时查询文件属性或读取文件数据该怎么办呢? 要实现这个想法首先你得自己 下发请求, 只有这样你才能突破PASSIVE_LEVEL的限制.如何自己下发请求在Minifilter的 官方资料中却未提及,这里我公布出自己逆向的Minifilter代码供大家参考: // // Ex接口克服了PASSIVE_LEVEL中断级的限制,以便可以在APC_LEVEL正常使用 // NTSTATUS FltQueryInformationFileEx( IN PFLT_INSTANCE InitiatingInstance, IN PFILE_OBJECT FileObject, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass, OUT PULONG LengthReturned OPTIONAL ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PFLT_CALLBACK_DATA Cbd = NULL; do { if( !InitiatingInstance || !FileObject || !FileInformation || !Length ) { status = STATUS_INVALID_PARAMETER; break; } status = FltAllocateCallbackData( InitiatingInstance, FileObject, &Cbd ); if(!NT_SUCCESS(status)) break; Cbd->Iopb->MajorFunction = IRP_MJ_QUERY_INFORMATION; Cbd->Iopb->Parameters.QueryFileInformation.FileInformationClass = FileInformationClass; Cbd->Iopb->Parameters.QueryFileInformation.InfoBuffer = FileInformation; Cbd->Iopb->Parameters.QueryFileInformation.Length = Length; FltPerformSynchronousIo( Cbd ); status = CallbackData->IoStatus.Status; if(LengthReturned) *LengthReturned = CallbackData->IoStatus.Information; FltFreeCallbackData( Cbd ); } while(0); return status; } // ----------------------------------------------------------------------------------- NTSTATUS FltPrepareRenameOrSetLinkInfo( IN PFLT_INSTANCE Instance, IN PFILE_OBJECT FileObject, IN PFLT_CALLBACK_DATA Cbd, IN PVOID FileInformation, OUT PFILE_OBJECT *RetObjectPtr ) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PFILE_RENAME_INFORMATION fri = NULL; PFILE_LINK_INFORMATION fli = NULL; FILE_BASIC_INFORMATION fbi = {0}; UNICODE_STRING fileName = {0}; ULONG desiredAccessFlag = 0; ULONG attributes = 0; OBJECT_ATTRIBUTES objectAttribs = {0}; IO_STATUS_BLOCK ioStatusBlock = {0}; PFLT_FILTER Filter = NULL; PFILE_OBJECT retFileObject = NULL; HANDLE retFileHandle = NULL; PDEVICE_OBJECT deviceObject1 = NULL, deviceObject2 = NULL; if( Instance == NULL) return STATUS_INVALID_PARAMETER; desiredAccessFlag = 2; fri = (PFILE_RENAME_INFORMATION)FileInformation; fli = (PFILE_LINK_INFORMATION)FileInformation; if( !FlagOn( FileObject->Flags, FO_DIRECT_DEVICE_OPEN ) ) { Status = FltQueryInformationFile( Instance, FileObject, &fbi, sizeof(fbi), FileBasicInformation, NULL ); if( NT_SUCCESS(Status) ) { if( FlagOn( fbi.FileAttributes, FILE_ATTRIBUTE_DIRECTORY ) ) desiredAccessFlag = 4; } else return Status; } fileName.Length = fileName.MaximumLength = fri->FileNameLength; fileName.Buffer = &fri->FileName[0]; attributes = FileObject->Flags; attributes = ( ( ( ~( attributes >> 0x0B ) ) & 0x40 ) | 0x200 ); InitializeObjectAttributes( &objectAttribs, &fileName, attributes, fri->RootDirectory, NULL ); // 获取和Instance关联的Filter对象, // 在正式产品中建议由用户传入Filter对象, // 因为在MInifilter驱动加载时我们肯定知道Filter对象 __asm { mov eax, Instance mov eax, dword ptr [eax+0x1C] mov Filter, eax } Status = FltCreateFileEx( Filter, Instance, &retFileHandle, &retFileObject, SYNCHRONIZE|desiredAccessFlag, &objectAttribs, &ioStatusBlock, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT, NULL, 0, 0x105 // IO_FORCE_ACCESS_CHECK|IO_NO_PARAMETER_CHECKING|0x4 ); if( NT_SUCCESS(Status) ) { ObDereferenceObject( retFileObject ); if( Cbd->Iopb->Parameters.SetFileInformation.FileInformationClass == FileLinkInformation ) { if( fli->ReplaceIfExists == FALSE ) { if( ioStatusBlock.Information == FILE_EXISTS ) { FltClose( retFileHandle ); Status = STATUS_OBJECT_NAME_COLLISION; return Status; } } } deviceObject1 = IoGetBaseFileSystemDeviceObject( retFileObject ); deviceObject2 = IoGetBaseFileSystemDeviceObject( FileObject ); if( deviceObject1 != deviceObject2 ) { FltClose( retFileHandle ); Status = STATUS_NOT_SAME_DEVICE; return Status; } else { Cbd->Iopb->Parameters.SetFileInformation.ParentOfTarget = retFileObject; *RetObjectPtr = retFileHandle; Status = STATUS_SUCCESS; } } return Status; } NTSTATUS FltSetInformationFileEx ( IN PFLT_INSTANCE Instance, IN PFILE_OBJECT FileObject, IN PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass ) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PFLT_CALLBACK_DATA Cbd = NULL; PFILE_OBJECT RetObject = NULL; Status = FltAllocateCallbackData( Instance, FileObject, &Cbd ); if( NT_SUCCESS(Status) ) { Cbd->Iopb->MajorFunction = IRP_MJ_SET_INFORMATION; Cbd->Iopb->Parameters.SetFileInformation.FileInformationClass = FileInformationClass; Cbd->Iopb->Parameters.SetFileInformation.Length = Length; Cbd->Iopb->Parameters.SetFileInformation.ParentOfTarget = NULL; Cbd->Iopb->Parameters.SetFileInformation.DeleteHandle = NULL; Cbd->Iopb->Parameters.SetFileInformation.InfoBuffer = FileInformation; if( FileInformationClass >= FileRenameInformation ) { if( FileInformationClass <= FileLinkInformation ) { // // 在这个区间中的只有FileRenameInformation和FileLinkInformation // 两种类型的请求,而FILE_RENAME_INFORMATION和FILE_LINK_INFORMATION // 的结构定义又完全一致! // PFILE_RENAME_INFORMATION fri = (PFILE_RENAME_INFORMATION)FileInformation; Cbd->Iopb->Parameters.SetFileInformation.ReplaceIfExists = fri->ReplaceIfExists; if( fri->FileName[0] != L'\\' ) { if( fri->RootDirectory != NULL ) { Status = FltPrepareRenameOrSetLinkInfo( Instance, FileObject, Cbd, FileInformation, &RetObject ); if( !NT_SUCCESS(Status) ) { FltFreeCallbackData( Cbd ); return Status; } } } else { Status = FltPrepareRenameOrSetLinkInfo( Instance, FileObject, Cbd, FileInformation, &RetObject ); if( !NT_SUCCESS(Status) ) { FltFreeCallbackData( Cbd ); return Status; } } } else if( FileInformationClass == FileMoveClusterInformation ) { PFILE_MOVE_CLUSTER_INFORMATION fmci = (PFILE_MOVE_CLUSTER_INFORMATION)FileInformation; Cbd->Iopb->Parameters.SetFileInformation.ClusterCount = fmci->ClusterCount; } } FltPerformSynchronousIo( Cbd ); Status = Cbd->IoStatus.Status; FltFreeCallbackData( Cbd ); if( RetObject != NULL ) { FltClose( RetObject ); } } return Status; } // ----------------------------------------------------------------------------------- NTSTATUS FltReadFileEx ( IN PFLT_INSTANCE InitiatingInstance, IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER ByteOffset, OUT PVOID Buffer, IN ULONG Length, IN FLT_IO_OPERATION_FLAGS Flags, OUT PULONG BytesRead OPTIONAL, IN PFLT_COMPLETED_ASYNC_IO_CALLBACK CallbackRoutine OPTIONAL, IN PVOID CallbackContext OPTIONAL ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PFLT_CALLBACK_DATA Cbd = NULL; LARGE_INTEGER old_bytes_offset = {0}; LARGE_INTEGER final_byte_offset = {0}; BOOLEAN isNonCachedIo = FALSE; BOOLEAN dontUpdateByteOffset = FALSE; do { if( !InitiatingInstance || !FileObject || !Buffer ) { status = STATUS_INVALID_PARAMETER; break; } if(CallbackRoutine) { status = STATUS_NOT_SUPPORTED; break; } if(!Length) break; if(BytesRead) *BytesRead = 0; if( FlagOn( FileObject->Flags, FO_SYNCHRONOUS_IO ) ) { if( FlagOn( Flags, FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET ) ) { dontUpdateByteOffset = TRUE; } } if( ByteOffset ) { final_byte_offset = *ByteOffset; } else { final_byte_offset = FileObject->CurrentByteOffset; } if( FlagOn( Flags, FLTFL_IO_OPERATION_NON_CACHED ) || FlagOn( Flags, FLTFL_IO_OPERATION_PAGING ) || FlagOn( FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ) ) { isNonCachedIo = TRUE; } else { isNonCachedIo = FALSE; } status = FltAllocateCallbackData( InitiatingInstance, FileObject, &Cbd ); if (!NT_SUCCESS(status)) { return status; } if( dontUpdateByteOffset ) { old_bytes_offset = FileObject->CurrentByteOffset; } Cbd->Iopb->MajorFunction = IRP_MJ_READ; Cbd->Iopb->Parameters.Write.ByteOffset = final_byte_offset; Cbd->Iopb->Parameters.Write.Length = Length; Cbd->Iopb->Parameters.Write.WriteBuffer = Buffer; Cbd->Iopb->IrpFlags = 0; SetFlag( Cbd->Iopb->IrpFlags, IRP_READ_OPERATION ); if( isNonCachedIo ) SetFlag( Cbd->Iopb->IrpFlags, IRP_NOCACHE ); if( FlagOn(FLTFL_IO_OPERATION_PAGING, Flags) ) { SetFlag(Cbd->Iopb->IrpFlags, IRP_PAGING_IO); } FltPerformSynchronousIo( Cbd ); if( dontUpdateByteOffset ) { FileObject->CurrentByteOffset = old_bytes_offset; } status = Cbd->IoStatus.Status; if(BytesRead) *BytesRead = Cbd->IoStatus.Information; FltFreeCallbackData(Cbd); break; } while(0); return status; } // ----------------------------------------------------------------------------------- // // FltWriteFile接口 // NTSTATUS FltWriteFileEx ( IN PFLT_INSTANCE InitiatingInstance, IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER ByteOffset, IN ULONG Length, OUT PVOID Buffer, IN FLT_IO_OPERATION_FLAGS Flags, OUT PULONG BytesWrite OPTIONAL, IN PFLT_COMPLETED_ASYNC_IO_CALLBACK CallbackRoutine OPTIONAL, IN PVOID CallbackContext OPTIONAL ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PFLT_CALLBACK_DATA Cbd = NULL; LARGE_INTEGER old_bytes_offset = {0}; LARGE_INTEGER final_byte_offset = {0}; BOOLEAN isNonCachedIo = FALSE; BOOLEAN dontUpdateByteOffset = FALSE; do { if( !InitiatingInstance || !FileObject || !Buffer ) { status = STATUS_INVALID_PARAMETER; break; } if(CallbackRoutine) { status = STATUS_NOT_SUPPORTED; break; } if(!Length) break; if(BytesWrite) *BytesWrite = 0; if( FlagOn( FileObject->Flags, FO_SYNCHRONOUS_IO ) ) { if( FlagOn( Flags, FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET ) ) { dontUpdateByteOffset = TRUE; } } if( ByteOffset ) { final_byte_offset = *ByteOffset; } else { final_byte_offset = FileObject->CurrentByteOffset; } if( FlagOn( Flags, FLTFL_IO_OPERATION_NON_CACHED ) || FlagOn( Flags, FLTFL_IO_OPERATION_PAGING ) || FlagOn( FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ) ) { isNonCachedIo = TRUE; } else { isNonCachedIo = FALSE; } status = FltAllocateCallbackData( InitiatingInstance, FileObject, &Cbd ); if (!NT_SUCCESS(status)) { return status; } if( dontUpdateByteOffset ) { old_bytes_offset = FileObject->CurrentByteOffset; } Cbd->Iopb->MajorFunction = IRP_MJ_WRITE; Cbd->Iopb->Parameters.Write.ByteOffset = final_byte_offset; Cbd->Iopb->Parameters.Write.Length = Length; Cbd->Iopb->Parameters.Write.WriteBuffer = Buffer; Cbd->Iopb->IrpFlags = 0; if( FlagOn( FileObject->Flags, FO_WRITE_THROUGH ) ) { Cbd->Iopb->OperationFlags = SL_WRITE_THROUGH; } SetFlag( Cbd->Iopb->IrpFlags, IRP_WRITE_OPERATION ); if( isNonCachedIo ) SetFlag( Cbd->Iopb->IrpFlags, IRP_NOCACHE ); if( FlagOn(FLTFL_IO_OPERATION_PAGING, Flags) ) { SetFlag(Cbd->Iopb->IrpFlags, IRP_PAGING_IO); } FltPerformSynchronousIo( Cbd ); if( dontUpdateByteOffset ) { FileObject->CurrentByteOffset = old_bytes_offset; } status = Cbd->IoStatus.Status; if(BytesWrite) *BytesWrite = Cbd->IoStatus.Information; FltFreeCallbackData( Cbd ); break; } while(0); return status; } 其中FltReadFileEx 和 FltWriteFileEx 两个接口暂不支持异步IO, 因为异步IO涉及到MInifilter框架内部 未公开的数据结构, 所以实现起来比较麻烦. 不过基本上同步IO已经够用了. |
|
|
沙发#
发布于:2009-09-03 09:38
这好的贴居然没人顶...
|
|
板凳#
发布于:2009-09-03 12:06
厉害,好贴,鼓掌
|
|
|
地板#
发布于:2009-09-03 14:30
您太厉害了,拜一个
|
|
|
地下室#
发布于:2010-10-13 09:53
好贴啊.拿回去用用
|
|
5楼#
发布于:2010-10-16 15:58
牛
|
|