1. 引言

前面的文章主要记录 SnowSword 在进程、驱动和内存视角上的检测实践。这次把测试重点放到 SnowWall 对恶意行为链的检测:使用 SnowSword 在授权的隔离实验机中对 Windows 计算器进程执行 DLL 远程注入,然后观察 SnowWall 如何记录、关联并阻断这一串操作。

本文只讨论防御性检测和实验现象。远程线程注入也可能出现在调试、兼容性工具和安全软件中,因此“命中行为链”是需要进一步复核的高风险信号,而不是脱离上下文的恶意归因。

2. 实验环境与对照条件

实验对象是 Windows 11 中的 CalculatorApp.exe,日志记录的目标 PID 为 4236。发起方是桌面目录下未签名的 SnowSword.exe,PID 为 7108,父进程为 explorer.exe。

实验采用两组对照:

条件 观察结果
SnowWall 开启 注入流程出现失败提示,日志记录跨进程内存操作和远程线程创建,并在行为阈值处阻断
SnowWall 关闭 注入流程出现成功提示,作为未启用防护时的对照现象

两组截图的窗口布局基本一致,区别主要在 SnowWall 是否仍处于监控状态以及注入结果提示。这里的“成功/失败”只表示本次测试程序报告的结果,最终判断仍以日志和目标进程状态为准。

3. 注入代码的行为拆解

RemoteInjectDll 的核心流程可以抽象为:

1
2
3
4
5
6
7
8
OpenProcess(PROCESS_ALL_ACCESS)
↓
VirtualAllocEx 分配目标进程内存
↓
WriteProcessMemory 写入 DLL 路径
↓
ZwCreateThreadEx 在目标进程创建线程
└─ 线程入口 = LoadLibraryW

代码首先通过 OpenProcess(PROCESS_ALL_ACCESS, ...) 获取目标进程句柄。随后按 DLL 路径长度调用 VirtualAllocEx,再用 WriteProcessMemory 把路径写入目标地址空间,并通过 ReadProcessMemory 做一次写入验证。

在 64 位分支中,由于 64 位 Windows 的 kernel32.dll 在系统范围内按相同基址加载,远程线程入口可以直接使用本进程解析到的 LoadLibraryW 地址,参数是目标进程中的路径地址。在 32 位分支中,代码额外获取目标进程中的函数地址,构造一段调用 LoadLibraryW 的 x86 shellcode,分配可执行内存后再通过 ZwCreateThreadEx 执行。两条分支的实现细节不同,但从防御侧看都形成了相同的高风险序列:跨进程分配、跨进程写入、跨进程线程创建。

这也是行为检测比只匹配某个 API 更有价值的地方:单独调用 VirtualAllocEx 可能有正常用途,但它与后续写入和远程线程创建在短时间内连续出现时,语义明显发生变化。

4. SnowWall 日志中的行为链

日志时间集中在 06:52:20 至 06:52:21,关键记录如下:

4.1 第一步:跨进程分配导致污点升级

首先,NtAllocateVirtualMemory 被记录为规则评估事件,随后 SnowWall 输出 CrossAlloc 告警,原因是“污点等级升级为 1”,可疑度分数为 15,并标记为永久污染。

这一步并没有立即给出最终阻断结论,但它为后续行为建立了上下文状态。也就是说,SnowWall 并非把每一次系统调用都孤立处理,而是为进程累积行为标签。

4.2 第二步:向 CalculatorApp.exe 写入内存

紧接着的 NtWriteVirtualMemory 事件显示:

  • 发起 PID:7108;
  • 目标 PID:4236;
  • 目标映像:CalculatorApp.exe;
  • CrossProcess=1;
  • 发起程序未签名,且没有可信祖先进程标记。

该条记录中的 rule_action=1 和 reason=RULE_ALLOW 表示这一条规则评估本身没有阻断,不能理解成整个注入流程已经被 SnowWall 放行。它只是行为链中的中间事件。

4.3 第三步:远程线程创建触发阈值

随后到达 NtCreateThreadEx——用户态调用 ZwCreateThreadEx 最终进入的正是这个内核系统服务,因此日志记录的是 NtCreateThreadEx。日志明确标出 CrossThreadCreate,匹配规则“远程线程注入链”,可疑度分数升至 82.91,并出现 behavior_hit=1、reason=BEHAVIOR_THRESHOLD。

之后 SnowWall 输出:

1
2
行为累积判定恶意: PID=7108 LastTag=CrossThreadCreate
event=DECISION ... action=BLOCK reason=BEHAVIOR_THRESHOLD

因此,本次实验的完整判定是:前面的单条规则评估允许记录继续进入决策流程;当跨进程分配、写入和远程线程创建形成可疑序列后,行为累计分数达到阈值,SnowWall 最终执行 BLOCK。

5. 截图与日志的相互印证

5.1 SnowWall 开启:注入被阻断

SnowWall 开启时拦截注入

截图中可以看到 SnowSword 的目标进程列表、Windows 计算器窗口和 SnowWall 窗口,同时弹出“注入失败”的提示。它与日志最后的 action=BLOCK 相互印证:测试程序观察到失败,SnowWall 侧则给出了行为阈值阻断记录。

5.2 SnowWall 关闭:作为对照的成功提示

SnowWall 关闭后的成功注入对照

关闭 SnowWall 后,界面弹出“注入成功”的提示。

6. 结果分析:为什么是“行为链”而不是单点告警

本次日志可以整理成一条简化链路:

1
2
3
4
5
6
7
8
9
10
11
未签名 SnowSword.exe
│
├─ NtAllocateVirtualMemory ── CrossAlloc,污点等级 1,分数 15
│
├─ NtWriteVirtualMemory ───── CrossProcess=1,写入 PID 4236
│
└─ NtCreateThreadEx ───────── CrossThreadCreate,分数 82.91
↓
BEHAVIOR_THRESHOLD
↓
BLOCK

其中有三个值得注意的设计点:

  1. 状态累积:第一次分配操作先建立污点,后续事件可以继承上下文;
  2. 目标关联:日志不仅记录 API,还记录目标 PID、目标映像和跨进程标志;
  3. 分级决策:中间事件可以先记录或允许,最终由行为阈值统一决定是否阻断。

这种策略比“看到 OpenProcess 就直接拦截”更适合降低误报,也比只等待 DLL 加载完成再处理更及时。

7. 工程观察与防御建议

从测试代码和日志可以得到几项工程上的观察:

  • PROCESS_ALL_ACCESS 权限过宽,防御产品可将句柄权限、调用者身份和目标进程保护级别纳入风险评分;
  • VirtualAllocEx 与 WriteProcessMemory 的组合比单独的内存分配更值得关注;
  • NtCreateThreadEx 是行为链中的关键收敛点,但检测不应只依赖函数名,还要核对入口地址、目标进程和前序事件;
  • 32 位分支需要额外的可执行内存和 shellcode,64 位分支则直接将 LoadLibraryW 作为线程入口,跨架构差异可以作为日志字段而不是简单的放行条件;
  • 测试程序在清理路径中关闭句柄,但还应确保远程内存和 shellcode 在所有失败分支都得到释放,避免实验代码自身引入泄漏或不稳定因素。

对防御侧而言,较稳妥的策略是保留原始事件、建立短时间窗口内的行为关联,并把签名、路径、父子进程关系和目标映像作为辅助证据。最终动作可以按风险等级分为记录、告警、挂起或阻断,同时为调试工具和受信任软件保留明确的审计例外。

8. 当前局限与证据边界

本次实验仍有以下限制:

  1. 只有一组目标进程和一次主要日志片段,尚未进行多次重复统计;
  2. 未覆盖签名的合法调试器、不同完整性级别和受保护进程;
  3. 未分别验证 32 位目标进程分支与 64 位目标进程分支的全部路径;
  4. 截图中的“注入成功”来自测试程序提示,尚未用独立工具确认 DLL 模块、入口执行和线程退出状态;
  5. 当前日志没有展示完整规则配置、阈值定义和所有前置事件,因此不能据此推断 SnowWall 在其他版本或其他策略下必然给出相同结果。

换句话说,日志能够证明本次运行中 SnowWall 观察到了这些 API 事件,并在该策略下输出 BLOCK;截图能够证明两种开关状态下界面现象不同。至于检测覆盖率、误报率和跨版本稳定性,还需要更系统的实验设计。

9. 后续实验计划

后续准备建立一个小型复现实验矩阵,至少保留以下字段:

  • SnowWall 版本、规则版本和 Windows 版本;
  • 发起进程签名、路径、完整性级别与父进程;
  • 目标进程架构、保护属性和 PID;
  • 每个 API 事件的时间戳、目标和规则动作;
  • 最终动作、测试程序返回值和独立验证结果;
  • 正常调试场景与注入测试场景的重复次数。

在此基础上,再比较只调用单个 API、缺少前序事件以及完整行为链时的分数变化,才能更准确地评估 SnowWall 的阈值设计和误报边界。

总结

这次实验展示了 SnowWall 如何从 NtAllocateVirtualMemory、NtWriteVirtualMemory 到 NtCreateThreadEx 逐步积累上下文,并将跨进程内存操作与远程线程创建关联为“远程线程注入链”。日志中的 CrossAlloc、CrossThreadCreate、BEHAVIOR_THRESHOLD 和最终 BLOCK,与 SnowWall 开启时的失败提示形成了较完整的证据链;关闭 SnowWall 后的成功提示则提供了直观对照。

这个结果说明,针对高风险进程行为,按序列关联和分级决策比单点 API 拦截更有解释力。但它仍然是一次受控环境下的功能验证,不能替代多版本、多样本和正常软件基线测试。

参考

  • Microsoft Learn:OpenProcess、VirtualAllocEx、WriteProcessMemory、NtCreateThreadEx
  • Windows Internals, 7th Edition
  • 本系列前篇:日报_SnowSword隐藏驱动检测实测、SnowSword-隐藏驱动检测原理与工程实现
  • SnowSword 项目地址:https://gitee.com/le-ziyi/SnowSword

相关项目与联系

项目SnowSword —— Windows 10/11 x64 内核分析与 Anti-Rootkit 工具,源码与发布包在 Gitee。

技术合作Windows 内核 / 驱动开发 / 逆向分析 / 兼容性开发,范围与边界见 技术合作。

联系2160752730@qq.com · QQ 2160752730 · 微信 lst_3258110