MCPTrace 是一个 Volatility 3 插件,用于从 Windows 和 Linux 内存转储中提取 MCP/JSON-RPC 消息候选。它会检查进程内存中的请求、响应、通知、工具名称和调用参数,然后记录恢复的内容及其在内存中的位置。
该项目侧重于分析人员可以检查和验证的证据。每个工件都保留其原始字节、进程 ID、虚拟地址、编码、长度和 SHA-256 哈希。结果可以导出为 JSONL,以便进一步分析或与其他日志进行比较。MCPTrace 在已获取的内存镜像上运行,不需要 LLM 或外部 AI API。
tools/call 名称和参数。当前分析目标是 Windows x64 和 Linux x86-64。插件名称指的是内存镜像中的操作系统,与运行 Volatility 所用的操作系统无关。
MCPTrace 使用 Volatility 的进程枚举和地址转换功能。在 Windows 上,它遍历进程的 虚拟地址描述符 (VAD);在 Linux 上,它遍历 虚拟内存区域 (VMA)。这些映射定义了要检查的进程地址范围。两个适配器共享相同的消息雕刻、关联、策略和导出代码。
在可读范围内,扫描器搜索字面量 JSON-RPC 版本标记,并在其周围定位候选 JSON 对象。它处理嵌套对象、转义字符、字符串内的花括号以及跨连续读取块的消息。具有重复键或不支持标识符的 JSON 会被拒绝,而不是被静默重新解释。MCP 相关性由已知方法名称、响应结构和关联的请求 ID 确定;它不是完整的 MCP 模式验证。
缺失的内存保持缺失状态。读取器不会用零填充空隙,也不会跨不同的 VAD/VMA 拼接字节。使用 --include-partial 时,未解析的片段可以单独显示,而不会虚构缺失的 ID 或参数。可以使用页表信息跳过大型未映射范围,不可读的地址范围仍会显示在扫描统计信息中。
关联是刻意保守的。诸如 1 之类的数字 ID 与字符串 ID "1" 不同,不同进程中的消息不会自动关联。与某个 ID 关联的多个不同表示会被标记为有歧义。候选关系本身不会重建会话、消息方向或执行时间线。
需要 Python 3.10+。安装包含固定版本的框架依赖 volatility3==2.28.2。请保留仓库的 plugins/ 目录可用:Python 包通过 pip 安装,而 -p plugins 用于加载 Volatility 适配器。
git clone https://github.com/Kowntaewook/MCPTrace.git
cd MCPTrace
python -m venv .venv
为你的 shell 激活环境:
.\.venv\Scripts\Activate.ps1source .venv/bin/activate然后安装 MCPTrace:
python -m pip install .
在已激活虚拟环境的仓库根目录下运行以下示例。将镜像路径和 PID 替换为你的证据和目标进程。MCP 客户端和服务器可能运行在不同的进程中,因此请在相关情况下同时检查两者。
Windows
在运行 MCPTrace 之前,请先确认 Volatility 能够解析该镜像并枚举其进程。Windows 符号准备可能需要网络访问。
vol -f windows.raw windows.info.Info
vol -f windows.raw windows.pslist.PsList
mkdir output-windows
vol -p plugins -f windows.raw -o output-windows windows.mcptrace.MCPTrace --pid 4242 5252 --dump
Linux
将与该转储的精确内核构建匹配的 ISF 符号放入 symbols/linux/。
如果 linux.pslist.PsList 无法解析其内核或层要求,请在解读 MCPTrace 输出之前先解决
镜像/符号配置问题。
vol -s symbols -f linux.lime linux.pslist.PsList
mkdir output-linux
vol -p plugins -s symbols -f linux.lime -o output-linux linux.mcptrace.MCPTrace --pid 4242 --dump
--pid 可扫描所有进程,或传入多个 PID:--pid 4242 5252。--dump 会将每个进程的 JSONL 文件导出到由 -o 指定的目录。vol -p plugins windows.mcptrace.MCPTrace -h(或 Linux 上的等效命令)查看所有选项。如需以 JSON 形式呈现完整结果表,请将全局 -r json 选项放在插件名称之前。这与 --dump 生成的每进程 JSONL 导出是分开的。
vol -p plugins -f windows.raw -r json windows.mcptrace.MCPTrace --pid 4242 > findings.json
| 选项 | 用途 |
|---|---|
--pid 4242 5252 | 选择进程 ID;省略则检查适配器枚举的所有进程。 |
--dump | 使用全局 -o 目录,将显示的产物和扫描摘要导出为 JSONL。 |
--include-partial | 包含原始、未解析的片段,而不重建缺失字段。 |
--include-rpc | 同时显示未确认与 MCP 相关的通用 JSON-RPC 候选。 |
--policy PATH | 对工具参数应用本地规则;参见 Windows 和 Linux 示例。 |
--suspicious-only | 仅显示策略匹配项和摘要;需要非空策略。 |
--max-records N | 在过滤前限制每个进程的候选记录数;默认值:10000。 |
--max-object-bytes N | 限制单个完整 JSON 对象的大小;默认值:65536 字节。 |
--max-bytes N | 限制每个进程尝试的地址范围字节数;0 表示不限制。 |
策略发现描述的是与分析师提供的规则相匹配的结果。匹配并不代表存在恶意活动。在将示例路径、主机和工具名称应用于其他案例之前,请先审查它们。
诸如 mcptrace.pid-4242.jsonl 的文件包含一条元数据记录、若干产物记录以及最终的扫描摘要。元数据标识进程、目标操作系统和地址空间。产物记录同时保留解析后的消息和精确恢复的字节。
| 字段 | 含义 |
|---|---|
pid、virtual_address、region_start | 证据所属的进程和位置。地址是进程虚拟地址,而非映像文件偏移。 |
message、method、tool、request_id | 解析后的消息内容及选定字段(如可用)。 |
raw_base64、byte_length、raw_sha256 | 原始字节、其长度以及用于验证的 SHA-256。 |
state、encoding | 记录是完整的还是片段,以及其字节的编码方式。 |
relation、candidate_virtual_addresses | 候选对应位置以及该关系是否模糊。 |
findings | 可选的参数策略检查结果。 |
要验证某个产物,请解码 raw_base64,检查其长度和哈希,并通过相应的进程内存层重新读取该范围。将 message 重新格式化为 JSON 可能会改变空白或转义,因此请使用保留的字节进行精确比较。不同的内存副本仍作为独立的证据记录。
请结合产物一起阅读扫描摘要。它报告已扫描区域、可读和不可读字节、无效区域、跳过的进程、错误以及限制事件。不可读字节可能包含未使用的保留地址空间。没有消息的结果并不能证明 MCP 活动从未发生。
该基准测试使用了 三个全新的 Windows Server 2022 虚拟机捕获。每个虚拟机通过 stdio 运行两对使用官方 Python MCP SDK 的客户端/服务器。在通过 WinPmem 获取物理 RAM 之前,已交换了实际流量;测试消息未被注入到生成的映像中。
每个条件完成了 64 次工具调用和 133 条逻辑消息,包括初始化、一条通知和工具发现。载荷包括 ASCII、韩文/表情符号、转义字符、空白以及一个 2 KiB 字符串。条件如下:
恢复计数合并了每次捕获中的客户端和服务器,并对逻辑消息去重。该表报告了三次捕获的均值和范围。
| 条件 | 消息 / 133:均值(范围) | 工具对 / 64:均值(范围) |
|---|---|---|
| 无保留帧列表 | 59.7 (55-66) | 18.3 (15-21) |
| 保留帧对照 | 133.0 (133-133) | 64.0 (64-64) |
无保留帧的运行分别恢复了 66、58 和 55 条消息,其中包含 21、19 和 15 个完整的工具请求/响应对。跨捕获汇总后,即 179/399 条消息和 55/192 个对。保留对照组在每次捕获中均恢复了 133 条消息和 64 个对。在两个端点中都发现的配对,不一定完整存在于单个进程内。
三次捕获中有两次达到了候选搜索上限,分别报告了 4 次和 3 次回溯上限事件。这些运行被明确标记为 completed_with_limits,并仍保留在表中。这些事件并非唯一缺失消息的计数。在最终三次捕获中,未观察到进程读取错误、跳过的目标或记录/字节预算限制。
每张镜像均被分析三次,共对四个选定的端点进程进行了九次 CLI 扫描。运行时间中位数为 53.95 秒,均值为 53.94 秒,范围为 53.32-54.48 秒。运行器报告了 4 个逻辑 CPU 和约 16 GiB 内存。
计时包括 CLI 启动、Volatility automagic、进程扫描、JSON 渲染和 JSONL 导出。不包括采集、初始符号准备和单独的字节验证。镜像在扫描前已完成哈希计算和检查,因此这些并非冷缓存或全进程/全镜像吞吐量测量。
全部 1,339 条导出记录 / 562,402 字节均通过了对其字节、哈希、虚拟地址和 VAD 边界的原生进程层检查。重复扫描产生了字节完全相同的 JSONL,镜像哈希保持不变,临时 RAM 镜像在分析后被删除。在 2,480 条可评估的有向候选链接中未观察到错误链接;该计数包括内存副本之间的链接。
三个故意未发送的对照组也被恢复。这揭示了一个重要的解释局限:一个 MCP 形状的对象可以存在于内存中而从未被传输。在评估证据时,必须考虑日志、缓存值和示例。
两种条件都包含会改变内存的日志记录,而保留帧是有利的对照组。这些结果描述的是一个小型 SDK 测试夹具,并非一般性的召回率、精确率或攻击检测性能。该工作负载与早先的 8 次调用正向验证不同,因此两个结果并非受控的前后对比。完整测量数据、各捕获统计信息和复现说明见基准报告和机器可读结果。
基准测试暴露了一个过早的限值计数器递增问题:一个包含 133 条有效 SDK 消息的本地流被完全恢复,却产生了 228 次候选限值事件。现在,计数器仅在排除较旧候选后、有界回溯失败时才递增。搜索边界本身未改变,真实的限值事件仍在输出中可见。最初的失败尝试和修正记录在基准报告中。
所测量的实现通过了 135 项自动化测试、Ruff 检查,以及在 Windows 和 Ubuntu 上使用 Python 3.10 和 3.12 的 CI。测试涵盖解析、精确字节保留、内存间隙、类型化 ID 关联、平台适配器、导出和基准报告。
在计数器修正后,还重新扫描了一个现有的公开 Linux MCP 样本。两个 JSONL 导出保持字节完全相同,并保留了全部 41 个工件。该样本使用推断的物理内存布局,因为其 VMware 元数据不可用;这是一个有条件的验证结果,而非 Linux 恢复率基准。详情记录在 Linux RAM 验证报告中。
MCPTrace 目前仅提取明文 UTF-8/UTF-16LE JSON-RPC 工件。它不会重组 Python/V8 堆对象、解密应用程序数据、恢复已换出的内容,或推断转储中缺失的字节。字面版本标记和有界对象/搜索大小也意味着某些有效表示可能被遗漏。
分析仅限于 Volatility 所选 pslist 和进程内存层所暴露的进程和映射。隐藏进程、这些映射之外的证据以及不可读页面需要其他分析方法。目前不支持 ARM 和 32 位目标。
受控基准测试涵盖 Windows Server 2022、一个 Python SDK 版本和 stdio 流量。它不能证明在 Windows 11、Claude Desktop 或其他客户端、不同传输方式,或在额外内存压力下延迟收集时具有相同的恢复行为。仅凭完整 JSON 和候选 ID 匹配并不能证明传输、工具执行、会话成员身份或入侵。