搜索全站

输入至少 2 个字符,查找相关内容。

↑↓ 选择 Enter 打开Esc 关闭

ShimCache 与 Amcache

Prefetch 有一个致命弱点:它是可选的。被显式关闭、被清理、或只记录路径哈希,都会让执行证据链断掉。

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

一、概述

Prefetch 有一个致命弱点:它是可选的。被显式关闭、被清理、或只记录路径哈希,都会让执行证据链断掉。

Windows 还提供了两个不依赖功能开关的执行相关工件:

工件 位置 记录什么 独立性
ShimCache(AppCompatCache) SYSTEM hive 的注册表值 程序被启动过的路径与时间 系统必开,普通设置无法关闭
Amcache %SystemRoot%\AppCompat\Programs\Amcache.hve 程序的路径、SHA-1、PE 编译时间、首次执行时间 Windows 8+ 默认开启

三者形成三角验证:Prefetch 给次数与精确时间、ShimCache 给「系统看到过它启动」、Amcache 给「文件身份与首次运行时刻」。任何一个单独用都有缺口,交叉才能收敛。

这两个工件各有一个极易导致错误结论的陷阱:

  • ShimCache 的时间戳不是执行时间——它是目标 exe 的文件修改时间。
  • ShimCache 在硬断电时会丢失尚未落盘的条目——它常驻内存,正常关机/重启时才写入 hive。

它与 Prefetch 深度解析 并列,属于分析环节的执行侧证据,但独特价值在现场状态这个维度:

  • 上游依赖 注册表 hive 的正确提取。离线注册表必须用 ControlSet001(而不是 CurrentControlSet),这是本领域最高频的坑,方法见注册表取证;Amcache 则是独立文件,接入方式见只读挂载与安全接入。
  • 它自己要先判断现场状态。系统运行中 / 正常关机 / 硬断电,三种状态下 ShimCache 的可用性完全不同,这个判断必须在分析之前做完。
  • 下游支撑 两处。Amcache 的 SHA-1 是文件身份的锚点,可用于判断「这个可执行文件是否被替换过」;内存里的 ShimCache 覆盖了磁盘版的缺口,从内存读取的方法见 3.3。

落到具体形态上:

形态 位置 关键结构
ShimCache HKLM\SYSTEM\ControlSet001\Control\Session Manager\AppCompatCache\AppCompatCache REG_BINARY 形式的注册表值,不是独立文件;条目有序排列,有容量上限,满了之后新条目挤掉最旧的
路径历史 Windows 2000/XP/2003 为 ...\Session Manager\AppCompatCache(无内层子键),Vista 及以后多一层 用错版本路径是常见的「读不到」原因
格式版本 Win7 及以前旧格式有 0x01 Executed 标志位,可区分「枚举过」与「执行过」 Win8 起该标志位被移除,改为 AVL 树式新结构,所有条目格式上等价
Amcache C:\Windows\AppCompat\Programs\Amcache.hve 完整路径、SHA-1(只覆盖前 30 MB)、PE 编译时间戳、首次执行时间、文件大小
内存中的 ShimCache 活系统或内存镜像 数据主要常驻内存,会话注销与正常关机时才落盘

三个判定要点:ShimCache 与功能开关无关、Win8 起无法区分「枚举过」与「执行过」、Amcache 的 SHA-1 只覆盖前 30 MB。

据此能回答的是:系统是否尝试启动过某个路径的程序(不受 Prefetch 开关影响)、某个可执行文件的 SHA-1 与 PE 自称的编译时间、以及它在系统上的首次执行时刻。

回答不了的是这些,外加两个必须写进报告的结论:

  • ShimCache 的时间戳是目标 exe 的 $STANDARD_INFORMATION 最后修改时间,不是执行时间。 系统登记条目时读的是文件信息(为判断版本与兼容性),顺手把文件修改时间记了下来。它不记录「你什么时候点了这个 exe」——兼容性缓存不需要这个信息。把文件修改时间当执行时间,是本领域最常见的技术性错误。
  • 硬断电机器上磁盘 ShimCache 的「缺失」是技术必然,不是证据。 数据常驻内存,硬断电(拔电源、崩溃、长按电源键)会使尚未落盘的更新丢失,磁盘上的 ShimCache 停留在上一次成功写入时。写成「未发现相关程序执行痕迹」是错误表述,正确写法是「因系统异常断电,该时段执行痕迹未落盘,无法据此判断」。
  • Win8/10/11 上不能证明执行成功。 旧格式的 0x01 Executed 标志位已被移除,所有条目在格式上等价,只能证明「系统尝试启动过该路径的程序」。
  • 完整的文件哈希。 Amcache 的 SHA-1 只覆盖前 30 MB(为性能做的设计),比对时必须标注范围,不能当作完整文件哈希。
  • 文件的真实编译时间。 PE 编译时间戳可被伪造,只作「程序自称的编译时间」。
  • 执行次数。 ShimCache 与 Amcache 都不记次数,次数只有 Prefetch 的 Run Count 可靠。

读到这里你应该已经理解:NTFS 的 $STANDARD_INFORMATION 四个时间戳语义,否则无法理解 ShimCache 时间戳的真实含义,见NTFS 结构与 MFT 解析;注册表 hive 的离线提取方法,特别是 ControlSet001 的选择,见注册表取证;Prefetch 深度解析的结论,后面的可信度对比表需要拿它作对照;Windows 的关机语义与内存落盘机制,这是判断现场状态的前提;以及内存取证的基本概念(从内存读注册表键值),见内存取证总览。

二、核心原理

2.1 ShimCache 是什么、为什么必然存在

Windows 需要知道「这台机器上曾跑过哪些程序」来解决应用程序兼容性问题:老程序在新系统上跑不起来时,系统需要找到可能让它跑起来的垫片(shim)。

为加速这个查找,系统维护一个有序的路径缓存,这就是 ShimCache。

关键特性:

  • 与功能开关无关。删掉注册表值后,重启时系统会重新建表。
  • 有容量上限,满了之后新条目会挤掉最旧的。
  • 以 REG_BINARY 形式存放在注册表里,不是独立文件。

注册表位置(离线必须用 ControlSet001):

HKLM\SYSTEM\ControlSet001\Control\Session Manager\AppCompatCache\AppCompatCache

路径历史:Windows 2000 / XP / 2003 是 ...\Session Manager\AppCompatCache(无 AppCompatCache 子键层);Vista 及以后多了一层。用错版本路径是常见的「读不到」原因。

格式随版本变化:Windows 7 及以前的旧格式条目中有 0x01 Executed 标志位,可区分「文件被枚举过」与「文件被执行过」;Windows 8 起该标志位被移除,改为 AVL 树式新结构,所有条目在格式上等价。因此在 Win8/10/11 上,ShimCache 只能证明「系统尝试启动过该路径的程序」,不能证明执行成功。

2.2 ★ 陷阱一:时间戳不是执行时间

这是本篇最重要的技术纠正。

大量二手资料把 ShimCache 的时间戳描述为「执行时间」,这是错的。

ShimCache 条目中记录的时间,语义是:

目标 exe 文件本身的 $STANDARD_INFORMATION 最后修改时间(NTFS MFT 记录里的「修改时间」)

系统登记条目时读的是文件信息(为判断版本与兼容性),顺手把文件修改时间记了下来。

它不记录「你什么时候点了这个 exe」——兼容性缓存不需要这个信息。

这带来一个非常危险的后果:

对 exe 执行 timestomp(把文件修改时间改为 2019-01-01)
    ↓ ShimCache 中对应条目的时间也变成 2019-01-01
    ↓ 分析师看到 ShimCache 说「2019 年运行过 notepad.exe」→ 错误结论
ShimCache 时间显示 真实含义 不能推断
2019-03-11 02:14:55 那个 exe 文件的修改时间是 2019-03-11 不能推断「2019 年运行过它」
2024-11-10 08:22:41 该 exe 在 2024-11-10 被修改/编译 不能推断「当天运行过它」
无时间 条目存在,但文件已删或时间不可解析 不能推断「从未运行过」

报告表述模板:

  • 错误:「ShimCache 显示 malware.exe 于 2019-03-11 被执行过。」
  • 正确:「ShimCache 中存在 C:\...\malware.exe 的条目,表示系统曾尝试启动过该路径下的程序。条目时间 2019-03-11 02:14:55 是该文件的最后修改时间(经 MFT 记录核对一致),不构成执行时间证据。」

真正执行时间的正确来源:

需求 正确来源
程序执行时间 Prefetch、事件日志 4688、Sysmon 事件 1
文件访问时间 $STANDARD_INFORMATION 的 Access(易被关闭或延迟更新)
文件修改时间 MFT $STANDARD_INFORMATION(ShimCache 里就是这个)

2.3 ★ 陷阱二:硬断电可能丢失尚未落盘的条目

这是本篇最重要的实战提醒。

程序启动 → 兼容性服务把路径加入【内存中的 ShimCache】
                                  ↓ 内存中持续更新
        【会话注销 / 系统正常关机重启】→ 写入 SYSTEM hive(磁盘)
  • 数据主要常驻内存,在会话注销与系统正常关机/重启时写入 SYSTEM hive 的 AppCompatCache 值。
  • 硬断电(拔电源、崩溃、长按电源键)会使尚未落盘的更新丢失,磁盘上的 ShimCache 停留在上一次成功写入时的状态(具体粒度随 Windows 版本与内存压力而异,无法精确到「丢失最后几条」)。
最后正常关机:2024-11-14 23:40;案发:2024-11-15 01:07(USB 接入并运行程序)
→ 磁盘 ShimCache 很可能没有 01:07 之后运行的程序条目
→ 这不是「没执行」,而是「证据未落盘」
现场状态 处置
系统运行中 先做内存采集再关机,用内存插件读 ShimCache
正常关机 磁盘 ShimCache 基本完整,可直接用
硬断电/崩溃 磁盘 ShimCache 只反映上次成功写入的状态,必须记录此局限

要反复强调的一句话:遇到硬断电的机器,磁盘 ShimCache 的「缺失」是技术必然,不是证据。 写成「未发现相关程序执行痕迹」是错误表述;正确写法是「因系统异常断电,该时段执行痕迹未落盘,无法据此判断」。

2.4 Amcache:另一个独立工件

Amcache(Application Compatibility Cache)是 Windows 8 引入的独立注册表 hive,位于 C:\Windows\AppCompat\Programs\Amcache.hve,记录程序的完整路径、SHA-1 哈希、PE 编译时间戳、首次执行时间与文件大小。

两条重要限制:SHA-1 只覆盖文件前 30 MB(为性能做的设计),比对时必须标注范围,不能当作完整文件哈希;PE 编译时间可被伪造,只作「程序自称的编译时间」。

独立性价值:即使 Prefetch 被关闭、即使 ShimCache 因断电丢失,Amcache 作为独立文件仍可用。

局限是只记录首次执行时间,文件从未运行过则不在其中。

2.5 三者的可信度对比

维度 Prefetch ShimCache Amcache
记录「执行尝试」 是 是 是(首次)
记录「执行次数」 是(Run Count) 否 否
记录「精确执行时间」 是(8 槽内) 否(是文件修改时间) 仅首次
记录「完整路径」 是 是 是
记录「文件哈希」 否 否 SHA-1(前 30MB)
记录「PE 编译时间」 否 否 是(可伪造)
可被功能开关关闭 是 否 否
硬断电丢失未落盘条目 否(运行时写盘) 可能 部分
独立文件 否 否(在 SYSTEM hive 内) 是

推荐组合策略:先查 EnablePrefetcher 确认 Prefetch 是否可用;再查 ShutdownTime 判断是否异常关机(正常则 ShimCache 可用,异常则需内存采集或记录局限)。

无论前两步如何,Amcache 作为独立文件均可用于建立路径与哈希基线;最后三者加事件日志与 LNK 交叉验证形成结论。

三、操作步骤

3.1 提取并解析

mkdir -p /evidence/hives
# SYSTEM hive 与 Amcache.hve(Win8+;Win7 用 RecentFileCache.bcf)
for h in SYSTEM Amcache.hve; do
  fls -o 2048 -r -p /work/DigiForensics.dd | grep -iE "config/SYSTEM$|AppCompat/Programs/$h$" \
    | grep -E '^r/r' | awk '{print $2}' | head -1 \
    | while read -r ino; do icat -o 2048 /work/DigiForensics.dd "$ino" > "/evidence/hives/$h"; done
  printf '%s: ' "$h"; xxd -l 4 -p "/evidence/hives/$h"      # 期望 72656766(regf)
done

# 确认控制集编号(离线必做)
rip.exe -p /evidence/hives/SYSTEM -a /tmp/select.txt select
# \Select\Current : 1     → 路径写 ControlSet001
# 解析 ShimCache:自动识别 2000~11 各种格式,版本判断交给工具
AppCompatCacheParser.exe -f C:\evidence\hives\SYSTEM --csv C:\evidence\out
# → Path / ModifiedTime / InsertedTime / Executed(仅 Win7 有 Executed)
AmcacheParser.exe -f C:\evidence\hives\Amcache.hve --csv C:\evidence\out
# → Path / SHA1 / Compile Time / First Run Time / File Size
工具 输入 输出 适用
RegRipper appcompatcache SYSTEM hive 文本/十六进制 快速查看,二进制需另解析
AppCompatCacheParser SYSTEM hive CSV(自动识别版本) 首选
Volatility 3 内存镜像 CSV/TXT 运行中 / 断电前机器

3.2 核对时间戳语义(必做)

拿到 ShimCache 条目后,必须核对它的时间到底是什么:

# 从 ShimCache CSV 中挑一个可疑路径
grep -i 'suspicious' /evidence/out/AppCompatCacheParser_*.csv
# → Path: C:\Users\admin\AppData\Local\Temp\suspicious.exe
#   ModifiedTime: 2019-03-11 02:14:55

# 拿这个时间与文件的 MFT 时间戳对照
fls -o 2048 -r -p /work/DigiForensics.dd | grep -i 'suspicious.exe'
istat -o 2048 /work/DigiForensics.dd <inode>
# Modified: 2019-03-11 02:14:55     ← 与 ShimCache 一致
# Created : 2024-11-10 08:22:41
# Accessed: 2024-11-14 21:30:44
对照结果 结论
ShimCache 时间 = MFT Modified 证实是文件修改时间,不是执行时间
ShimCache 时间 ≠ MFT Modified 文件可能已被 timestomp,或时间字段解析有误,需进一步核实
文件已删除,无法对照 用 Amcache 的 Compile Time 互证;或从 VSS/备份找旧版本

这个核对只需做一次。一旦确认「ShimCache 时间 = MFT Modified」,后续所有条目都按这个语义解读。

3.3 从内存读取 ShimCache

机器运行中时磁盘 ShimCache 可能未落盘,硬断电时未落盘部分已丢失;运行中可从内存读当前会话条目。

Volatility 3 插件:windows.shimcachemem.ShimcacheMem,从对应版本的内存结构中读取。

vol -f /evidence/DigiForensics-mem.raw windows.shimcachemem.ShimcacheMem
vol -f /evidence/DigiForensics-mem.raw windows.info      # 先确认内核符号可用
vol -f /evidence/DigiForensics-mem.raw windows.amcache.Amcache
情形 该怎么做
系统运行中 先做内存采集,再用本节命令
系统硬断电 内存已丢,未落盘部分无法恢复,必须记录局限
系统正常关机 用 3.1 的磁盘路线即可

3.4 三者交叉验证