当前位置: 代码网 > 科技>操作系统>Windows > 【驱动开发】Windows过滤平台(WFP,Windows Filtering Platform)

【驱动开发】Windows过滤平台(WFP,Windows Filtering Platform)

2024年08月01日 Windows 我要评论
TDI:Transport Driver Interface,传输层接口。TDI在Windows Vista之后就不再支持了,之后的版本中被WFP取代。socket可以指定某种方式开始传输用户的数据(比如TCP或UDP),这就是传输层。传输层的特点是:用户只需要关心实际需要传输的用户数据,而不用担心数据实际的发送次数、如何封装、如何确定发送正确性、出错何重发等。Windows过滤平台(Windows Filter Platform),是从Vista系统后新增的一套系统API和服务,为网络数据包过滤。

windows的发展历程

正题开始之前,先总结一下windows的发展历程。

  • windows1.0、2.0、3.0、3.1、3.2:16位。
  • windows9x:包括windows 95windows 98windows me
  • windowsnt系列:包括windows nt 3.1windows nt 3.1windows nt 4.0windows 2000windows xpwindows server 2003windows vistawindows server 2008windows 7windows server 2012windows 8windows 10,这些版本都源于windows nt 内核。

比较常见的几个版本的顺序:
windows 2000
windows xp
windows vista
windows 7
windows 8
windows10

tdi简介

tdi:transport driver interface,传输层接口。tdi在windows vista之后就不再支持了,之后的版本中被wfp取代。
socket可以指定某种方式开始传输用户的数据(比如tcp或udp),这就是传输层。
传输层的特点是:用户只需要关心实际需要传输的用户数据,而不用担心数据实际的发送次数、如何封装、如何确定发送正确性、出错何重发等。

wfp简介

windows过滤平台(windows filter platform),是从vista系统后新增的一套系统api和服务,为网络数据包过滤提供架构支撑。
wfp框架是分层结构,可以在不同分层中进行过滤重定向修改网络数据包。
通过wfp框架,开发者可以在其上轻松实现防火墙、入侵检测系统、网络监视程序以及流量控制程序等。
wfp框架包含用户态api和内核态api。它只是一个提供各层网络数据包过滤的框架,自身并不是防火墙,也不存在任何过滤逻辑。

wfp框架主要分为两大层次模块:
在这里插入图片描述

用户态基础过滤引擎(bfe)

基础过滤引擎:bfe,base filtering enging。
bfe 对上提供c管理api以及rpc接口,封装在fwpuclnt.dll中,供用户态程序调用;对下和kmfe交互,受其控制。

内核态过滤引擎(kmfe)

内核态过滤引擎:kmfe,kernel mode filtering enging,是整个wfp框架的核心。
其内部被划分为多个分层,不同分层代表着网络协议栈特定的层,在每个分层中可以存在子层和过滤器。kmfe负责检查网络数据包是否命中过滤器的规则(rule),对于命中的过滤器,会执行这些过滤器指定的动作(action)。

问题一:网络数据包从哪来?
答:kmfe需要和系统网络协议栈(如tcp/ip协议栈)交互,通过一种称为垫片(shim)的内核模块从网络协议栈中获取网络数据。
垫片被插入到网络协议栈各个层中,包括:

  • 数据流分层垫片:对应 流/报文 数据分层(ipv4/ipv6)
  • ale网络连接管理:对应 发送/接收 ale分层(ipv4/ipv6)
  • 传输分层垫片(tcp/udp):对应 发送/接收 传输分层(ipv4/ipv6)
  • 网络分层垫片(ipv4/ipv6):对应 发送/接收 ip分层(ipv4/ipv6)

不同层次的垫片获取到的网络数据不同,垫片获取到数据后,通过kmfe提供的classify api,把数据传送到wfp的相应分层(layer)中。

垫片(shim)

垫片是一种特殊的内核模块,被安插在系统网络协议栈(如tcp/ip协议栈)的不同层(栈)中,主要作用有:

  1. 获取网络协议栈的数据。
    被安插在传输层,可以获取tcp/udp等协议数据;
    被安插在网络层,可以获取ip协议等数据。
    shim获取到数据后,会通过kmfe提供的分类api,把数据传递到相应的wfp分层中。
  2. 把kmfe的过滤结果反馈给网络协议栈。
    比如kmfe需要拦截某一类网络数据,通过分类api把过滤结果通知垫片,由于垫片被安插在网络协议栈中,所以垫片可以在网络协议栈中直接拦截网络数据包。

总结:垫片负责wfp的数据来源以及执行数据拦截/放行的最终动作,属于网络协议栈和wfp框架之间的通信桥梁。但垫片对开发者来说是透明的,无须过多关注。

分层(layer)

kmfe内部被划分成不同的分层,每一个分层代表了系统网络协议栈的一个特定的层,接收待定的数据。
分层是一个容器,里面包含了零个或多个过滤器,此外还可能包含一个或多个子层

分层标识:
每个分层都有一个唯一的值来标识,在内核态,使用64位的luid来标识一个子层;在用户态,使用128位guid来标识一个分层。
这两种分层标识存在部分对应关系,一般来说,
把内核态用到的分层标识称为运行时过滤分层标识
把用户态使用到的分层标识称为管理过滤分层标识
常见的运行时过滤分层标识:.
fwpm_layer_ale_auth_connect_v4:连接ipv4
fwpm_layer_ale_auth_recv_accept_v4:接收ipv4
fwpm_layer_ale_auth_listen_v4:监听ipv4
常见的管理过滤分层标识:
fwpm_layer_inbound_ippacket_v4:接收ipv4网络数据包层
fwpm_layer_inbound_ippacket_v6:接收ipv6网络数据包层
fwpm_layer_outbound_ippacket_v4:发送ipv4网络数据包层
fwpm_layer_outbound_ippacket_v6:发送ipv6网络数据包层

子层(sub layer)

子层是分层内更小的一个划分,一个分层可能被划分成多个子层,并且这种划分是由开发者控制的。
划分子层时需要给新子层分配一个权重(weight),权重的值越,表明优先级越
当有相应的网络数据到达分层时,wfp会按照分层内的子层优先级顺序传递网络数据,子层的权重值越大,越早获取到数据。

typedef struct fwpm_sublayer0_ {
  guid               sublayerkey;	// 子层标识
  fwpm_display_data0 displaydata;	// 显示数据
  uint32             flags;			// 特性,如fwpm_sublayer_flag_persistent
  guid               *providerkey;
  fwp_byte_blob      providerdata;
  uint16             weight;		// 权重,值越大,优先级越高
} fwpm_sublayer0;
typedef struct fwpm_display_data0_ {
	wchar* name;		// 对象名字
	wchar* description;	// 对象描述
}fwpm_display_data0;

过滤器(filter)

过滤器存在于wfp的分层中,wfp内置了一部分过滤器供开发者使用,开发者也可以添加自己的过滤器。
过滤器里保存了网络数据包的拦截规则(rule)和处理动作(action),rule指明了需要过滤哪些网络数据包,当rule被命中时,就会执行指定的action。

一般来说,过滤器中的动作会表明是放行(permit)还是拦截(block)网络数据包。在实际情况中,kmfe的分层中可能会存在多个子层以及多个过滤器,对于一次网络事件而言,可能同时命中多个过滤器的规则,而这些命中规则的过滤器可能指定了不同的过滤动作,为了计算出最终的过滤动作,wfp引入了过滤仲裁器(fileter arbitration)模块,过滤仲裁器计算出最终的过滤动作后交给kmfe,kmfe最终将过滤结果反馈给垫片。

过滤器可以关联分层和子层,以及呼出接口。
在需要对网络数据包进行复杂的分析和处理的情况下,过滤器一般需要关联一个呼出接口,当过滤器的规则被命中时,wfp会直接执行与改过滤器关联的呼出接口内的回调函数。

typedef struct fwpm_filter0_ {
  guid                   filterkey;		// 过滤器标识,若fwpmfilteradd0中初始化为0,则bfe将生成一个
  fwpm_display_data0     displaydata;	// 显示数据
  uint32                 flags;			// 特性
  guid                   *providerkey;
  fwp_byte_blob          providerdata;
  guid                   layerkey;		// 过滤器所在的分层标识
  guid                   sublayerkey;	// 过滤器所在的子层标识
  fwp_value0             weight;		// 权重
  uint32                 numfilterconditions;	// 过滤条件数
  fwpm_filter_condition0 *filtercondition;		// 过滤条件
  fwpm_action0           action;		// 操作
  union {
    uint64 rawcontext;
    guid   providercontextkey;
  };
  guid                   *reserved;
  uint64                 filterid;
  fwp_value0             effectiveweight;
} fwpm_filter0;

typedef struct fwpm_action0_ {
  fwp_action_type type;	// 操作类型,如fwp_action_block(阻止流量)、fwp_action_permit(允许流量)
  union {
    guid filtertype;	// 过滤类型
    guid calloutkey;	// 呼出接口标识
  };
} fwpm_action0;

呼出接口(callout)

呼出接口由一系列的回调函数组成,当网络数据包命中某过滤器的规则且该过滤器关联了呼出接口时,就会调用该呼出接口的回调函数。
callout除了包含回调函数外,还包含一个guid值,用来唯一地标识一个呼出接口。
一般来说,不同的呼出接口的回调函数实现不同的功能,系统内置了一部分呼出接口可以供开发者使用,开发者也可以向系统注册自己的呼出接口来完成特定的逻辑。

typedef struct fwps_callout1_ {
	guid calloutkey;		// 呼出接口标识
	uint32 flags;			// 特性,可设为0
	fwps_callout_classify_fn1 classifyfn;
	fwps_callout_notify_fn1 nptifyfn;
	fwps_callout_flow_delete_notify_fn0 flowdeletefn;
}fwps_callout1

呼出端口的回调函数(classifyfn、notifyfn、flowdeletefn)

  • classifyfn:过滤器的规则被命中时被调用,可以在回调函数中获取网络数据包的相关信息,具体信息取决于过滤器所在的分层,还可以对网络数据包设置允许/拦截操作,。
  • notifyfn:过滤器被添加到过滤引擎中或者从过滤引擎中移除时被调用。
  • flowdeletefn:当一个网络数据流要被终止时被调用。
void fwpscalloutclassifyfn1(
  [in]           const fwps_incoming_values0 *infixedvalues,	// 被过滤层中每个数据字段的值
  [in]           const fwps_incoming_metadata_values0 *inmetavalues,	// 被过滤层中每个元数据字段的值
  [in, out]      void *layerdata,	// 指向被过滤层中原始数据的结构指针,可能为null
  [in, optional] const void *classifycontext,	// 可选,表示和呼出接口驱动关联的上下文
  [in]           const fwps_filter1 *filter,	// 过滤器指针
  [in]           uint64 flowcontext,	// 和流句柄关联的上下文
  [in, out]      fwps_classify_out0 *classifyout	// 该函数对该网络数据包的过滤结果
);
typedef struct fwps_classify_out0_ {
  fwp_action_type actiontype;	// 操作类型
  uint64          outcontext;
  uint64          filterid;
  uint32          rights;
  uint32          flags;
  uint32          reserved;
} fwps_classify_out0;

ntstatus fwpscalloutnotifyfn1(
  [in] fwps_callout_notify_type notifytype,	// 通知类型, fwps_callout_notify_add_filter / fwps_callout_notify_delete_filter / fwps_callout_notify_type_max
  [in] const guid *filterkey,	// 过滤器标识
  [in] fwps_filter1 *filter		// 过滤器指针
);
void fwpscalloutflowdeletenotifyfn0(
  [in] uint16 layerid,		// 分层标识
  [in] uint32 calloutid,	// 呼出接口id
  [in] uint64 flowcontext	// 关联的上下文指针
);

通过wfp api实现网络数据包过滤

  • 调用fwpmengineopen0打开过滤引擎的会话,获得引擎句柄;使用结束后调用fwpmengineclose0关闭。
  • 调用fwpmtransactionbegin0 在当前会话中开始事务;使用结束后使用pfnfwpmtransactionabort0终止事务。
  • 定义一个或多个呼出接口(自实现回调函数),然后调用用fwpscalloutregister0向过滤引擎注册呼出接口;使用结束后调用fwpscalloutunregisterbyid0fwpscalloutunregisterbykey0卸载。
  • 调用fwpmcalloutadd0向过滤引擎中添加呼出接口;使用结束后调用fwpmcalloutdeletebyid0移除。
  • 初始化过滤器并关联呼出接口,调用fwpmfilteradd0向过滤引擎中添加过滤器;移除过滤器使用fwpmfilterdeletebyid0fwpmfilterdeletebykey0
  • 调用fwpmtransactioncommit0 在当前会话中提交当前事务。
  • 关闭句柄以及终止会话事务。
(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com