搜索全站

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

↑↓ 选择 Enter 打开Esc 关闭

用户行为痕迹

Prefetch 回答「程序有没有跑过」。用户行为痕迹回答另一件事——人在干什么。

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

一、概述

Prefetch 回答「程序有没有跑过」。用户行为痕迹回答另一件事——人在干什么。

这类痕迹散落在注册表的用户配置单元(NTUSER.DAT)里,一行记录对应一个真实动作:打开过某个应用、在地址栏敲过某个路径、挂载过某个盘、点进过某个目录。

密度高,误读率也高。UserAssist 的值经过 ROT13 编码,RunMRU 是二进制链表,Shellbags 记的是资源管理器的导航历史。不解码,拿到手的就是一堆字节。把编码后的字符串直接抄进报告,是这类工件最常见也最致命的错误。

局限同样硬。绝大多数条目只存在于该用户的 NTUSER.DAT,配置文件被删除就全部消失;部分键有固定条目上限(UserAssist 旧版本为 100),到顶后循环覆盖;它们只能证明「使用了某个入口」,证明不了操作成功,更证明不了恶意。

这一层位于分析环节的「归属与行为」,上游是执行证据——程序执行证据见Prefetch 深度解析,注册表解析方法见注册表取证。上游要的是用户 hive 提取与归属判定准不准。这些键值全在用户自己的 hive 里,系统账户 hive(SYSTEM)内没有这些内容——只有用户行为才有「用户」。分析系统账户会得到「该用户从未使用过任何程序」的错误结论,因为那些数据根本不在那里。

解析方式必须按版本决定。UserAssist 有两种取值布局(WinXP 16 字节、Win7+ 72 字节),混用会得出完全错误的次数;Shellbags 的结构按版本差异较大,把旧结构当新结构读会得到完全错位的路径。下游支撑行为画像:Shellbags 容量不固定、无硬上限,是长周期案件中少有的「用户活动档案」;MountPoints2 在外泄与溯源案件中价值极高。

全部痕迹位于 NTUSER.DAT 内:

痕迹 位置(Software\ 下) 记录内容 容量特性
UserAssist Microsoft\Windows\CurrentVersion\Explorer\UserAssist\{GUID}\Count 程序打开次数与最后使用时间 上限约 100 条,循环覆盖
RunMRU ...\Explorer\RunMRU 运行对话框中手工输入过的命令 上限约 59 项
TypedPaths ...\Explorer\TypedPaths 地址栏手工输入的路径 上限约 30 项
WordWheelQuery ...\Explorer\WordWheelQuery 「打开方式」列表中输入过的关键词 有上限
RecentDocs ...\Explorer\RecentDocs 最近打开文档的完整路径 按扩展名分子键
MountPoints2 ...\Explorer\MountPoints2 曾挂载过的卷、目录与 GUID 路径挂载 按卷标识分子键
Shellbags Microsoft\Windows\Shell\Bags 及 ...\Software\Classes\Local Settings\...\Shell\Bags 资源管理器导航历史与排序偏好 滚动保留,无硬上限

ROT13 编码的适用范围只有一个:值名(子键名)里的程序路径。

元素 是否 ROT13 说明
值名 / 子键名中的路径 是 P:\Windows\System32\pqnq.rkr → C:\Windows\System32\cmd.exe
Win7+ 的 Run Count 否 是二进制 DWORD,直接按小端读
Win10+ 时间戳子键名中的时间 否 是 FILETIME(16 字节),只对路径部分做 ROT13

据此能回答的是:某用户打开过哪些程序及其次数、输入过哪些路径、挂载过哪些卷或网络共享到哪个目录、浏览过哪些目录,以及某目录的文件已被删除时用户是否进过该目录(Shellbags 独有,5.2 就是靠它定位了目录访问)。

回答不了的部分,最容易踩坑的是前两种:

  • 把 Win7+ 的计数当成 ROT13 字符串去「解码」。 ROT13 只作用于字母,数字原样保留,所以把一个 DWORD 误读成 ROT13 字符串时,往往会得到一个看似合理却完全错误的次数。正确做法是先看值长度(16 / 72 字节)判定版本,再决定解析方式。
  • 拿时间来定位行为时刻。 时间证明力普遍弱于事件日志与 NTFS 时间戳。UserAssist 最后使用时间部分版本有、部分版本没有(缺失不等于没使用);TypedPaths / RunMRU 只有值没有独立时间戳,其注册表键的最后写入时间会被其他写入刷新,不精确。绝不能单独用于精确定位行为时刻,只能作为「某用户与某路径/程序发生过交互」的存在性证据。
  • 时间戳的类型搞混。 RecentDocs 与 Shellbags 里的时间是键的最后写入时间,反映用户活动,但不是「文件被访问」的时间。
  • 操作是否成功。 这些键值只证明「使用了某个入口」,证明不了操作完成。
  • 行为是否恶意。 中性的使用记录,定性需要行为证据与哈希查库。
  • 入口数量之外的完整历史。 UserAssist、RunMRU、TypedPaths 都有条目上限并循环覆盖,「最近 N 条」之外的部分不可知。
  • 已删除用户配置文件的痕迹。 用户配置文件被删除即全部消失,这类缺失必须限定结论范围。

往下读之前先确认你已经掌握注册表 hive 的提取与路径解析(尤其是用户 hive 的逐用户选取,见注册表取证)、ROT13 与 Base64 这类编码的本质(ROT13 只作用于字母,数字原样保留)、Windows 版本差异对键值结构的影响(UserAssist 与 Shellbags 的布局都随版本变化),并且会按值长度与实际取值验证布局假设,不要照搬任何一版布局。此外要掌握时间戳的纪元与 FILETIME 换算——Win10+ 的时间戳藏在子键名里——并理解**「存在性证据」与「时点证据」的区别**,这些工件只提供前者。

二、核心原理

2.1 工件矩阵与落点

痕迹 位置(NTUSER.DAT 内) 记录内容 容量特性
UserAssist Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist\{GUID}\Count 程序打开次数与最后使用时间 上限约 100 条,循环覆盖
RunMRU Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU 运行对话框中手工输入过的命令 上限约 59 项
TypedPaths Software\Microsoft\Windows\CurrentVersion\Explorer\TypedPaths 资源管理器地址栏手工输入的路径 上限约 30 项
WordWheelQuery Software\Microsoft\Windows\CurrentVersion\Explorer\WordWheelQuery 文件关联「打开方式」列表中输入过的关键词 有上限
RecentDocs Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs 最近打开文档的完整路径 按扩展名分子键
MountPoints2 Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2 曾挂载过的卷、目录与 GUID 路径挂载 按卷标识分子键
Shellbags / ShellBagMRU Software\Microsoft\Windows\Shell\Bags 及 Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\Bags 资源管理器窗口导航历史与排序偏好 滚动保留
BAM / UserAssist 扩展 Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist 子项 部分版本额外记录执行计数 视版本

全在用户自己的 hive 里。SYSTEM 装的是 ControlSet、服务、会话这类系统级信息,SOFTWARE 是 64 位与 32 位机器级配置,两边都没有用户行为。

查错 hive 得到的空结果,是「数据不在这里」而不是「没有行为」。

2.2 UserAssist 的编码与结构

UserAssist 有两种取值布局,必须按 Windows 版本区分。

混用会得出完全错误的次数。

Win7 / Win8.x(Windows 7 起,值长度 72 字节)

偏移 长度 内容
0 4 Session ID
4 4 Run Count(二进制小端 DWORD,不是字符串)
8 8 Focus Count(Win7/8 存在;Win8.1 起不再填充)
16 56 其余为保留填充(0);Win7 布局在此处不含时间字段

Win7 的 72 字节布局在偏移 16 之后是纯填充;部分 Win8 构建会在偏移 60 处放入最后使用时间 FILETIME。该字段位置随版本变化,必须用实际检材的长度与取值验证,不要照搬任何一版布局。

WinXP(值长度 16 字节)

偏移 长度 内容
0 4 Run Count(DWORD)
4 4 0
8 4 0x00000000
12 4 0x000000FF(版本标记)

最后使用时间的来源随版本变。Win10 / Win11 会另外在 UserAssist\<GUID>\Count 下追加带时间戳的子键(形如 \{GUID}\{timestamp}\{ROT13 路径}),时间在子键名里,不在值数据中。

Win8 及更早版本的值数据里通常不含最后使用时间。缺失不等于没使用过。

ROT13 编码的适用范围只有一个:值名(子键名)里的程序路径。

元素 是否 ROT13 说明
值名 / 子键名中的路径 是 P:\Windows\System32\pqnq.rkr → C:\Windows\System32\cmd.exe
Win7+ 的 Run Count 否 是二进制 DWORD,直接按小端读
Win10+ 时间戳子键名中的时间 否 是 FILETIME(16 字节),只对路径部分做 ROT13

最常见的错误:把 Win7+ 的计数当成 ROT13 字符串去「解码」。ROT13 只作用于字母,数字原样保留——所以把一个 DWORD 误读成 ROT13 字符串时,往往会得到一个看似合理却完全错误的次数。先看值长度(16 / 72 字节)判定版本,再决定解析方式。

2.3 Shellbags 的取证价值

Shellbags 记的是资源管理器窗口的导航序列:用户进过哪些目录、在每个目录里改过哪些排序与视图设置。

这让它能回答两个别处答不了的问题——

  • 用户在被调查时间窗内是否浏览过某个特定目录,哪怕该目录下的文件已被删除;
  • 目录的最后访问时间在注册表层面是否被更新过。

结构按版本差异较大:早期是 ShellBagMRU 下的树形节点,较新版本引入了独立的索引表与名称映射表。解析器必须显式区分版本,把旧结构当新结构读会得到完全错位的路径。

容量上它不固定,不像 UserAssist 那样有硬上限,是长周期案件里少有的「用户活动档案」。

2.4 MountPoints2 的卷与目录挂载痕迹

MountPoints2 的子键名是卷标识(Volume identifier)而非普通名字,键值是流式数据,其中可解析出:

  • 该卷曾被挂载到哪些目录(例如把某个网络共享挂载到 Z:\ 或某个本地目录);
  • 真实路径(网络路径、USB 标记等);
  • 磁盘卷标。

它在数据外泄与溯源案件中极有价值:记录「用户把哪台机器/哪个共享映射到了哪里」。

而且是用户主动操作才会产生的痕迹,不能由系统自动生成,证明力较强。

2.5 时间语义

时间语义三条,差别很大。

UserAssist 最后使用时间:部分版本有,部分版本没有。缺失不等于没使用。

RecentDocs 路径与 Shellbags:其中的时间字段是注册表键的最后写入时间,反映用户活动,但不是「文件被访问」的时间。

TypedPaths / RunMRU:只有值,没有独立时间戳。对应注册表键的最后写入时间可作参考,但会被其他写入刷新,不精确。

结论很直接:这些工件的时间证明力普遍弱于事件日志与 NTFS 时间戳。绝不能单独用于精确定位行为时刻,只能作为「某用户与某路径/程序发生过交互」的存在性证据。

三、操作步骤

3.1 提取用户 hive

mmls /work/DigiForensics.dd
fsstat -o 2048 /work/DigiForensics.dd

fls -o 2048 -r -p /work/DigiForensics.dd \
  | grep -Ei '/Users/[^/]+/(NTUSER\.DAT|UsrClass\.dat)$' | grep -E '^r/r' | awk '{print $2}' \
  | while read -r ino; do
      u=$(echo "$ino" | cut -d: -f2)
      icat -o 2048 /work/DigiForensics.dd "$ino" > "/evidence/registry/users/$u/$(basename "${ino%%:*}")"
    done

UsrClass.dat 承载了 HKCU\Software\Classes 的内容。旧版本中 Shellbags 的部分数据就在其中。

不能只提 NTUSER.DAT。

3.2 导出并解码 UserAssist

用注册表解析工具加载 hive 后,导出 UserAssist\{GUID}\Count 下的全部子键。

先按值长度定版本,再选解析路径:

值长度 = 72 字节  → Win7/8.x:Run Count = DWORD(偏移 4, 小端)
值长度 = 16 字节  → WinXP:DWORD(偏移 0, 小端)
子键名形如 \{GUID}\{FILETIME}\{ROT13路径}  → Win10+,取子键名中的 FILETIME 作为最后使用时间

无论哪种版本,值名中的路径都要做 ROT13 还原。

ROT13 只作用于字母,数字与符号原样通过。所以还原后的路径里出现数字和反斜杠是正常的,不是解码失败。

3.3 解析 TypedPaths 与 RunMRU

TypedPaths  值形如:
  "D:\Projects\2024\Q1"=  (0x03 0x00 ...)
RunMRU     结构为 MRU 链表:
  0x00 'm' 'r' 'u' + 计数 + 各条目 "(0x...)null 字符串 null"

RunMRU 不是普通值列表,是一个 MRU 链表。头部是 ASCII 的 mru 加计数,其后是若干 (0x...) 标记与 null 终止的路径字符串,按最近使用顺序排。

解析时跳过标记字节,只保留以 null 结尾的字符串。

3.4 导出 Shellbags

使用专门的 Shellbags 解析器导出,明确指定目标系统版本以启用正确的结构解析。导出结果应包含:导航路径、每条记录对应的窗口特征、该路径在检材中的时间戳。

分析时的实用筛选:

  • 只看时间窗内的记录(与案件时间窗比对);
  • 关注指向敏感目录的路径(如财务、研发、\财务\、客户资料目录);
  • 与 NTFS 目录 $STANDARD_INFORMATION 的访问时间互证。

3.5 交叉验证

用户行为痕迹必须与其他证据配合:

  • Prefetch:确认该程序确实执行。
  • LNK / Jump List:确认打开了哪个具体文件。
  • 事件日志 4624 / 4634:确认登录与注销区间,判断行为是否发生在有人值守时段。
  • NTFS $UsnJrnl:把「访问过某目录」收敛到具体的文件创建/修改操作。

四、常见陷阱

本章按解码与结构判读 → 容量与缺失解释 → 落点与版本差异 → 结论表述边界归组,每条给出:现象、为什么会误判、误判代价、正确做法。

★ 标记表示该操作会导致原始检材永久灭失或对检材造成不可逆改变,执行前必须停下来确认。

4.1 解码与结构判读

陷阱 1:忘记 ROT13,直接引用值名里的原始字符串

现象

UserAssist 导出结果里出现 P:\Windows\System32\pqnq.rkr、C:\Users\victim\AppData\Roaming\bhfgvn\pbagragf,报告照抄其中一条作为「该用户运行过的程序」。附件里放的是同一份乱码字符串。

原因

ROT13 编码的适用范围只有一个:值名(子键名)里的程序路径。 系统在写入 UserAssist 键名时对字母做了 ROT13 映射,数字、\、:、. 等符号原样保留。

所以 pqnq.rkr 还原后正是 cmd.exe——字母全部平移 13 位。而 E:\7-Zip\7zFM.rxE 里的数字与符号看着「没被处理」,恰恰说明编码只作用于字母,不是解码失败。

解析器(KAPE、regripper 插件、专门脚本)