devia
论坛版主
论坛版主
  • 注册日期2005-05-14
  • 最后登录2016-04-05
  • 粉丝3
  • 关注0
  • 积分1029分
  • 威望712点
  • 贡献值1点
  • 好评度555点
  • 原创分8分
  • 专家分4分
阅读:6805回复:5

突破FltQueryInformation / FltSetInformation / FltReadFile / FltWriteFile 的PASSIVE_LEVEL限制

楼主#
更多 发布于:2009-09-02 16:20
[ 原创 ] [ 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已经够用了.
人总在矛盾中徘徊。。。
neak47
驱动小牛
驱动小牛
  • 注册日期2009-05-25
  • 最后登录2016-01-09
  • 粉丝4
  • 关注0
  • 积分140分
  • 威望1221点
  • 贡献值1点
  • 好评度0点
  • 原创分0分
  • 专家分1分
沙发#
发布于:2009-09-03 09:38
这好的贴居然没人顶...
cyliu
论坛版主
论坛版主
  • 注册日期2003-06-13
  • 最后登录2014-04-11
  • 粉丝5
  • 关注0
  • 积分1238分
  • 威望2531点
  • 贡献值0点
  • 好评度577点
  • 原创分14分
  • 专家分10分
板凳#
发布于:2009-09-03 12:06
厉害,好贴,鼓掌
走走看看开源好 Solaris vs Linux
looksail
荣誉会员
荣誉会员
  • 注册日期2005-05-22
  • 最后登录2014-03-15
  • 粉丝2
  • 关注0
  • 积分1016分
  • 威望991点
  • 贡献值0点
  • 好评度239点
  • 原创分0分
  • 专家分0分
地板#
发布于:2009-09-03 14:30
您太厉害了,拜一个
 
提问归提问,还是只能靠自己
liyunch
驱动小牛
驱动小牛
  • 注册日期2001-06-28
  • 最后登录2014-09-05
  • 粉丝0
  • 关注0
  • 积分13分
  • 威望134点
  • 贡献值0点
  • 好评度94点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2010-10-13 09:53
好贴啊.拿回去用用
qdslp
驱动牛犊
驱动牛犊
  • 注册日期2009-12-29
  • 最后登录2010-11-04
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望21点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2010-10-16 15:58
游客

返回顶部