简介这份资源是面向Windows内核开发与网络安全方向学习者的WFP网络驱动防火墙源码适合具备一定驱动开发基础、希望深入理解Windows过滤平台WFP架构的开发者参考。它可用于研究网络数据包拦截、过滤规则下发与驱动层通信等典型场景帮助读者在真实代码中理清WFP的调用流程与实现思路。压缩包为zip格式整体约766KB体量轻便便于快速导入工程对照阅读。目前已有283人学习关注说明其在驱动防火墙这一细分领域具备一定参考价值。源码围绕防火墙与WFP驱动展开读者可从中获取过滤引擎注册、网络层与传输层拦截、规则匹配及驱动与用户态交互等关键实现细节并据此搭建自己的实验工程或进行二次开发。对于想从零理解Windows驱动防火墙工作原理、补齐内核网络编程短板的开发者而言这是一份可直接研读的实践素材。1. SuperDriver 与 WFP从内核驱动到防火墙过滤的落地路径Windows 平台上做网络过滤绕不开 WFPWindows Filtering Platform。很多人第一次听到 SuperDriver 这个词会以为它是一个现成的防火墙产品其实它更像一个技术方向用内核驱动的方式把网络流量的拦截、放行、审计能力做到系统底层。标题里的 windowsdriver、firewall、wfp 三个词恰好对应了这条路径的三个关键层——驱动是载体firewall 是目标WFP 是官方提供的过滤框架。如果你正在做终端安全、流量管控、或者需要在内核态实现精细化的网络策略这套组合值得认真研究。它适合有 C/C 基础、了解 Windows 驱动模型、并且愿意在虚拟机里反复调试的工程师。新手可以跟着步骤跑通最小过滤驱动熟手则要关注过滤层选择、回调优先级和性能开销这些边界问题。2. WFP 架构与驱动选型为什么不用 NDIS 或 TDI2.1 WFP 的分层模型与过滤引擎WFP 不是单一 API而是一套分层的过滤架构。它把网络栈切成多个层Layer每个层对应数据包处理的不同阶段。常见的层包括 FWPM_LAYER_INBOUND_IPPACKET_V4入站 IP 包、FWPM_LAYER_OUTBOUND_TRANSPORT_V4出站传输层、FWPM_LAYER_ALE_AUTH_CONNECT_V4连接授权等。每个层上可以挂多个过滤器Filter过滤器由条件Condition和动作Action组成。条件可以是 IP 地址、端口、协议号、进程 ID 等动作通常是 permit、block 或 callout。WFP 的核心优势在于它在内核态提供统一的过滤点不需要自己解析 TCP/IP 栈也不需要 hook 系统调用。相比 NDIS 驱动WFP 的过滤逻辑更靠近策略层开发量小、稳定性高。相比已经废弃的 TDIWFP 有微软官方支持和持续更新。选型时我一般会先确认需求如果只是做 IP/端口级别的黑白名单用 WFP 的过滤层直接挂 Filter 就够了如果要做深度包检测或协议解析才需要写 callout 驱动。2.2 驱动类型选择WDM、KMDF 还是 WFP CalloutWindows 驱动模型有 WDM、KMDF、UMDF 几种。WFP 的 callout 驱动通常用 KMDF 或 WDM 编写因为需要在内核态注册 callout 函数。KMDF 封装了大部分 PnP 和电源管理逻辑代码量少推荐新手从 KMDF 入手。但要注意WFP 的 callout 注册本身是一套独立的 API和 KMDF 的框架并不冲突。一个常见的误区是以为写了 WFP callout 就能拦截所有流量。实际上callout 只在你注册的层和条件下被触发。如果只在 ALE_AUTH_CONNECT 层注册那么已经建立的连接不会再次触发。要覆盖完整生命周期需要在多个层注册或者使用 WFP 的 net event 机制。我一般会先画一张流量路径图标出哪些层需要挂过滤器再决定 callout 的注册点。2.3 最小过滤驱动的代码骨架下面是一个 KMDF 驱动中注册 WFP 过滤器的核心代码片段。它演示了如何打开过滤引擎、添加一个出站阻断过滤器。// 打开 WFP 过滤引擎 HANDLE engineHandle NULL; FWPM_SESSION0 session {0}; session.flags FWPM_SESSION_FLAG_DYNAMIC; // 动态会话驱动卸载时自动清理 NTSTATUS status FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, session, engineHandle); if (!NT_SUCCESS(status)) { DbgPrint(FwpmEngineOpen0 failed: 0x%X\n, status); return status; } // 添加过滤器阻断出站到 192.168.1.100 的 TCP 流量 FWPM_FILTER0 filter {0}; FWPM_FILTER_CONDITION0 conditions[2] {0}; // 条件1远程 IP 地址 conditions[0].fieldKey FWPM_CONDITION_IP_REMOTE_ADDRESS; conditions[0].matchType FWP_MATCH_EQUAL; conditions[0].conditionValue.type FWP_UINT32; conditions[0].conditionValue.uint32 0xC0A80164; // 192.168.1.100 // 条件2协议为 TCP conditions[1].fieldKey FWPM_CONDITION_IP_PROTOCOL; conditions[1].matchType FWP_MATCH_EQUAL; conditions[1].conditionValue.type FWP_UINT8; conditions[1].conditionValue.uint8 IPPROTO_TCP; filter.layerKey FWPM_LAYER_ALE_AUTH_CONNECT_V4; filter.action.type FWP_ACTION_BLOCK; filter.filterCondition conditions; filter.numFilterConditions 2; filter.displayData.name LBlock 192.168.1.100 TCP; filter.weight.type FWP_EMPTY; // 自动权重 UINT64 filterId 0; status FwpmFilterAdd0(engineHandle, filter, NULL, filterId); if (!NT_SUCCESS(status)) { DbgPrint(FwpmFilterAdd0 failed: 0x%X\n, status); FwpmEngineClose0(engineHandle); return status; }这段代码的逻辑是先打开一个动态 WFP 会话然后构造一个过滤器指定层为 ALE_AUTH_CONNECT_V4条件为远程地址等于 192.168.1.100 且协议为 TCP动作为阻断。最后调用 FwpmFilterAdd0 把过滤器加入引擎。参数说明FWPM_SESSION_FLAG_DYNAMIC 表示会话是动态的驱动卸载或进程退出时 WFP 会自动清理该会话下的所有过滤器避免残留规则。filter.weight.type 设为 FWP_EMPTY 表示由系统自动分配权重权重高的过滤器优先匹配。如果多条规则冲突需要手动设置权重。提示在开发阶段建议先用 FWP_ACTION_BLOCK 配合具体条件做小范围测试确认过滤生效后再扩大规则范围。直接阻断所有流量可能导致调试通道中断。3. 从驱动加载到规则生效完整落地步骤3.1 环境准备与驱动签名在 Windows 上加载内核驱动签名是绕不过去的坎。开发阶段可以开启测试签名模式用 bcdedit 命令设置。具体操作以管理员身份打开命令提示符执行bcdedit /set testsigning on然后重启。重启后桌面右下角会显示“测试模式”水印。接着用 Visual Studio 的 WDK 工具链编译驱动生成 .sys 文件。测试签名可以用 makecert 和 signtool 生成自签名证书并签名。# 开启测试签名模式管理员权限 bcdedit /set testsigning on # 重启后验证 bcdedit /enum | findstr testsigning # 生成自签名证书在 WDK 命令行中 makecert -r -pe -ss PrivateCertStore -n CNTestDriver testcert.cer # 签名驱动 signtool sign /v /s PrivateCertStore /n TestDriver /t http://timestamp.digicert.com SuperDriver.sys参数说明/r表示创建自签名证书/pe表示私钥可导出/ss指定证书存储位置。signtool 的/s指定存储名/n指定证书主题名/t指定时间戳服务器。注意时间戳服务器地址可能因网络环境不同而需要调整如果时间戳失败可以去掉/t参数先本地签名。3.2 驱动加载与 WFP 会话初始化驱动编译签名后可以用sc create注册为系统服务然后sc start启动。更常用的调试方式是用 OSR Loader 或 WinDbg 直接加载。驱动入口函数 DriverEntry 中除了常规的 KMDF 初始化还要调用 WFP 的引擎打开和过滤器注册。NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { WDF_DRIVER_CONFIG config; WDF_DRIVER_CONFIG_INIT(config, EvtDeviceAdd); NTSTATUS status WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, config, WDF_NO_HANDLE); if (!NT_SUCCESS(status)) { return status; } // 初始化 WFP status InitWfpFilters(); if (!NT_SUCCESS(status)) { DbgPrint(InitWfpFilters failed: 0x%X\n, status); return status; } return STATUS_SUCCESS; }InitWfpFilters 函数内部就是上一节展示的 FwpmEngineOpen0 和 FwpmFilterAdd0 调用。注意驱动卸载时要调用 FwpmEngineClose0 关闭会话动态会话会自动清理过滤器但显式关闭更稳妥。3.3 验证过滤效果用 netsh 和日志确认驱动加载后怎么确认过滤器真的生效最直接的方法是用 netsh 查看 WFP 状态。netsh wfp show state可以导出当前 WFP 的完整状态到 XML 文件里面包含所有过滤器和层的信息。搜索你设置的过滤器名称如果能找到且状态为 active说明注册成功。# 导出 WFP 状态 netsh wfp show state # 查看生成的 XML 文件默认在当前目录 # 搜索过滤器名称 findstr /C:Block 192.168.1.100 TCP wfpstate.xml另一个验证方法是实际发起连接。用 ping 或 telnet 测试目标地址如果被阻断连接会超时或立即失败。同时可以在驱动里加 DbgPrint 输出用 DebugView 查看 callout 是否被触发。注意 DbgPrint 在正式发布版本中应移除或改为 ETW 日志避免性能影响。注意netsh wfp show state导出的 XML 文件可能很大建议用 findstr 或 PowerShell 的 Select-String 过滤关键字不要直接打开。4. 避坑与排查WFP 驱动开发中的五个血泪教训4.1 过滤器不生效层选错了现象驱动加载成功netsh 也能看到过滤器但目标流量依然能通。原因过滤器挂在了不匹配的层。比如想阻断出站连接却挂在了 FWPM_LAYER_INBOUND_IPPACKET_V4。解决确认流量方向出站连接授权用 ALE_AUTH_CONNECT_V4入站用 ALE_AUTH_RECV_ACCEPT_V4。如果不确定先用netsh wfp show layers列出所有层找到对应方向的层再注册。4.2 驱动加载失败签名或依赖问题现象sc start报错 577 或 1275。原因577 是签名验证失败1275 是驱动被阻止加载。解决确认测试签名模式已开启证书已导入受信任的根证书颁发机构。如果是 1275检查驱动是否被组策略或安全软件拦截。在虚拟机里开发时关闭安全软件的驱动拦截功能。4.3 系统蓝屏callout 函数里做了分页操作现象驱动运行一段时间后蓝屏错误码 IRQL_NOT_LESS_OR_EQUAL。原因WFP callout 函数可能在 DISPATCH_LEVEL 被调用此时不能访问分页内存或调用可能引起页错误的函数。解决callout 里只做轻量判断复杂逻辑放到工作项或系统线程中处理。所有在 callout 中访问的内存确保是非分页的用 ExAllocatePoolWithTag 时指定 NonPagedPool。4.4 规则残留动态会话没清理现象驱动卸载后之前设置的阻断规则依然生效导致目标地址无法访问。原因WFP 会话不是动态的或者驱动异常退出没有关闭会话。解决始终使用 FWPM_SESSION_FLAG_DYNAMIC 标志并在 DriverUnload 中显式调用 FwpmEngineClose0。如果已经残留可以用netsh wfp show state找到过滤器 ID再用netsh wfp delete filter删除。4.5 性能下降过滤器条件过于宽泛现象开启驱动后网络吞吐明显下降CPU 占用升高。原因过滤器条件太少导致每个包都要经过 callout 判断。解决尽量在过滤器中添加精确条件减少 callout 触发频率。比如用 IP 地址和端口组合条件而不是只匹配协议。另外把多个条件合并到一个过滤器而不是注册多个过滤器分别匹配。5. 进阶技巧用 WFP 实现动态黑白名单与进程级管控5.1 基于进程 ID 的过滤WFP 支持按进程 ID 过滤这在做应用级防火墙时非常有用。条件字段是 FWPM_CONDITION_ALE_APP_ID类型是 FWP_BYTE_BLOB需要把进程路径转换成 WFP 的内部标识。可以用 FwpmGetAppIdFromFileName0 函数把文件路径转成 App ID。// 把进程路径转为 App ID FWP_BYTE_BLOB* appId NULL; NTSTATUS status FwpmGetAppIdFromFileName0(L\\Device\\HarddiskVolume3\\Program Files\\MyApp\\app.exe, appId); if (NT_SUCCESS(status)) { conditions[0].fieldKey FWPM_CONDITION_ALE_APP_ID; conditions[0].matchType FWP_MATCH_EQUAL; conditions[0].conditionValue.type FWP_BYTE_BLOB_TYPE; conditions[0].conditionValue.byteBlob appId; // 后续添加到 filter 中 }参数说明FwpmGetAppIdFromFileName0 接受 NT 路径格式的文件名返回的 FWP_BYTE_BLOB 需要在使用后调用 FwpmFreeMemory0 释放。注意路径必须是设备路径不能用 Win32 路径。可以用 QueryDosDevice 把盘符转成设备路径。5.2 动态更新规则运行时增删过滤器实际产品中规则需要动态更新。WFP 提供了 FwpmFilterAdd0 和 FwpmFilterDeleteById0 两个 API可以在驱动运行期间增删过滤器。我一般会维护一个规则列表每条规则对应一个 filterId更新时先删旧再加新。注意删除和添加之间可能有短暂的空窗期如果要求无缝切换可以先用高权重的新规则覆盖再删除旧规则。5.3 验证与监控用 ETW 记录过滤事件DbgPrint 只适合开发阶段正式版本建议用 ETWEvent Tracing for Windows记录过滤事件。WFP 本身支持审计事件可以在注册过滤器时设置 FWP_ACTION_FLAG_CALLOUT 并关联一个 callout 函数在 callout 中调用 EtwWrite 写入自定义事件。这样可以用 Windows 事件查看器或 tracelog 工具实时监控过滤情况。监控方式适用阶段性能开销持久化DbgPrint DebugView开发调试高否ETW 自定义事件测试与生产低可配置WFP 内置审计生产低是netsh wfp show state排查无否5.4 一个我踩过的坑App ID 路径格式第一次用 FwpmGetAppIdFromFileName0 时我传了C:\Program Files\MyApp\app.exe结果返回 STATUS_INVALID_PARAMETER。后来查文档才知道必须用 NT 设备路径比如\Device\HarddiskVolume3\Program Files\MyApp\app.exe。获取设备路径可以用QueryDosDevice或者用GetFinalPathNameByHandle再转换。这个坑卡了我半天希望后来者直接绕过。做 WFP 驱动这些年最大的习惯就是每次改完过滤器条件先在虚拟机里用netsh wfp show state确认规则状态再用实际流量验证最后才上真机。驱动开发没有后悔药蓝屏一次可能就要重装系统。把测试签名、动态会话、非分页内存这三件事刻在脑子里能省下大量排查时间。希望帮到你。本文还有配套的精品资源点击获取