Minifilter特点
在Minifilter框架中,不在需要自己去写代码生成设备,去绑定卷.这些框架已经做好了.唯一需要我们做的就是在Callback中处理我们感兴趣的回调函数而已.
创建文件
使用FltCreateFile 不能再使用ZwCreateFile
通信方式
在minifilter中改为通过端口通信.
驱动加载
使用inf文件安装 然后使用命令net start +驱动名
或者使用代码的方式加载,与NT驱动不同的是,需要新增两个注册表键值.
Minifilter的注册
CONST FLT_REGISTRATION FilterRegistration = {
sizeof( FLT_REGISTRATION ), // Size
FLT_REGISTRATION_VERSION, // Version
0, // Flags
NULL, // 上下文相关回调(数组)
Callbacks, // 所有IRP的操作都在这个数组里,需要关心的就是这里面的Irp处理回调
MiniUnload, // MiniFilterUnload
MiniInstanceSetup, // 每一个卷设备都会生成一个Instance 把Instance绑定到卷设备上
//可以从该回调函数获得卷设备的名称,扇区大小 文件系统类别
MiniInstanceQueryTeardown, // InstanceQueryTeardown
MiniInstanceTeardownStart, // Instance和卷设备分离的时候会调用该回调
MiniInstanceTeardownComplete, // InstanceTeardownComplete
NULL, // 以下三个回调是关于名字处理的
NULL, // GenerateDestinationFileName
NULL // NormalizeNameComponent
};
回调函数中的数据
IRP数据结构在Minifilter中已经看不到了.框架使用的是CALLBACK_DATA的这样一种数据结构.
typedef struct _FLT_CALLBACK_DATA {
FLT_CALLBACK_DATA_FLAGS Flags;
PETHREAD CONST Thread;
PFLT_IO_PARAMETER_BLOCK CONST Iopb;
IO_STATUS_BLOCK IoStatus;
struct _FLT_TAG_DATA_BUFFER *TagData;
union {
struct {
LIST_ENTRY QueueLinks;
PVOID QueueContext[2];
};
PVOID FilterContext[4];
};
KPROCESSOR_MODE RequestorMode;
} FLT_CALLBACK_DATA, *PFLT_CALLBACK_DATA;
IRP相关信息在结构FLT_IO_PARAMETER_BLOCK里面
typedef struct _FLT_IO_PARAMETER_BLOCK {
//
// Fields from IRP
// Flags
ULONG IrpFlags;
//
// Major/minor functions from IRP
//
UCHAR MajorFunction;
UCHAR MinorFunction;
//
// The flags associated with operations.
// The IO_STACK_LOCATION.Flags field in the old model (SL_* flags)
//
UCHAR OperationFlags;
//
// For alignment
//
UCHAR Reserved;
//
// The FileObject that is the target for this
// IO operation.
//
PFILE_OBJECT TargetFileObject;
//
// Instance that i/o is directed to
//
PFLT_INSTANCE TargetInstance;
//
// Normalized parameters for the operation
//
FLT_PARAMETERS Parameters; //写入位置 写入长度 缓冲区等相关参数
} FLT_IO_PARAMETER_BLOCK, *PFLT_IO_PARAMETER_BLOCK;
Altitude值:20000-429999
IRP_PAGING_IO
IRP_PAGING_IO是由系统发起的,自己不需要监控.设置FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO标志.
例如:
{ IRP_MJ_CREATE,
FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO,
MiniPreOperation,
MiniPostOperation }
预操作的返回值
typedef enum _FLT_PREOP_CALLBACK_STATUS {
FLT_PREOP_SUCCESS_WITH_CALLBACK, //调用POST操作(相当于完成函数)
FLT_PREOP_SUCCESS_NO_CALLBACK, //不会调用POST操作
FLT_PREOP_PENDING,
FLT_PREOP_DISALLOW_FASTIO, //禁用FAST_IO
FLT_PREOP_COMPLETE, //完成DATA,不会再往下传递.
FLT_PREOP_SYNCHRONIZE //POST操作的IRQL等级小于DPC
} FLT_PREOP_CALLBACK_STATUS, *PFLT_PREOP_CALLBACK_STATUS;
POST操作的IRQL
一般情况下是DPC,相等于是完成函数
如果拦截的是IRP_MJ_CREATE IRQL=PASSIVE_LEVEL
如果是基于FASTIO的, IRQL=PASSIVE_LEVEL
如果预处理操作的返回值是FLT_PREOP_SYNCHRONIZE POST操作的IRQL<DPC
POST操作的返回值
typedef enum _FLT_POSTOP_CALLBACK_STATUS {
FLT_POSTOP_FINISHED_PROCESSING,
FLT_POSTOP_MORE_PROCESSING_REQUIRED
} FLT_POSTOP_CALLBACK_STATUS, *PFLT_POSTOP_CALLBACK_STATUS;
判断Data是什么操作的宏
#define FLT_IS_IRP_OPERATION(Data) (FlagOn( (Data)->Flags, FLTFL_CALLBACK_DATA_IRP_OPERATION ))
#define FLT_IS_FASTIO_OPERATION(Data) (FlagOn( (Data)->Flags, FLTFL_CALLBACK_DATA_FAST_IO_OPERATION ))
#define FLT_IS_FS_FILTER_OPERATION(Data) (FlagOn( (Data)->Flags, FLTFL_CALLBACK_DATA_FS_FILTER_OPERATION ))
DATA中参数的获取
IRP 中的buffer和length 都变得在data中获取
获取创建文件全路径
FLT_PREOP_CALLBACK_STATUS
MyPreCreate(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_Flt_CompletionContext_Outptr_ PVOID *CompletionContext
)
{
//需要调用POST
return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}
FLT_POSTOP_CALLBACK_STATUS
MyPostCreate(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_opt_ PVOID CompletionContext,
_In_ FLT_POST_OPERATION_FLAGS Flags
)
{
NTSTATUS status = STATUS_SUCCESS;
PFLT_FILE_NAME_INFORMATION pNameInfo = NULL;
status = FltGetFileNameInformation(Data,
FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT,
&pNameInfo);
if(!NT_SUCCESS(status))
{
KdPrint(("获取文件信息失败,status=%x\n",status)); //文件信息有获取失败的时候
return status;
}
status=FltParseFileNameInformation(pNameInfo);
if (!NT_SUCCESS(status))
{
KdPrint(("解析文件信息失败\n"));
FltReleaseFileNameInformation(pNameInfo);
return status;
}
KdPrint(("卷名:%wZ\n", &pNameInfo->Volume));
KdPrint(("文件名:%wZ\n", &pNameInfo->Name));
FltReleaseFileNameInformation(pNameInfo);
return FLT_POSTOP_FINISHED_PROCESSING;
}
拦截进程创建
Minifilter中的文件操作
Minifilter上下文
创建 删除 重命名的判断
FLT_PREOP_CALLBACK_STATUS
NPPreCreate (
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__deref_out_opt PVOID *CompletionContext
)
{
NTSTATUS status;
PFLT_FILE_NAME_INFORMATION nameInfo;
UNREFERENCED_PARAMETER( FltObjects );
UNREFERENCED_PARAMETER( CompletionContext );
PAGED_CODE();
if (gCommand == ENUM_PASS)
{
return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}
else if (gCommand == ENUM_BLOCK && gPath[0] != 0)
{
__try
{
status = FltGetFileNameInformation( Data,
FLT_FILE_NAME_NORMALIZED |
FLT_FILE_NAME_QUERY_DEFAULT,
&nameInfo );
if (NT_SUCCESS( status ))
{
char fileName[500] = "";
FltParseFileNameInformation(nameInfo);
if (NPUnicodeStringToChar(&nameInfo->Name, fileName))
{
if (strstr(fileName, gPath))
{
//IRP_MJ_CREATE
if (Data->Iopb->MajorFunction == IRP_MJ_CREATE)
{
//create file
if ( ((Data->Iopb->Parameters.Create.Options>>24) & 0x000000ff) == FILE_CREATE ||
((Data->Iopb->Parameters.Create.Options>>24) & 0x000000ff) == FILE_OPEN_IF||
((Data->Iopb->Parameters.Create.Options>>24) & 0x000000ff) == FILE_OVERWRITE_IF)
{
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->IoStatus.Information = 0;
FltReleaseFileNameInformation( nameInfo );
return FLT_PREOP_COMPLETE;
}
//move into folder
if (Data->Iopb->OperationFlags == '\x05')
{
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->IoStatus.Information = 0;
FltReleaseFileNameInformation( nameInfo );
return FLT_PREOP_COMPLETE;
}
}
//IRP_MJ_WRITE
if (Data->Iopb->MajorFunction == IRP_MJ_WRITE)
{
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->IoStatus.Information = 0;
FltReleaseFileNameInformation( nameInfo );
return FLT_PREOP_COMPLETE;
}
//IRP_MJ_SET_INFORMATION
if (Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION)
{
//delete file
if (Data->Iopb->Parameters.SetFileInformation.FileInformationClass == FileDispositionInformation)
{
DbgPrint("delete file\n");
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->IoStatus.Information = 0;
FltReleaseFileNameInformation( nameInfo );
return FLT_PREOP_COMPLETE;
}
//rename file
if (Data->Iopb->Parameters.SetFileInformation.FileInformationClass == FileRenameInformation)
{
DbgPrint("rename file\n");
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->IoStatus.Information = 0;
FltReleaseFileNameInformation( nameInfo );
return FLT_PREOP_COMPLETE;
}
}
}
}
FltReleaseFileNameInformation( nameInfo );
}
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}
}
return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}
文件的重定向
FLT_PREOP_CALLBACK_STATUS
MyMinifiterPreOperation (
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_Flt_CompletionContext_Outptr_ PVOID *CompletionContext
)
{
NTSTATUS status;
PFLT_FILE_NAME_INFORMATION nameInfo;
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(CompletionContext);
UNICODE_STRING desFilename;
RtlCreateUnicodeString(&desFilename, L"\\DEVICE\\HARDDISKVOLUME3\\USERS\\User\\DESKTOP\\2.TXT");//为了方便测试路径我写死了,实际操作也很简单仅仅只是字符串的拼接
PFILE_OBJECT FileObject;
PAGED_CODE();
__try {
status = FltGetFileNameInformation(Data,
FLT_FILE_NAME_NORMALIZED |
FLT_FILE_NAME_QUERY_DEFAULT,
&nameInfo);
if (NT_SUCCESS(status)) {
FltParseFileNameInformation(nameInfo);
if (wcsstr(nameInfo->Name.Buffer, L"1.txt")) {
FileObject = Data->Iopb->TargetFileObject;
FileObject->FileName = desFilename;//替换成目标文件的路径。
Data->IoStatus.Information = IO_REPARSE;
Data->IoStatus.Status = STATUS_REPARSE;
Data->Iopb->TargetFileObject->RelatedFileObject = NULL;
FltSetCallbackDataDirty(Data);
FltReleaseFileNameInformation(nameInfo);
return FLT_PREOP_COMPLETE;
}
//release resource
FltReleaseFileNameInformation(nameInfo);
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("EXCEPTION_EXECUTE_HANDLER\n");
}
return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}