Minfilter与legacy filter区别
比sfilter加载顺序更易控制. altitude被绑定到合适的位置。
Minfilter在注册表服务项中有一项Altitude值
此值越高位置越靠前 (待考证
每一个minifilter驱动必须有一个叫做altitude的唯一标识符.一个minifilter驱动的altitude定义了它加载时在I/O栈中相对其他minifilter驱动的位置。值越小,栈中位置就越低
FSFilter Anti-Virus 320000-329999 此组包括在文件I/O期间探测并杀毒的过滤驱动.
FSFilter Encryption 140000-149999此组包括在文件I/O期间加密和解密数据的过滤驱动.
图片2
可卸载能力.
Callback模型仅需处理必要操作的能力.
不再需要给一个IRP配置一个完成例程,Minfilter每个过滤功能有2个回调函数,一个是“事前”回调(PreCallBack),一个是“事后”回调(PosCallBack)
相当于PosCallBack就是sfilter中的IRP完成例程
要调用PosCallBack只需要PreCallBack 返回 FLT_PREOP_SUCCESS_WITH_CALLBACK
而返回FLT_PREOP_SUCCESS_NO_CALLBACK则告诉系统,处理好这件事后不用调用PosCallBack了
一个相当于sfilter中的Cpy,一个是skip
阻止下发返回FLT_PREOP_COMPLETE
兼容性更好
名字处理更容易
FltGetFileNameInformation
只需要传入回调函数CALL_DATA data 和一个PFLT_FILE_NAME_INFORMATION 指针就可以获得相关文件的信息 然后再调用
FltParseFileNameInformation就可以获得路径了
例子:(注意 获取路径需要在Pos中获取(即创建成功后才能获取到真实的数据))
//重命名的获得:
安装方式(.inf/动态加载)
通信方式(port)
同样遵循IRQL,锁等内核开发通用机制
FltCreateFile
Minfilter架构
fileMonitorRegistration是唯一我们需要做的
fileMonitorCallbacks 例子:
可以只需要一个回调如IRP_MJ_CLEANUP
//一个回调的例子:
上下位数组 例子:
Minifilter的启动
.inf文件安装minifilter
这个就是抄啊改的 没什么介绍的,只需要注意里面的ClassGUID和Class必须对上
这是查询网址
http://msdn.microsoft.com/en-us/library/windows/hardware/ff540394(v=vs.85).aspx
如果需要用自己的加载器加载Minfilter 只需要在注册表服务对应的RegPath下创建REG_SZ类型的Instances子健
在这里键下创建键值项,项值为Altitude
下面说一说回调
PRE-OP的返回值:
FLT_PREOP_SUCCESS_WITH_CALLBACK,//常用
FLT_PREOP_SUCCESS_NO_CALLBACK,//常用
FLT_PREOP_PENDING,//挂起IRP 不常用
FLT_PREOP_DISALLOW_FASTIO,//关闭FASTIO
FLT_PREOP_COMPLETE,//阻止
FLT_PREOP_SYNCHRONIZE//不常用
POST-OP的返回值:
FLT_POSTOP_FINISHED_PROCESSING,//常用
FLT_POSTOP_MORE_PROCESSING_REQUIRED
我们可以判断这个Data是什么请求
判断Data是什么操作的宏
参数数据的获取:
比如这次是查询目录 (怎么判断是什么操作?每个对应的回调就告诉你了这是什么操作,不可以在Create的回调中收到写操作把)
//读, 读有可能是使用MDL可能使用其它buff 判断的方法是看这个有没有值,没有值则是另一种
pNameInfo里面还有很多东西
WDK里面的例子:
//重命名的获得:
其实NtCreateSection对应着一个IRP
IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION
Data->Iopb->Parameters.AcquireForSectionSynchronization.PageProtection == PAGE_EXECUTE(等于这个就是创建进程)
在x64可以用这个监控进程 不过不需要
文件操作
在过滤驱动中,我们不能使用默认的文件操作,这会引起重入
Minfilter给我提供了专门的函数
FltCreateFile
FltReadFile
FltWriteFile
FltClose
FltQueryXxx
FltSetXxx
FltGetXxx
FltPerformXxx
其中的一个例子:
Minfilter上下文:
Context上下文:其实就是附着在某个对象上的一段数据,这段数据由自己定义;
FltAllocateContext
FltReleaseContext
Stream Context - 流上下文,也就是大家常用的FCB(File Control Block)的上下文,文件和FCB是一对一的关系;
FltGetStreamContext
FltSetStreamContext
Stream Handle Context - 流句柄上下文,也就是大家常见的FO(File Object)的上下文,一个文件可以对应多个FO,属一对多关系;
FltGetStreamHandleContext
FltSetStreamHandleContext
Instance Context - 实例上下文,也就是过滤驱动在文件系统的设备堆栈上创建的一个过滤器实例;
FltGetInstanceContext
FltSetInstanceContext
Volume Context - 卷上下文,卷就是大家通常看到的C,D,E盘以及网络重定向器,一般情况下一个卷对应一个过滤器实例对象,在实际应用上经常用Instance Context来代替Volume Context。
FltGetVolumeContext
FltSetVolumeContext
文件上下文(vista之后)
FltGetFileContext
FltSetFileContext
Context使用例子
//获取访问
先说说HIPS的实现,
r3,首先得到R0通信端口的句柄
使用FilterConnectCommunicationPort 只需要注意第一个参数和最后一个参数即可 其它都为0或NULL
然后绑定这个端口(我理解为绑定)
使用CreateIoCompletionPort 只需要注意第一个参数最后一个参数即可,最后一个参数:为这个工作线程设置几个线程
这样有助于高效率 一般小于64 ,也可以设置请求次数 这样回复也会高效率一些(具体看后面的代码)
我们首先使用FiltetGetMessage异步获取一下消息,如果有信息,则下面的GetQueuedCompletionStatus就会恢复(如果没有消息,GetQueuedCompletionStatus就会暂停下来,并让出CPU,等待有信息)
有了信息后我们就可以进行扫描 过滤,搞定之后就调用FilterReplyMessage返回给内核
然后继续调用FilterGetMessage-等待--处理--返回给内核
代码:
注意:这里的FILTER_REPLY_HEADER结构,里面有一项是固定的,有一项是可以自定义的,包括增加自己的结构
同样的Message对应的结构里面有一项也是可以自定义的 ,这要跟内核对应起来就可以了,内核里面只有自定义的那一项
比如:R0数据结构 这个就是自定义的
R3的结构
比sfilter加载顺序更易控制. altitude被绑定到合适的位置。
Minfilter在注册表服务项中有一项Altitude值
此值越高位置越靠前 (待考证
每一个minifilter驱动必须有一个叫做altitude的唯一标识符.一个minifilter驱动的altitude定义了它加载时在I/O栈中相对其他minifilter驱动的位置。值越小,栈中位置就越低
FSFilter Anti-Virus 320000-329999 此组包括在文件I/O期间探测并杀毒的过滤驱动.
FSFilter Encryption 140000-149999此组包括在文件I/O期间加密和解密数据的过滤驱动.
图片2
可卸载能力.
Callback模型仅需处理必要操作的能力.
不再需要给一个IRP配置一个完成例程,Minfilter每个过滤功能有2个回调函数,一个是“事前”回调(PreCallBack),一个是“事后”回调(PosCallBack)
相当于PosCallBack就是sfilter中的IRP完成例程
要调用PosCallBack只需要PreCallBack 返回 FLT_PREOP_SUCCESS_WITH_CALLBACK
而返回FLT_PREOP_SUCCESS_NO_CALLBACK则告诉系统,处理好这件事后不用调用PosCallBack了
一个相当于sfilter中的Cpy,一个是skip
阻止下发返回FLT_PREOP_COMPLETE
兼容性更好
名字处理更容易
FltGetFileNameInformation
只需要传入回调函数CALL_DATA data 和一个PFLT_FILE_NAME_INFORMATION 指针就可以获得相关文件的信息 然后再调用
FltParseFileNameInformation就可以获得路径了
例子:(注意 获取路径需要在Pos中获取(即创建成功后才能获取到真实的数据))
//在postcreate里获得
PFLT_FILE_NAME_INFORMATION pNameInfo = NULL;
ntStatus = FltGetFileNameInformation(Data,
FLT_FILE_NAME_NORMALIZED|
FLT_FILE_NAME_QUERY_DEFAULT,
&pNameInfo);
FltParseFileNameInformation(pNameInfo);
pNameInfo->Name.Buffer
pNameInfo->Volume
FltReleaseFileNameInformation(pNameInfo);
//重命名的获得:
PFILE_RENAME_INFORMATION
pFileRenameInfomation = (PFILE_RENAME_INFORMATION)Data->Iopb->Parameters.SetFileInformation.InfoBuffer;
FltGetDestinationFileNameInformation //重命名获得
安装方式(.inf/动态加载)
通信方式(port)
同样遵循IRQL,锁等内核开发通用机制
FltCreateFile
Minfilter架构
结构
FltRegisterFilter( DriverObject,
&fileMonitorRegistration,
&g_pFilter );
FltStartFiltering( g_pFilter );
fileMonitorRegistration是唯一我们需要做的
这是一个FLT_REGISTRATION 结构
const FLT_REGISTRATION fileMonitorRegistration =
{
sizeof( FLT_REGISTRATION ), // Size
FLT_REGISTRATION_VERSION, // Version
0, // Flags
ContextRegistration, // ContextRegistration //上下文数组
fileMonitorCallbacks, // Operation callbacks//最重要的
fileMonUnload, // FilterUnload
fileMonInstanceSetup, // InstanceSetup
NULL, // InstanceQueryTeardown
fileMonInstanceTeardownStart, // InstanceTeardownStart
NULL, // InstanceTeardownComplete
NULL, // GenerateFileName
NULL, // GenerateDestinationFileName
NULL // NormalizeNameComponent
};
fileMonitorCallbacks 例子:
可以只需要一个回调如IRP_MJ_CLEANUP
const FLT_OPERATION_REGISTRATION
fileMonitorCallbacks[] =
{
{
IRP_MJ_CREATE,
FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO,//这个是可以忽略的IRP
HOOK_PreNtCreateFile,
HOOK_PostNtCreateFile
},
{
IRP_MJ_CLEANUP,
0,
HOOK_PreNtCleanup,
NULL
},
{
IRP_MJ_WRITE,
0,
HOOK_PreNtWriteFile,
HOOK_PostNtWriteFile
},
{
IRP_MJ_SET_INFORMATION,
0,
HOOK_PreNtSetInformationFile,
HOOK_PostNtSetInformationFile
},
{
IRP_MJ_OPERATION_END//这个是必须要加的
}
};
//一个回调的例子:
FLT_PREOP_CALLBACK_STATUS
HOOK_PreNtCreateFile (
PFLT_CALLBACK_DATA Data,
PCFLT_RELATED_OBJECTS FltObjects,
PVOID *CompletionContext
//分配的一个context资源
)
{
//sandbox?
//主防??
//杀毒引擎??
//加解密??
return XXX;
}
FLT_POSTOP_CALLBACK_STATUS
HOOK_PostNtCreateFile (
PFLT_CALLBACK_DATA Data,
PCFLT_RELATED_OBJECTS FltObjects,
PVOID CompletionContext,
//在PRE-OP里返回 //FLT_PREOP_SUCCESS_WITH_CALLBACK
//时获取里面的上下文,并最后释放
FLT_POST_OPERATION_FLAGS Flags
)
{
return XXX;
}
上下位数组 例子:
PFLT_FILTER g_pFilter = NULL;
const FLT_CONTEXT_REGISTRATION
ContextRegistration[] =
{//在释放context之前调用,可以在此释放context里的内存等
{
FLT_INSTANCE_CONTEXT,
0,
CtxContextCleanup,
CTX_INSTANCE_CONTEXT_SIZE,
CTX_INSTANCE_CONTEXT_TAG
},
{
FLT_FILE_CONTEXT,
0,
CtxContextCleanup,
CTX_FILE_CONTEXT_SIZE,
CTX_FILE_CONTEXT_TAG
},
{
FLT_STREAM_CONTEXT,
0,
CtxContextCleanup,
CTX_STREAM_CONTEXT_SIZE,
CTX_STREAM_CONTEXT_TAG
},
{
FLT_STREAMHANDLE_CONTEXT,
0,
CtxContextCleanup,
CTX_STREAMHANDLE_CONTEXT_SIZE,
CTX_STREAMHANDLE_CONTEXT_TAG
},
{ FLT_CONTEXT_END }
};
Minifilter的启动
NTSTATUS initFileMonitor (PDRIVER_OBJECT DriverObject )
{
return FltRegisterFilter( DriverObject,
&fileMonitorRegistration,
&g_pFilter );
}
NTSTATUS startFileMonitor( )
{
if(g_pFilter)
return FltStartFiltering( g_pFilter );
return STATUS_INSUFFICIENT_RESOURCES;
}
VOID stopFileMonitor( )
{
if(g_pFilter)
{
FltUnregisterFilter( g_pFilter );
g_pFilter = NULL;
}
}
.inf文件安装minifilter
这个就是抄啊改的 没什么介绍的,只需要注意里面的ClassGUID和Class必须对上
这是查询网址
http://msdn.microsoft.com/en-us/library/windows/hardware/ff540394(v=vs.85).aspx
如果需要用自己的加载器加载Minfilter 只需要在注册表服务对应的RegPath下创建REG_SZ类型的Instances子健
在这里键下创建键值项,项值为Altitude
SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances子健下的键值项
例子:
//-------------------------------------------------------------------------------------------------------
// SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances子健下的键值项
//-------------------------------------------------------------------------------------------------------
strcpy(szTempStr,"SYSTEM\\CurrentControlSet\\Services\\");
strcat(szTempStr,lpszDriverName);
strcat(szTempStr,"\\Instances");
if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,szTempStr,0,"",REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,(LPDWORD)&dwData)!=ERROR_SUCCESS)
{
return FALSE;
}
// 注册表驱动程序的DefaultInstance 值
strcpy(szTempStr,lpszDriverName);
strcat(szTempStr," Instance");
if(RegSetValueEx(hKey,"DefaultInstance",0,REG_SZ,(CONST BYTE*)szTempStr,(DWORD)strlen(szTempStr))!=ERROR_SUCCESS)
{
return FALSE;
}
RegFlushKey(hKey);//刷新注册表
RegCloseKey(hKey);
//-------------------------------------------------------------------------------------------------------
// SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances\\DriverName Instance子健下的键值项
//-------------------------------------------------------------------------------------------------------
strcpy(szTempStr,"SYSTEM\\CurrentControlSet\\Services\\");
strcat(szTempStr,lpszDriverName);
strcat(szTempStr,"\\Instances\\");
strcat(szTempStr,lpszDriverName);
strcat(szTempStr," Instance");
if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,szTempStr,0,"",REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,(LPDWORD)&dwData)!=ERROR_SUCCESS)
{
return FALSE;
}
// 注册表驱动程序的Altitude 值
strcpy(szTempStr,lpszAltitude);
if(RegSetValueEx(hKey,"Altitude",0,REG_SZ,(CONST BYTE*)szTempStr,(DWORD)strlen(szTempStr))!=ERROR_SUCCESS)
{
return FALSE;
}
// 注册表驱动程序的Flags 值
dwData=0x0;
if(RegSetValueEx(hKey,"Flags",0,REG_DWORD,(CONST BYTE*)&dwData,sizeof(DWORD))!=ERROR_SUCCESS)
{
return FALSE;
}
RegFlushKey(hKey);//刷新注册表
RegCloseKey(hKey);
return TRUE;
下面说一说回调
FLT_PREOP_CALLBACK_STATUS
HOOK_PreNtCreateFile (
PFLT_CALLBACK_DATA Data,
PCFLT_RELATED_OBJECTS FltObjects,
PVOID *CompletionContext
//分配的一个context资源
)
{
//sandbox?
//主防??
//杀毒引擎??
//加解密??
return XXX;
}
FLT_POSTOP_CALLBACK_STATUS
HOOK_PostNtCreateFile (
PFLT_CALLBACK_DATA Data,
PCFLT_RELATED_OBJECTS FltObjects,
PVOID CompletionContext,
//在PRE-OP里返回 //FLT_PREOP_SUCCESS_WITH_CALLBACK
//时获取里面的上下文,并最后释放
FLT_POST_OPERATION_FLAGS Flags
)
{
return XXX;
}
PRE-OP的返回值:
FLT_PREOP_SUCCESS_WITH_CALLBACK,//常用
FLT_PREOP_SUCCESS_NO_CALLBACK,//常用
FLT_PREOP_PENDING,//挂起IRP 不常用
FLT_PREOP_DISALLOW_FASTIO,//关闭FASTIO
FLT_PREOP_COMPLETE,//阻止
FLT_PREOP_SYNCHRONIZE//不常用
POST-OP的返回值:
FLT_POSTOP_FINISHED_PROCESSING,//常用
FLT_POSTOP_MORE_PROCESSING_REQUIRED
我们可以判断这个Data是什么请求
判断Data是什么操作的宏
FLT_IS_IRP_OPERATION
FLT_IS_FASTIO_OPERATION
FLT_IS_FS_FILTER_OPERATION
if(FLT_IS_FASTIO_OPERATION(Data))
{
ntStatus = STATUS_FLT_DISALLOW_FAST_IO;
Data->IoStatus.Status = ntStatus;
Data->IoStatus.Information = 0;
return FLT_PREOP_DISALLOW_FASTIO;
}
参数数据的获取:
PFLT_CALLBACK_DATA Data;
PEPROCESS processObject =
Data->Thread ? IoThreadToProcess(Data->Thread) : PsGetCurrentProcess();//获取EPROCESS
HandleToUlong(PsGetProcessId(processObject));//获取PID
Data->IoStatus.Status = ntStatus;//返回给R3的
Data->IoStatus.Information = 0;//同上
FltObjects->Volume,//卷
FltObjects->Instance,//实例
FltObjects->FileObject,//文件对象
FltObjects->FileObject->DeviceObject//设备对象
Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess //创建的权限
比如这次是查询目录 (怎么判断是什么操作?每个对应的回调就告诉你了这是什么操作,不可以在Create的回调中收到写操作把)
PVOID pQueryBuffer =
Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;
ULONG uQueryBufferSize =
Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length
//读, 读有可能是使用MDL可能使用其它buff 判断的方法是看这个有没有值,没有值则是另一种
PMDL pReadMdl = Data->Iopb->Parameters.Read. MdlAddress;
PVOID pReadBuffer = Data->Iopb->Parameters.Read. ReadBuffer;
ULONG uReadLength = Data->Iopb->Parameters.Read.Length;
写同上面
//在postcreate里获得
PFLT_FILE_NAME_INFORMATION pNameInfo = NULL;
ntStatus = FltGetFileNameInformation(Data,
FLT_FILE_NAME_NORMALIZED|
FLT_FILE_NAME_QUERY_DEFAULT,
&pNameInfo);
FltParseFileNameInformation(pNameInfo);
pNameInfo->Name.Buffer
pNameInfo->Volume
FltReleaseFileNameInformation(pNameInfo);
pNameInfo里面还有很多东西
WDK里面的例子:
// look again at the first example string from above:
//
// \Device\HarddiskVolume1\Documents and Settings\MyUser\My Documents\Test Results.txt:stream1
//
// Extension = "txt"
// Stream = ":stream1"
// FinalComponent = "Test Results.txt:stream1"
// ParentDir = "\Documents and Settings\MyUser\My Documents\"
//重命名的获得:
PFILE_RENAME_INFORMATION
pFileRenameInfomation = (PFILE_RENAME_INFORMATION)Data->Iopb->Parameters.SetFileInformation.InfoBuffer;
FltGetDestinationFileNameInformation //重命名获得
其实NtCreateSection对应着一个IRP
IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION
Data->Iopb->Parameters.AcquireForSectionSynchronization.PageProtection == PAGE_EXECUTE(等于这个就是创建进程)
在x64可以用这个监控进程 不过不需要
文件操作
在过滤驱动中,我们不能使用默认的文件操作,这会引起重入
Minfilter给我提供了专门的函数
FltCreateFile
FltReadFile
FltWriteFile
FltClose
FltQueryXxx
FltSetXxx
FltGetXxx
FltPerformXxx
其中的一个例子:
ntStatus = FltCreateFile(pFilter,
pDstInstance,
&hDstFile,
GENERIC_WRITE | SYNCHRONIZE,
&objDstAttrib,
&ioStatus,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE,
FILE_CREATE,
CreateOptions,
NULL,0,0);
Minfilter上下文:
Context上下文:其实就是附着在某个对象上的一段数据,这段数据由自己定义;
FltAllocateContext
FltReleaseContext
Stream Context - 流上下文,也就是大家常用的FCB(File Control Block)的上下文,文件和FCB是一对一的关系;
FltGetStreamContext
FltSetStreamContext
Stream Handle Context - 流句柄上下文,也就是大家常见的FO(File Object)的上下文,一个文件可以对应多个FO,属一对多关系;
FltGetStreamHandleContext
FltSetStreamHandleContext
Instance Context - 实例上下文,也就是过滤驱动在文件系统的设备堆栈上创建的一个过滤器实例;
FltGetInstanceContext
FltSetInstanceContext
Volume Context - 卷上下文,卷就是大家通常看到的C,D,E盘以及网络重定向器,一般情况下一个卷对应一个过滤器实例对象,在实际应用上经常用Instance Context来代替Volume Context。
FltGetVolumeContext
FltSetVolumeContext
文件上下文(vista之后)
FltGetFileContext
FltSetFileContext
PFLT_FILTER g_pFilter = NULL;
const FLT_CONTEXT_REGISTRATION
ContextRegistration[] =
{//在释放context之前调用,可以在此释放context里的内存等
{
FLT_INSTANCE_CONTEXT,
0,
CtxContextCleanup,
CTX_INSTANCE_CONTEXT_SIZE,
CTX_INSTANCE_CONTEXT_TAG
},
{
FLT_FILE_CONTEXT,
0,
CtxContextCleanup,
CTX_FILE_CONTEXT_SIZE,
CTX_FILE_CONTEXT_TAG
},
{
FLT_STREAM_CONTEXT,
0,
CtxContextCleanup,
CTX_STREAM_CONTEXT_SIZE,
CTX_STREAM_CONTEXT_TAG
},
{
FLT_STREAMHANDLE_CONTEXT,
0,
CtxContextCleanup,
CTX_STREAMHANDLE_CONTEXT_SIZE,
CTX_STREAMHANDLE_CONTEXT_TAG
},
{ FLT_CONTEXT_END }
};
Context使用例子
typedef struct _INSTANCE_CONTEXT {
…
} INSTANCE_CONTEXT, *PINSTANCE_CONTEXT;
PINSTANCE_CONTEXT pContext = NULL;
//分配与设置
ntStatus = FltGetInstanceContext(FltObjects->Instance, & pContext);//尝试获取
if(NT_SUCCESS(Status) == FALSE)
{
ntStatus = FltAllocateContext(g_pFilter,FLT_INSTANCE_CONTEXT,
sizeof(INSTANCE_CONTEXT),
PagedPool,& pContext);
if(NT_SUCCESS(Status) == FALSE)
{
return STATUS_SUCCESS;
}
RtlZeroMemory(pContext, sizeof(INSTANCE_CONTEXT));
}
pContext ->m_DeviceType = VolumeDeviceType;
pContext->m_FSType = VolumeFilesystemType;
FltSetInstanceContext(FltObjects->Instance, FLT_SET_CONTEXT_REPLACE_IF_EXISTS,pContext,NULL);
if (pContext)
{
FltReleaseContext(pContext);
}
//获取访问
PINSTANCE_CONTEXT pContext = NULL;
Status = FltGetInstanceContext(FltObjects->Instance,&pContext);
pContext->xxx = xxx;
Minifilter R3与R0通信
不用像NT框架里面的通信方式了,Minifilter为我们提供了专门的函数进行通信
在通信时,我们使用Port进行通信
在R0,我们创建一个Port,R3在通信前会得到Port的句柄,我们就可以通过这个port进行通信了
R0创建端口代码:
RtlInitUnicodeString( &uniString, ScannerPortName );
//
// We secure the port so only ADMINs & SYSTEM can acecss it.
//
//设置通信端口权限 ,只有管理员和系统进程才能操作
status = FltBuildDefaultSecurityDescriptor( &sd, FLT_PORT_ALL_ACCESS );
if (NT_SUCCESS( status )) {
InitializeObjectAttributes( &oa,
&uniString,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
sd );
//创建通信端口,并设置对应的回调函数
status = FltCreateCommunicationPort( ScannerData.Filter,
&ScannerData.ServerPort,
&oa,//设置的名字
NULL,
ScannerPortConnect,//当R3连接时回调 主要是记录R3的进程ID或EPROCESS以便放过本进程 还有记录R3的通信端口,给后面主动通信的时候用
ScannerPortDisconnect,//当R3离线时回调 主要是关闭R3端口和设置R3的进程信息为NULL
NULL,//处理R3主动函数 比如R3下新的规则,
1 );//最后一个常为1
//
// Free the security descriptor in all cases. It is not needed once
// the call to FltCreateCommunicationPort() is made.
//
//设置好后需要释放权限的设置
FltFreeSecurityDescriptor( sd );
//下面就是判断是否创建成功,成功后就开始开启过滤
先说说HIPS的实现,
r3,首先得到R0通信端口的句柄
使用FilterConnectCommunicationPort 只需要注意第一个参数和最后一个参数即可 其它都为0或NULL
然后绑定这个端口(我理解为绑定)
使用CreateIoCompletionPort 只需要注意第一个参数最后一个参数即可,最后一个参数:为这个工作线程设置几个线程
这样有助于高效率 一般小于64 ,也可以设置请求次数 这样回复也会高效率一些(具体看后面的代码)
我们首先使用FiltetGetMessage异步获取一下消息,如果有信息,则下面的GetQueuedCompletionStatus就会恢复(如果没有消息,GetQueuedCompletionStatus就会暂停下来,并让出CPU,等待有信息)
有了信息后我们就可以进行扫描 过滤,搞定之后就调用FilterReplyMessage返回给内核
然后继续调用FilterGetMessage-等待--处理--返回给内核
代码:
FilterConnectCommunicationPort( ScannerPortName,//与R0的名字一致
0,
NULL,
0,
NULL,
&port );//R0端口
//处理从R0来的请求,即R0调用FltSendMessage的请求
completion = CreateIoCompletionPort( port,NULL,0,1);
FilterGetMessage( Port,
&message->MessageHeader,
FIELD_OFFSET( SANDBOX_MESSAGE, Ovlp ),
&message->Ovlp );
while(1)
{
GetQueuedCompletionStatus( lpContext->Completion, &outSize, &key, &pOvlp, INFINITE );
//过滤,扫描
FilterReplyMessage(Port,
(PFILTER_REPLY_HEADER) &replyMessage,
sizeof( replyMessage ) );
FilterGetMessage( Port,
&message->MessageHeader,
FIELD_OFFSET( SANDBOX_MESSAGE, Ovlp ),
&message->Ovlp );
}
注意:这里的FILTER_REPLY_HEADER结构,里面有一项是固定的,有一项是可以自定义的,包括增加自己的结构
同样的Message对应的结构里面有一项也是可以自定义的 ,这要跟内核对应起来就可以了,内核里面只有自定义的那一项
比如:R0数据结构 这个就是自定义的
typedef struct _SCANNER_NOTIFICATION
{
ULONG BytesToScan;
ULONG Reserved;
UCHAR Contents[SCANNER_READ_BUFFER_SIZE];
} SCANNER_NOTIFICATION, *PSCANNER_NOTIFICATION;
typedef struct _SCANNER_REPLY
{
BOOLEAN SafeToOpen;
} SCANNER_REPLY, *PSCANNER_REPLY;
R3的结构
typedef struct _SCANNER_MESSAGE
{
FIL