0x01 前言

2713这兄弟又公开新姿势了

https://www.zerosalarium.com/2026/06/edrchoker-choking-telemetry-stream-block-edr.html
https://github.com/TwoSevenOneT/EDRChoker

借助Policy-based QoS限制EDR Agent和EDR Server之间的流量交互,表面是借助Policy-based QoS,实际上Policy-based QoS会调用内核中的NDIS LWF(NDIS轻量级过滤器,功能实现位于驱动pacer.sys中),NDIS LWF位于WFP的更底层,所以可以绕过EDR对流量的审查(EDR对流量的审查通常在WFP层,功能实现位于驱动tpcip.sys中),在流量上致盲EDR Agent,

网络流量从上到下,流经的各层如下:
应用层 (Sockets) -> TDI/Wsk (传输内核) -> tcpip.sys (传输层) -> NDIS LWF (pacer.sys 所在层) -> NDIS Miniport (网卡驱动) -> 物理硬件

NDIS是什么?
Network Device Interface Specification,网络设备接口规范,是微软 Windows 操作系统中定义的一套网络架构标准,它就像一个“翻译官”或“中介”。在它之上,是各种网络协议(如 TCP/IP);在它之下,是各种各样不同厂家生产的网卡驱动(Miniport Driver),有了 NDIS,写 TCP/IP 协议的人不需要关心用户用的是华为、Realtek 还是 Intel 的网卡;而写网卡驱动的人也不必去关心系统跑的是什么协议。大家都和 NDIS 接口对接即可

0x02 WMI是什么

WMI,全称:Windows Management Instrumentation,译为:Windows管理规范

可以把它理解成一个巨大的系统信息与配置数据库,我们可以:
查询系统信息:CPU型号、硬盘序列号、正在运行的进程、服务列表、事件日志……
修改系统设置:更改QoS限速策略、创建WMI事件监控、调用系统方法……

0x03 如何访问WMI

WMI技术基于COM,所以如果想用C++调用WMI,其实是C++ COM编程,比较繁琐

C#中直接封装了COM对象的交互,可通过System.Management命名空间下的类(如:ManagementScope、ManagementClass、ManagementObject等)来与WMI交互

0x04 关键代码讲解

整个程序代码相对简单,只有2个CSharp文件:Program.cs和Utils.cs,Utils.cs中的代码做了3件事:从文件中读取进程名、输出Banner、判断是否是Admin权限,都是常规编程内容

Program.cs中做了2件事:创建QoS策略,清除QoS策略,重点是如何创建和清除QoS策略,我们看下关键代码

1
2
3
4
5
6
7
8
9
10
var managementScope = new ManagementScope(@"\\.\ROOT\StandardCimv2");
managementScope.Connect();

\\.\ -> 表示本机
ROOT\StandardCimv2 -> 这是管理现代网络、存储等操作系统标准化设置的新区域,引入了许多遵循新标准(CIM)的类
ROOT\SecurityCenter2 -> 这个区域用来管理Windows安全中心的信息,如防火墙、杀毒软件等
ROOT\MicrosoftDNS -> 这里专门存放与DNS服务器相关的管理信息,如果你的计算机安装了DNS服务器角色,就可以在这里查询相关信息
ROOT\CIMv2 -> 这是WMI中最常用的命名空间,它包含了管理Windows操作系统、硬件和绝大多数软件所需的核心类,比如 Win32_Process(进程)、Win32_Service(服务)、Win32_LogicalDisk(逻辑磁盘)和 Win32_Product(软件产品)等。这个区域非常庞大,拥有超过1000个预定义的 WMI 类,是进行常规系统管理任务最常用的地方

还有很多这样的命令空间,不一一列举,总之这里用到的是 ROOT\StandardCimv2

创建特定命名空间的实例,并进入这个命名空间

1
2
3
4
5
var managementPath = new ManagementPath("MSFT_NetQosPolicySettingData");
var policyClass = new ManagementClass(managementScope, managementPath, null);
ManagementObject newPolicy = policyClass.CreateInstance();

还有 MSFT_NetAdapter_QosSettings、MSFT_NetAdapterQosElementSetting等等类,这里用到的是 MSFT_NetQosPolicySettingData

创建类MSFT_NetQosPolicySettingData的实例

1
2
3
4
5
6
7
8
9
newPolicy["Owner"] = 1;
string guid = Guid.NewGuid().ToString();
string policyName = Path.GetRandomFileName().Replace(".", "").Substring(0, 8);
newPolicy["Name"] = policyName;
newPolicy["InstanceID"] = $"{guid}\\{policyName}\\ActiveStore";
newPolicy["AppPathNameMatchCondition"] = procName;
newPolicy["IPProtocolMatchCondition"] = 3U;
newPolicy["NetworkProfile"] = 0U;
newPolicy["ThrottleRateAction"] = 8UL;

为这个实例设置各种属性(其实就是为这个Policy设置各种参数),包括策略名称、策略ID、要限速的进程名称、限速多少等等

1
2
3
4
5
var putOptions = new PutOptions
{
Type = PutType.CreateOnly
};
newPolicy.Put(putOptions);

将实例写入WMI存储库(应用策略)

0x05 尾语

流量侧致盲EDR Agent,最开始是借助防火墙,但创建防火墙规则会被Windows审计系统记录,产生ID为2004的日志,再结合拦截的进程为EDR Agent,可以断定为恶意攻击

接着出现调用WFP的API致盲EDR Agent,但同样也会被Windows审计系统记录,产生ID为5157的日志,再结合拦截的进程为EDR Agent,可以断定为恶意攻击

现在出现了Policy-based QoS致盲EDR Agent,由于这项技术是限制EDR Agent的速度,并不是丢弃EDR Agent的数据包,所以不会产生上述的类型的日志,但是可以通过监测组策略或WMI的方式来检测这项攻击,已经有人做了这项工作
https://github.com/sbousseaden/EDRUnChoker

由此也引发,如果想研究一个新的流量侧的致盲EDR Agent,可以研究NDIS LWF层的其他功能,或者继续往底层研究,NDIS Miniport层,甚至脱离Windows操作系统,针对网卡固件的攻击