关键词:Volatility 3、vol.py、插件命名、PluginLoader、ISF、渲染器、Linux 插件
难度:进阶
前置知识:内存采集流程、Python 基础、插件化架构概念
一、概述
有了内存镜像之后,你面对的是一大块没有格式的二进制。
要从里面读出"哪些进程在跑",必须先知道目标系统的 EPROCESS 结构长什么样、链表成员在第几个字节。没有这份定义,框架只能返回一堆十六进制——它甚至不知道自己读到的是不是有效数据。
Volatility 3 就是干这件事的:按目标系统的内核数据结构定义,把镜像内容重新解释成有语义的对象。它的存在把"读内存"从一件需要理解页表和结构偏移的手工活,变成了一条命令。而用好它的前提,是理解它的工作方式,而不是背下一长串命令名。
最容易浪费时间的一件事就是插件名写错。 网上的教程大多是 Volatility 2 时代的写法(pslist 不带前缀、--profile= 必填),而 Volatility 3 的插件名带命名空间前缀(windows.pslist)。写错不报"插件不存在",而是报"找不到符号表"或 automagic 失败——错误信息完全不指向真正的原因。
框架选型落在采集之后的分析引擎选择环节,上游是已经拿到并验证过的内存镜像,下游是四类具体分析任务(进程与注入、网络连接、凭据与密钥、非 Windows 平台)。它不负责采集,也不负责结论定性——框架的输出是原始材料,"这条发现能说到什么强度"在内存证据的可采性与报告里解决。
框架的输入与输出形态如下:
| 对象 |
具体形态 |
作用 |
| 镜像输入 |
DigiForensics-mem.raw、DigiForensics-mem.aff4、LiME 格式镜像 |
插件的 -f 参数 |
| 符号输入 |
Windows 的 ISF(JSON)、Linux 的 dwarf2json/btf2json 产物 |
让框架知道结构偏移 |
| 插件输出 |
pslist / netscan / malfind / cmdline 的表格或 JSON |
后续分析的原始材料 |
| 导出物 |
--dump 导出的进程内存、文件、注入页 |
二次分析的对象 |
| 日志 |
vol.py -l 留下的 vol.log |
可复现性的记录 |
最后一项容易被跳过:每次分析都要留日志,否则报告里的结论无法被第三方复现。
据此能回答的是这些:某个镜像里有哪些进程、哪些连接、哪些内存区域是私有可执行页、某个进程的完整内存内容、模块加载清单。它是枚举类问题的通用入口。
回答不了的是这些。它无法告诉你"没跑出来的插件"意味着什么——插件无输出可能是镜像不完整、可能是符号没匹配上、也可能确实没有该结构,这三种情况在输出上无法区分,必须回到三、操作步骤的验证环节交叉确认。框架也不会替你判断结论强度。
往下读之前,先确认你已经具备:基本的命令行与 Python 环境使用能力、理解"结构体偏移"这个概念(不需要会写内核代码)、以及一份可解析的内存镜像。镜像还没有,先看内存采集方法;镜像有但完全读不出内容,那不是这里的问题,看Windows 内存 Profile 机制。拿镜像后第一件事该跑什么,去进程与注入检测。
二、核心原理
2.1 架构:三层解耦
┌─────────────────────────────────────────────────────┐
│ 插件层 Plugins │
│ windows.pslist / linux.bash / timeliner ... │
│ —— 只关心"我要什么工件" │
├─────────────────────────────────────────────────────┤
│ 框架层 Framework │
│ automagic(自动层推断)→ layer(分层)→ symbol │
│ —— 负责"怎么在镜像上定位数据、怎么解释字节" │
├─────────────────────────────────────────────────────┤
│ 符号层 Symbols │
│ ISF 文件(Windows / Linux / macOS 各一套) │
│ —— 提供结构体的字段偏移与大小 │
└─────────────────────────────────────────────────────┘
automagic(自动魔法) 是 Volatility 3 的核心机制。传统做法是你手工指定"这个偏移是 Windows 10 的 KDBG",Volatility 3 改为自动推断:扫描镜像中的特征模式(如 KDBG 结构、PDB 签名)→ 推断出内核基址、是否 64 位、使用哪套符号 → 搭建出"物理地址 → 虚拟地址 → 结构字段"的完整映射链。
可观察的后果:一个正常镜像的首次 windows.info 会先花几十秒扫描(进度条 "PDB scanning finished"),而第二次运行因为缓存了就很快。如果你第二次也慢,检查缓存路径是否可写。
框架再好也救不回一份采集质量差的镜像。镜像来源、格式与采集后的验证步骤见第 02 篇。
2.2 插件命名规范:vol2 与 vol3 的根本差异
这是本板块最大的实践陷阱,必须彻底理解。
Volatility 2 的所有插件平铺、没有命名空间(vol.py -f mem.raw --profile=Win10x64 pslist)。
Volatility 3 的插件名必须带 OS 命名空间(python3 vol.py -f mem.raw windows.pslist)。
| 维度 |
Volatility 2 |
Volatility 3 |
| 插件名 |
pslist(平铺) |
windows.pslist(带命名空间) |
| 完整写法 |
无概念 |
windows.pslist.PsList(模块名 + 类名) |
| 系统匹配 |
--profile=Win10x64 必填 |
自动推断,无需 profile |
| PID 参数 |
-p 4628 |
--pid 4628 |
| 物理地址参数 |
--offset |
--physaddr |
| 导出文件 |
各插件自定义(-D、--dump-dir…) |
统一 -o + --dump |
| 输出格式 |
固定文本 |
-r quick/pretty/csv/json/jsonl |
实操建议:命令行里写模块名(windows.pslist)即可,框架会解析到对应类。若要显式指定类,用 windows.pslist.PsList(注意类名首字母大写、模块名全小写)。两者等价,但用模块名更简洁。
旧教程失效的具体表现:vol.py -f mem.raw pslist 在 vol3 里会提示找不到插件或 automagic 失败。很多人误以为是"镜像坏了"或"版本不对",实际上是命令写法属于上一代。看到不带前缀的插件名,先怀疑教程年代。
2.3 常用插件分类速查(Windows)
以下插件在 Volatility 3 2.28.2 的 framework/plugins/ 目录下逐一核实存在,一律使用规范位置。
| 维度 |
插件 |
用途 |
| 进程 |
windows.pslist |
遍历活动进程链表,列出运行中进程 |
|
windows.psscan |
扫描内存找进程对象,能发现被摘链的隐藏进程 |
|
windows.pstree / windows.malware.psxview |
父子关系树 / 多视角交叉比对 |
|
windows.cmdline |
命令行参数——取证价值最高 |
|
windows.envars / windows.getsids / windows.privileges |
环境变量 / SID / 特权 |
| 内存与模块 |
windows.malware.malfind |
扫描私有可执行页,检测注入 |
|
windows.malware.ldrmodules |
模块链表 vs 内存映射比对 |
|
windows.malware.hollowprocesses / pebmasquerade / processghosting |
空化 / PEB 伪装 / Process Ghosting 检测 |
|
windows.malware.suspicious_threads |
起始地址不在已知模块内的线程 |
|
windows.malware.skeleton_key_check |
域控 Skeleton Key 后门检测 |
|
windows.dlllist / windows.memmap |
进程加载的 DLL / 导出内存映射 |
|
windows.threads / windows.thrdscan |
线程枚举 / 扫描 |
| 句柄与文件 |
windows.handles / windows.filescan |
句柄表 / 扫描内核池中的 FILE_OBJECT |
|
windows.dumpfiles |
从内存导出文件(--physaddr / --virtaddr / --pid) |
|
windows.mftscan |
内存中的 MFT 缓存数据 |
| 网络 |
windows.netscan / windows.netstat |
扫描内核池(含已关闭连接)/ 仅活动连接 |
| 内核与 VAD |
windows.vadinfo / windows.vadwalk |
VAD 树结构 / VAD 遍历 |
|
windows.vadyarascan / windows.vadregexscan |
对 VAD 范围做 YARA / 正则扫描 |
|
windows.ssdt |
系统调用表(查 hook) |
|
windows.malware.unhooked_system_calls / indirect_system_calls |
inline hook / 间接系统调用检测 |
|
windows.callbacks / windows.malware.svcdiff |
内核回调持久化 / SCM 与内存服务差异 |
|
windows.driverscan / modscan / unloadedmodules |
驱动模块扫描 / 已卸载模块 |
|
windows.malware.drivermodule / windows.etwpatch |
驱动注册比对 / ETW 绕过检测 |
| 凭据 |
windows.registry.hashdump |
内存 SAM 中的 NTLM 哈希 |
|
windows.registry.lsadump |
LSA Secret(DPAPI 保护的凭据) |
|
windows.registry.cachedump |
缓存域凭据条目 |
| 注册表 |
windows.registry.hivelist / hivescan / printkey |
hive 列表 / 扫描导出 / 读指定键(--key) |
|
windows.registry.userassist / amcache |
UserAssist / Amcache 执行痕迹 |
| 服务与终端 |
windows.svcscan / svclist / windows.registry.scheduled_tasks |
服务扫描 / 计划任务 |
|
windows.consoles |
控制台历史(含输入内容) |
| 时间线 |
windows.cmdline + windows.registry.userassist + timeliner |
多源时间线合并 |
为什么本文只列 windows.malware.* / windows.registry.*,不列顶层旧名:这些顶层名(如 windows.malfind、windows.hollowprocesses、windows.scheduled_tasks、windows.amcache、windows.hashdump)在框架里是弃用转发壳——源码中它们继承 deprecation.PluginRenameClass,只把调用代理到新类并抛 FutureWarning。关键在于:这些壳的 removal_date 分别标注为 2026-06-07(malware 系)与 2026-09-25(registry 系),而框架的语义是"在 removal_date 之后的第一个发布版本中移除"。换言之,你手上任何比这两个日期更新的发行版,旧名都可能已经彻底消失。
因此:写脚本一律用规范名。 唯一的例外是手上只有旧版框架、需要兼容时,那才用旧名并加注释。
自查命令(任何版本都适用,列出你手上框架实际注册的全部插件):python3 vol.py -h 2>&1 | sed -n '/Plugins/,$p' | head -80
这一条比任何表格都可靠——表格反映的是某个版本,命令反映的是你手上那个版本。
2.4 Linux 插件
| 维度 |
插件 |
用途 |
| 进程 |
linux.pslist / pstree / psaux |
进程列表 / 父子关系 / 命令行+环境 |
|
linux.proc.Maps |
进程的内存映射(VMA) |
| 痕迹 |
linux.bash |
从内存恢复 bash 历史(含时间戳) |
|
linux.envars / linux.kmsg |
环境变量(常含密钥)/ 内核日志缓冲区 |
| 文件与网络 |
linux.lsof / linux.sockstat |
打开的文件 / 套接字统计 |
|
linux.ip.Addr / linux.mountinfo |
网络接口地址 / 挂载点 |
| 注入与 rootkit |
linux.malware.malfind |
私有可执行映射 |
|
linux.malware.check_modules / check_syscall / check_idt |
模块 vs sysfs / 系统调用表 hook / 中断描述表 |
|
linux.malware.check_afinfo / tty_check / netfilter |
协议函数指针 / TTY 钩子 / netfilter 钩子 |
|
linux.malware.hidden_modules / modxview |
隐藏模块 / 多视角模块比对 |
|
linux.malware.process_spoofing |
进程命令行与名称伪装检查 |
| 其他 |
linux.psscan / linux.pidhashtable |
扫描进程 / PID 哈希表(与链表交叉) |
|
linux.pscallstack / linux.capabilities |
进程调用栈 / capabilities |
|
linux.boottime / linux.kthreads |
启动时间基准点 / 内核线程 |
|
linux.ebpf / linux.tracing.* |
eBPF 程序映射 / ftrace·perf·tracepoint 检查 |
|
linux.keyboard_notifiers |
键盘通知链(键盘记录线索) |
|
linux.vmayarascan / linux.vmaregexcan |
对 VMA 范围做 YARA / 正则扫描 |
|
linux.pagecache.RecoverFs |
从 page cache 恢复文件系统内容 |
|
linux.ptrace / mac.bash |
被跟踪状态 / macOS shell 历史 |
⚠️ 重要澄清:这里列的 check_modules、check_syscall、tty_check 等"查 rootkit"插件,规范位置在 linux.malware.* 命名空间。顶层旧名(linux.check_modules 等)同样是弃用转发壳,removal_date 标注 2026-06-07。网上教程常见的 linux.check_modules 是旧名——在旧框架上能跑,但新框架上可能已经找不到。
⚠️ 不要写不存在的插件名:诸如 linux.netscan、linux.pcap、linux.harp、linux.nsenter、linux.msgqueue、linux.kdmesg、linux.ifconfig 这些名字在官方发行版中并不存在。Linux 内核日志的正确插件名是** linux.kmsg,网络接口地址是 linux.ip.Addr**。写报告引用插件时,务必用 python3 vol.py -h 核对实际可用列表。
2.5 渲染器与输出
Volatility 3 所有插件共用一套输出格式选择:
| 渲染器 |
输出 |
适用 |
quick(默认) |
立即输出的制表符文本,列宽不对齐 |
快速浏览 |
pretty |
结束时输出,列按宽度对齐 |
人工阅读首选 |
csv |
逗号分隔 |
导入 Excel / 时间线工具 |
json |
JSON 数组 |
程序处理 |
jsonl |
每行一条 JSON |
流式处理、大数据量 |
-r 必须在插件名【之前】,否则不生效
python3 vol.py -f mem.raw -r pretty windows.pslist
python3 vol.py -f mem.raw -r csv windows.pslist > pslist.csv
python3 vol.py -f mem.raw -r json windows.cmdline > cmdline.json
三、操作步骤
3.1 第 1 步:安装与验证
官方推荐:独立虚拟环境(避免与系统 Python 冲突)
python3 -m venv ~/vol3env
source ~/vol3env/bin/activate
pip install volatility3
验证
python3 vol.py --v