一、概述
EFS(Encrypting File System,透明加密文件系统)是 Windows Professional 及以上版本提供的文件级加密功能。
它工作在文件系统层,加密的是 NTFS 备用数据流 $EFS。文件本身还是那个能被正常读取的 NTFS 文件,只是内容被换成了密文。
这带来一个反直觉但极其有用的特性:
EFS 加密文件的所有者证书如果能在镜像中找到,文件即可被直接解密——不需要口令,不需要暴力破解。
这也是 EFS 和全卷加密最大的取证差异。
全卷加密的密钥受 TPM 与保护器双重保护,而 EFS 的私钥受 DPAPI 保护——而 DPAPI 保护的是"用户凭据",不是文件内容本身。 只要用户的 profile 还在、私钥文件还在,DPAPI 这一层就成了纸糊的。
这个差异决定了两类案件的处置方向截然不同:
| 场景 |
全卷加密(BitLocker) |
EFS |
| 密钥的封装 |
TPM 密封 / 恢复密码 / 启动密钥 |
用户证书私钥,在用户 profile 里 |
| 取证方向 |
全盘关键字搜索恢复密码 |
直接找 RSA 目录下的私钥文件 |
| 典型失败原因 |
用户把恢复密码存到域控、纸质归档或企业集中存储里 |
用户 profile 被删除、重装系统后私钥丢失 |
| "彻底不可恢复"的含义 |
罕见——设计上有恢复通道 |
常见——私钥没了就是数学上不可恢复 |
EFS 的取证价值恰恰落在那个"常见"上。私钥一丢,文件就真的没了。
所以**"私钥在不在"这个问题必须尽早、明确地回答**,不能拖到"所有方法都试过了"再下结论。
本篇处理的证据形态:
| 证据 |
位置 |
判据 / 说明 |
$EFS 属性流 |
NTFS 备用数据流,文件级 |
文件头带 EFS 特定 header |
| 用户私钥 |
%APPDATA%\Microsoft\Crypto\RSA\<SID>\,扩展名通常为 .pfx 或无扩展名 |
最主要的取证目标,DPAPI 保护但明文存在于镜像中 |
| DPAPI master key |
%APPDATA%\Microsoft\Protect\<SID>\<GUID>\ |
用户口令派生密钥保护它,口令已知即可解开 |
| 机器级 / 系统级私钥 |
C:\ProgramData\Microsoft\Crypto\RSA\<SID>\、C:\Windows\System32\Microsoft\Crypto\RSA\<SID>\ |
不能与用户级混淆 |
| 证书注册表痕迹 |
HKLM\SOFTWARE\Microsoft\SystemCertificates\Filesystem\Certificates\<指纹>\(用户级在 HKCU) |
值 EncryptedFileName 标识 EFS 证书;即使私钥已删,这一条仍可能存在 |
| XP 时代路径 |
C:\Documents and Settings\<用户>\Application Data\Microsoft\Crypto\RSA\<SID>\ |
跨版本取证必须覆盖 |
注册表痕迹这条要单独强调:它是"该用户曾使用 EFS"这个事实的独立证明。
私钥文件即使被删光,只要注册表条目还在,你依然可以写"该用户曾创建 EFS 证书"。
反过来不行。不能因为私钥不在就写"该用户未使用 EFS"。
EFS 的处置主链是四步,顺序本身就是方法论:
| 步骤 |
动作 |
产出 |
什么时候就该停 |
| 3.1 |
确认 EFS 使用痕迹 |
$EFS 流存在性 + 注册表证书条目 |
两条线索都无 → 写"未发现 EFS 使用痕迹"并列出扫描范围 |
| 3.2 |
提取 EFS 私钥 |
私钥文件路径 + 所属用户 |
用户 profile 不在 → 不要假设文件被删,先查未分配空间 |
| 3.3 |
导入证书后解密文件 |
明文内容 + 实际打开验证 |
只导入公钥无效 → 不要把"导入了"当成"能解密" |
| 3.4 |
私钥缺失时的替代路径 |
内存 / 爆破 / 备份 / 他人证书 |
全部走完仍无 → 转"不可恢复"的限定表述 |
第 3.3 步有一个非常常见的失败点值得提前知道:从证书管理器导出的 .pfx 默认包含私钥,而只导出 .cer(不带私钥)时导入成功、文件仍然打不开。
"证书导入成功"与"文件能解密"是两件事,验证必须落到"实际用该证书读出内容"。
在取证流程中的位置:本篇属于分析环节,通常在全卷加密解开之后才轮到它(加密卷里的用户 profile 本身也在加密层之下)。上游依赖是镜像制作与用户 profile 的提取;理解 $EFS 流的存在与读取方式,需要NTFS 数据流与隐藏数据——这篇是本篇的硬前置;HKCU 侧的 hive 提取见注册表取证。
下游支撑是解密后的文件内容分析,通常交给文件头与文件签名判断类型、以及时间线重建纳入时间证据。
DPAPI 机制本身的通用理解见浏览器密码库与 Token 解密——同一套 DPAPI 主密钥解开后,浏览器密码库会同时打开。
该用户是否使用过 EFS、私钥文件是否存在及位于何处、DPAPI 能否解开(有用户口令时)、哪些文件被 EFS 加密、注册表里有哪些证书条目、能否实际解密并读出明文。
私钥不存在且用户口令不可得时,EFS 加密内容在数学上不可恢复——这不是能力问题,是"内容密钥只被那个私钥解得开"的设计后果。
本篇也不能回答**"用户是不是故意加密的"(EFS 是系统特性,默认开启,用户自己往往并不知道)、"这些文件在被加密前的内容是什么"**(密文不保留原文痕迹),以及非 Professional 版本机器上的 EFS 痕迹含义(Home 版无此功能,痕迹值得单独核实)。
读者前提:你需要先掌握 NTFS 备用数据流的读取(NTFS 数据流与隐藏数据)、注册表 hive 的离线提取与查询(注册表取证)、以及 X.509 证书的基本概念(.pfx 何时含私钥、何时只有公钥,这个区分决定了 3.3 步能否成功)。
工作纪律方面,只读挂载与安全接入是前提——证书导入操作会改变取证工作站的证书库,不是原始检材,但必须与检材副本分离。
涉及用户口令的分支见通用密码恢复的授权与最小化要求。
二、核心原理
2.1 双钥体系
EFS 是非对称加密 + 对称加密混合方案。文件用 AES 加密,FEK 又被 RSA 私钥包着:
文件内容 ──AES──→ 密文(存入 $EFS 流)
↑
FEK(文件加密密钥)
↑
用户证书的 RSA 私钥解密
- 文件加密密钥(FEK):每个文件一把,随机生成,用于 AES 加密文件内容
- FEK 的存储:被加密后存入 NTFS 的备用数据流
$EFS,用证书的公钥加密
- 解密过程:用证书的私钥解出 FEK,再用 FEK 解密文件内容
取证意义:只要拿到私钥,所有属于该用户证书加密的文件都能解。
这也解释了 EFS 的经典陷阱——重装系统后文件永久丢失,因为私钥在旧系统的用户配置中。
2.2 私钥存放位置
用户的 EFS 私钥存在 DPAPI 保护下的用户凭据存储里:
| 位置 |
说明 |
%APPDATA%\Microsoft\Crypto\RSA\<SID>\ |
用户级私钥(最主要的取证目标) |
C:\Documents and Settings\<用户>\Application Data\Microsoft\Crypto\RSA\<SID>\ |
XP 时代路径 |
C:\ProgramData\Microsoft\Crypto\RSA\<SID>\ |
机器级证书 |
C:\Windows\System32\Microsoft\Crypto\RSA\<SID>\ |
系统证书 |
关键取证价值:若用户 profile 未被删除,这些私钥文件(扩展名通常为 .pfx 或无扩展名)明文存在于镜像中,只是被 DPAPI 加密。
DPAPI 的保护来自"用户的登录密码派生密钥"——若已知用户密码,DPAPI 即可解开。
2.3 DPAPI 的破解前提
DPAPI(Data Protection API)的解密逻辑:
DPAPI master key(%APPDATA%\Microsoft\Protect\<SID>\<GUID>\)
↓ SHA-256
用户密码 + salt
↓ PBKDF2 / NTLM
会话密钥
↓ 解密 DPAPI master key
master key 明文
↓
AES-256-CBC 解密 $EFS 流
FEK 明文
↓ AES
文件内容明文
攻击面说白了就三条:
- 用户密码已知 → 直接用
mimikatz / dpapi.py / impacket 全部解开
- 密码未知 → 离线爆破(DPAPI 支持离线爆破,是真实可行的攻击面)
- memory dump 已知 → 从内存中直接读取会话密钥
2.4 证书的注册表痕迹
不管私钥在不在,注册表里通常留有证书元信息:
HKLM\SOFTWARE\Microsoft\SystemCertificates\Filesystem\Certificates\
<证书指纹>\
EncryptedFileName ← EFS 加密的标识值
FriendlyName
CertHash
用户级证书则在:
HKCU\SOFTWARE\Microsoft\SystemCertificates\Filesystem\Certificates\
取证价值:EncryptedFileName 是 Windows 内部用于标识 EFS 证书的注册表值。
即使私钥文件已删除,注册表中的证书条目仍可能存在,可用于证明"该用户曾使用 EFS"这一事实。
三、操作步骤
3.1 确认 EFS 使用痕迹
# 1) 搜索 EFS 特有属性流标记
# EFS 加密文件的 $EFS 流以特定 header 开头
strings -n 20 DigiForensics.dd | grep -i "EncryptedFileName"
# 2) 检查是否存在 EFS 证书注册表项
# 在导出的 hive 中查
grep -aob "Filesystem\\\\Certificates" DigiForensics.dd
X-Ways / FTK Imager 里可以挂自定义关键字:
$EFS ; NTFS 备用数据流名
EncryptedFileName ; 注册表值名
3.2 提取 EFS 私钥(首选)
# 1) 从镜像中提取 RSA 目录(需先切出用户 profile)
# 路径:/Users/<用户名>/AppData/Roaming/Microsoft/Crypto/RSA/<SID>/
# 2) 用已知用户密码解密 DPAPI 保护的私钥
# 工具:impacket 的 dpapi.py
python3 dpapi.py -u domain/user -p password -k rsa.key -c CryptoKeys/*.pfx
# Windows 上用 mimikatz(目标机器或取证工作站)
# 提取当前用户的 DPAPI master key
mimikatz # lsadump::masterkeys /list
# 列出所有 EFS 证书
certutil -store my
3.3 导入证书后解密文件
EFS 取证最实用的就是这一条:
# 1) 导出 EFS 证书(含私钥)为 .cer / .pfx
# 在原系统(或已导入证书的取证机)上:
certmgr.msc # 个人 → 受信任的根证书颁发机构 / 个人 → 选择证书
# 右键 → 所有任务 → 导出 → 选择"是"导出私钥 → 后缀 .pfx
# 2) 在取证工作站上导入证书(含私钥)
certutil -user -importpfx "Exported.cer" # 提示输入密码(导出时设置的)
# 或双击 .pfx → 安装证书 → 当前用户
# 3) 访问 EFS 加密文件
type D:\ est.txt # 若证书正确,直接显示明文
⚠️ 关键点:导入的证书必须包含私钥。
只导入公钥部分无效——EFS 解密需要私钥解出 FEK。
3.4 无私钥时的替代方案
私钥文件丢了或者被覆盖了,能走的路就这些:
| 方案 |
说明 |
| 从内存提取 DPAPI 会话密钥 |
若有内存镜像,DPAPI 会话密钥以明文驻留在 LSASS 进程内存中 |
| DPAPI 离线爆破 |
DPAPI 支持离线爆破,工具:dpapi.py 的 --brute、hashcat mode 22100 |
| 备份恢复 |
从系统还原点、Windows.old、卷影副本中找回旧私钥 |
| 其他设备/用户证书 |
若文件被多用户共享,其他用户的证书可能也能解密 |
| 接受不可恢复 |
严格意义上,若私钥不存在且密码不可得,EFS 加密内容在数学上不可恢复 |
四、常见陷阱
4.1 认证与识别误判
误判「EFS 密钥丢失 = 无法取证」
现象:目标机器上找不到当前用户的私钥,报告写"EFS 私钥已丢失,相关文件无法解密"。
原因:EFS 私钥受 DPAPI 保护,而 DPAPI master key 是按用户 SID 分散存放的,系统本身还会复制它。密钥可能躺在别的用户 profile 里、被删账户留下的孤儿 keyfile 里、卷影副本里、系统完整备份里,甚至早就被导出成 .pfx 存到 U 盘或邮件附件上了。
只搜一个 profile 找不到,不等于不存在。
**影