WFP过滤平台
WFP(windows Filter Platform)windows过滤平台
WFP的推出是为了代替之前XP和03中基于包过滤的技术,比如Transport Driver Interface(TDI)过滤,Network Driver Interface Specification(NDIS)过滤,Winsock Layered Service Providers(LSP).
WFP是一组API和系统服务,他给网络过滤的应用提供了一种平台.WFP的这些API可以在操作系统网络堆栈的不同层次进行包的处理,在数据到达目的地之前,进行过滤或修改.
WFP主要分为两大层次模块:用户态基础过滤引擎(BFE).内核态过滤引擎(KM Filtering Engine).实际工作的是内核态的过滤引擎,用户可以在用户层通过其提供的API与BFE交互(BFE会与KMFE交互),或直接在内核层KMFE交互.
WFP开发相关的主要概念:
1.过滤引擎
WFP的过滤引擎包括BFE(用户态)和KMFE(内核态),与其系统的网络栈进行交互,我们可以向过滤引擎注册过滤规则或对数据的操作,过滤引擎最终完成相应的操作.
2.垫片shims
这个概念主要是有关WFP的运行原理,和WFP开发没有太大关联.
垫片是一种特殊的内核模块,被安插在系统的网络协议栈的不同层中,将不同层的数据传给WFP过滤引擎,并将过滤引擎的反馈操作传回到网络协议栈中.
3.Callout
Callout是WFP中非常重要的数据结构,其中包括对数据的具体操作函数,以及一个唯一的标识符GUID,我们主要是通过向过滤引擎注册自己定义的Callout来实现对数据的操作
4.分层
系统的网络协议栈是分为多层的,WFP的过滤引擎也是分开为多层(Layer),我们在注册自己的Callout时需要指定网络的具体那一层,对该层的数据进行操作.
5.自层
在前面WFP的分层基础上,WFP提供了子层的概念,分层是进队网络协议栈的分层,是固定的,在这个分层的基础上,WFP在每一层上进一步提供了子层.在每一个网络协议栈的层次上,开发者可以定义多个子层,并赋予其权重值,网络数据会按照子层的权重值顺序执行子层的操作.
6.过滤器
WFP提供了过滤器(filter)的概念,其实现对数据的过滤.例如我们注册了一个对网络数据操作的Callout,但是我们只想对目标IP地址为A的数据包进行操作,这时就可以通过定义和注册相应的Filter,过滤出目标地址为A的数据包,Callout则只会对经过过滤后的数据包进行处理.
WFP开发步骤1
1.开启WFP过滤引擎,创建句柄
调用WfpmEngineOpen()开启过滤引擎.
2.开启过滤设置
调用FwpmTracsactionBegin()
3.注册Callout
a).定义FWPS_CALLOUT结构的变量
该结构主要包含以下3个函数:
1.1).classifyFn
当一个过滤器关联了Callout,且规则被命中时(过滤器内的条件全部成立),过滤引擎会调用相应的Callout中的classifyFn函数.开发者可以在classifyFn函数内获取网络数据包的相关信息,具体信息取决于过滤器所在分层,classifyFn也可以设置对网络数据包的”permit/block”操作.
1.2).notifyFn
当过滤器被添加到过滤引擎中或者从过滤引擎中被移除时,WFP会调用这个过滤器对应的Callout的notifyFn函数.notifyFn函数中可以获取到与网络数据相关的一些信息,例如进程信息等,也可以在notifyFn中进行一些初始化的操作.
1.3).flowDeleteFn
当一个网络数据要被终止时,WFP会调用flowDeleteFn函数.
b).定义一个GUID,唯一标识这个Callout
c).调用FWPSCalloutRegister()函数注册该FWPS_CALLOUT变量.
4.注册相应的Callout到WFP的过滤引擎
前面一步是向WFP的过滤引擎注册了Callout,这里需要将其添加到WFP的过滤引擎,通过前面的GUID唯一定位这个Callout.
5.添加子层
调用FwpmSubLayerAdd向WFP添加子层,子层的权重值决定了数据在进过各个子层的顺序.
6.添加Filter
定义FWPM_FILTER变量,调用FwpmFilterAdd功函数添加该Filter/
7.提交所有操作,使上面的操作生效
调用FwpmTransactionCommit()函数提交上面的操作,使对数据的操作生效.
8.销毁过滤引擎句柄
在不使用该句柄时,调用FwpmEngineClose()函数将其销毁.
WFP开发步骤2
1.注册呼出接口
2.添加呼出接口
3.添加子层
4.添加过滤引擎
WFP开发步骤3
1.定义一个或多个呼出接口
2.向过滤引擎注册呼出接口
3.添加步骤1的呼出接口到过滤引擎.tips:注册呼出接口和添加呼出接口是两个不同的操作
4.设计一个或多个子层,把子层添加到分层中
5.设计过滤器,把呼出接口,子层,分层和过滤器关联起来,向过滤引擎添加过滤器
具体步骤:
1.注册呼出接口可以使用FwpsCalloutRegister()
函数原型 NTSTATUS NTAPI FwpsCalloutRegister1(
IN_OUT void*deviceObject,
IN const FWPS_CALLOUT1 callout,
OUT OPTIONAL UINT32calloutId);
呼出接口被成功注册后,FwpsCalloutRegister1函数返回STATUS_SUCCESS;
如果FWPS_CALLOUT1结构体内calloutKey所标识的呼出接口被注册过了,那么FwpsCalloutRegister1函数返回STATUS_FWP_ALREADY_EXISTS;
如果发生错误,那么FwpsCalloutRegister1函数返回其他错误码;
成功注册呼出接口后还需要卸载呼出接口,卸载呼出接口使用FwpsCalloutUnregisterById或FwpsCalloutUnregisterByKey函数,其中FwpsCalloutUnregisterById函数是通过指定呼出接口”运行时标识”来对呼出接口进行卸载.FwpsCalloutUnregisterByKey函数是通过呼出接口的GUID值来对呼出接口进行卸载.
2.成功注册呼出接口后,还需要把呼出接口添加到过滤引擎中,在将呼出接口添加到过滤引擎之前,需要先打开过滤引擎.打开过滤引擎使用FwpmEngineOpen0()函数,函数原型如下:
NTSTATUS NTAPI
FwpmEngineOpen0(
IN const wchar_t serverNAme OPTIONAL,
IN UINT32 authnService,
IN SEC_WINNT_AUTH_IDENTITY_W authIdentity OPTIONAL,
OUT HANDLEengineHandle); 有了这个句柄,就可以通过这个句柄把呼出接口添加到过滤引擎中.把呼出接口添加到过滤引擎中可以使用FwpmCalloutAdd0()函数,函数原型如下: DWORD WINAPI FwpmCalloutAdd0( __in HANDLE engineHandle, __in const FWPM_CALLOUT0 callout,
__in_opt PSECURITY_DESCRIPTOR sd,
__out_opt UINT32* id);
tips:函数成功添加呼出接口到过滤引擎中后返回STATUS_SUCCESS;如果WFP发现相同的呼出接口已经被添加到过滤引擎中,函数返回STATUS_FWP_ALREADY_EXISTS;如果发生错误,函数返回其他错误码;
函数成员 __out_opt UINT32* id:成功添加呼出接口后,系统返回一个id,可以用这个id移除已添加的呼出接口,可以使用FwpmCalloutDeleteById0和FwpmCalloutDeleteByKey0;
3.子层的添加与移除
WDK提供了FwpmSubLayerAdd0函数添加子层,函数原型如下:
DWORD WINAPI FwpmSubLayerAdd0(
__in HANDLE engineHandle,
__in const FWPM_SUBLAYER0* subLayer,
__in_opt PSECURITY_DESCRIPTOR sd);
FwpmSubLayerAdd0函数成功添加子层后返回ERROR_SUCCESS;否则返回错误码;
可以使用FwpmSubLayerDeleteByKey0函数来移除一个子层,函数原型如下:
DWORD FwpmSubLayerDeleteByKey0(
__in HANDLE engineHandle,
__in const GUID* key);
4.过滤器的添加
使用FwpmFilterAdd0函数将过滤器添加到过滤引擎中,函数原型如下:
DWORD WINAPI FwpmFilterAdd0(
__in HANDLE engineHandle,
__in const FWPM_FILTER0 filter, __in_opt PSECURITY_DESCRIPTOR sd, __out_opt UINT64 id);
函数成员:UINT64*id:当过滤器被成功添加到过滤引擎中,过滤引擎会为这个过滤器分配一个唯一id来标识;
该函数成功添加过滤器后返回ERROR_SUCCESS;否则返回特定错误码;
移除过滤器可以使用FwpmFilterDeleteById0或FwpmFilterDeleteByKey0函数,其中FwpmFilterDeleteById0函数通过指定过滤器的id进行移除,而FwpmFilterDeleteByKey0函数通过指定过滤器的GUID进行移除;
笔记:
垫片:垫片是在windows网络协议层中不同层次的对象,目的是为了向WFP过滤平台提供不同的数据