ProcDump:受控触发、转储采集与证据退出
ProcDump 是转储采集器,不是 WinDbg 的一个命令
ProcDump 监视目标进程,并按异常、无响应、CPU、内存或人工条件写出 Windows Dump。它拥有独立可执行文件、EULA、触发状态、进程权限和退出动作;采集成功只能证明文件已经产生,不能证明符号匹配或根因成立。
工程接入的重点是限制触发次数、Dump 类型、目录配额、运行身份和保留期,并在结束时取消监控、撤销 AeDebug 注册、核销转储副本。分析阶段再把文件交给 WinDbg、CDB 或其他兼容调试器。
用 ProcDump 建立最小采集闭环
最安全的入门目标是同一普通用户启动的隔离测试进程。先创建受限实验目录,再按 PID 采集一个默认 Mini:
$Lab = Join-Path $env:TEMP 'windbg-procdump-lab'
$DumpDir = Join-Path $Lab 'dumps'
New-Item -ItemType Directory -Force $DumpDir | Out-Null
$TargetPid = <test-process-pid>
.\procdump.exe -accepteula -n 1 -mm $TargetPid $DumpDir
Get-ChildItem $DumpDir -Filter *.dmp |
Select-Object Name, Length, LastWriteTime预期证据不是“命令退出了”,而是目录中出现一个 dump、文件大小非零,并且工具报告目标 PID 与输出路径。安装了 Debugging Tools 后,再做结构完整性检查:
$Dump = Get-ChildItem $DumpDir -Filter *.dmp | Select-Object -First 1
dumpchk.exe $Dump.FullNameDumpChk 只能快速判断文件能否读取、基础结构是否合理;它不能证明关键内存已采集,也不能证明 PDB 正确。
按异常采集,而不是等人盯着窗口
-e 在 second-chance,也就是未处理异常时写 dump:
.\procdump.exe -accepteula -ma -n 1 -e your-service.exe $DumpDir-e 1 同时捕获 first-chance 与 second-chance 异常。first-chance 异常会先到调试器,应用随后可能自行处理;在异常频繁但可恢复的程序上,无过滤使用 -e 1 会快速制造大量 dump:
# 仅用于隔离实验:上限、过滤和目录容量必须同时存在
.\procdump.exe -ma -n 2 -e 1 -f '<known-exception-text>' `
your-test-app.exe $DumpDir这个反例应看到“应用处理了异常但仍产生 dump”。它证明 first-chance 是线索,不等于崩溃根因;上线前必须验证过滤文本的命中与不命中各一次,并设置 dump 个数、目录配额和停止条件。
CPU、内存、挂起与退出触发
ProcDump 的触发器必须和指标语义一起评审:
| 现场信号 | 参数示例 | 容易误判的地方 |
|---|---|---|
| CPU 持续过高 | -c <percent> -s <seconds> | 加 -u 才按单核口径解释阈值 |
| CPU 持续过低 | -cl <percent> -s <seconds> | 低 CPU 不能单独证明线程死锁 |
| 进程 commit 过高 | -m <MB> | 是 process memory commit,不是 working set 或 private bytes |
| GUI 挂起 | -h | 表示窗口至少 5 秒不响应消息;不适用于无窗口服务 |
| 进程退出 | -t | 适合抓退出现场,不解释退出原因 |
| 等待目标启动 | -w | 按名称等待时要防止选中同名错误实例 |
| 启动并监控 | -x <folder> <image> | ProcDump 成为父级启动入口,项目脚本要处理参数与工作目录 |
例如,采集两份相隔至少一个触发周期的 GUI 挂起 dump,可以比较线程栈是否稳定停在同一等待链:
.\procdump.exe -accepteula -h -n 2 -s 10 -mm `
your-test-app.exe $DumpDir-s 表示条件连续满足的秒数,-n 表示写多少个 dump 后退出。多时点相同栈比单张快照更能支持“持续等待”的判断,但仍要结合锁、等待对象和应用证据,不能由一个 WaitForSingleObject 帧直接宣布死锁。
clone 采集的 -r [1..5] 可降低某些采集路径的停顿,但高并发会消耗系统资源;-a 依赖 -r,会在预计产生长暂停时跳过触发,-at <seconds> 可取消超时采集。降低停顿不等于无停顿,跳过 dump 也必须进入告警与审计。
把采集能力接进项目,而不是接进每个人的记忆
项目仓库适合保存采集策略和脚本模板,不适合保存 dump、private PDB、符号缓存或真实进程参数。一个可评审的采集配置至少要把这些决策显式化:
schema: 1
target: your-service.exe
trigger:
kind: unhandled-exception
firstChance: false
dump:
type: mini
maxCount: 2
outputDirectory: "${DUMP_STAGING_DIR}"
guards:
requireApprovedIncident: true
minimumFreeSpaceBytes: "${DUMP_MIN_FREE_BYTES}"
maximumDirectoryBytes: "${DUMP_MAX_DIR_BYTES}"
retention:
classification: restricted-debug-evidence
owner: runtime-debugging-oncall
deleteAfterReview: true包装脚本应先解析目标 PID 与所有者,再检查输出目录 ACL、可用空间和现有证据总量,最后才启动 ProcDump。脚本退出码至少区分:未找到唯一目标、权限拒绝、容量不足、触发窗口结束但未产出、dump 写入失败、取消成功。不要把 procdump.exe 的整段命令散落在 Wiki、聊天和个人计划任务中。
构建流水线则需要独立发布符号证据包。推荐顺序是:
编译一次得到 EXE/DLL 与 PDB,不在发布后重新编译“同版本”符号。计算二进制和 PDB 摘要,提取 PDB GUID/age。把 private PDB 发布到受限符号仓库,把允许外发的 public/stripped PDB 发布到另一个层级。
生成构建清单,绑定源码提交、编译配置、制品摘要和符号身份。用一个发布制品产生受控 dump,在干净分析机上只通过符号服务解析,验证源码行和私有函数。删除分析机临时缓存,确认没有依赖构建机偶然残留路径。
若使用 SymStore,先在隔离仓库演练 add、查询和事务回滚,再交给单写者流水线。符号仓库写权限只给发布身份,开发者和分析机使用只读权限;同一事务的清单、日志和摘要进入审计记录。
容量预算从触发频率和内存规模一起算
Full dump 的规模与进程可访问内存密切相关,不能把一个小测试程序的压缩比推广到所有服务。容量预估至少包含:
最坏单份大小 × 单次最大份数 × 同时受监控实例数
+ 符号缓存增长
+ TTD .run、可重建 .idx 与录制日志
+ WinDbg 日志与传输临时副本
+ 安全余量采集前观察目标 commit、目录当前总量与磁盘可用空间:
$p = Get-Process -Id <target-pid>
$resolvedDumpDir = (Resolve-Path -LiteralPath $DumpDir).Path
$drive = [IO.DriveInfo]::new([IO.Path]::GetPathRoot($resolvedDumpDir))
[pscustomobject]@{
PrivateBytes = $p.PrivateMemorySize64
DumpDirectoryBytes = (Get-ChildItem $DumpDir -File -Recurse |
Measure-Object Length -Sum).Sum
AvailableFreeBytes = $drive.AvailableFreeSpace
}PrivateMemorySize64 是该进程已提交的私有字节,不等于 ProcDump -m 判断的完整进程 commit,也不等于 Full dump 大小;这里把它作为容易取得的预算输入,并同时保留磁盘余量。需要让脚本复刻 -m 触发判断时,应使用经目标 PID 校验的 Windows 性能计数器并先处理同名实例映射,不能把这个属性直接代替官方触发指标。-mp 对 CLR 进程可能转成 Full;first-chance 触发可能在短时间连发;-r clone 并发会叠加瞬时资源。容量门禁应在启动前拒绝不安全计划,并在写入后重新检查,而不是等磁盘满了再删。
团队指标不要只看“采集成功率”,还应看触发次数、实际写出数、因容量/暂停预算跳过数、每份大小、目录总量、分析完成到销毁的年龄、符号命中率与 mismatch 数。阈值来自进程基线、磁盘预算和恢复目标,不使用脱离负载的万能数字。
权限提升必须是例外路径
调试同一用户拥有的测试进程通常不需要 SeDebugPrivilege。跨用户、LocalSystem 服务或本无权访问的进程可能需要 Debug privilege;它可以绕过常规进程访问边界,因此是高权限能力,不是“遇到 Access Denied 就以管理员重试”的快捷键。
权限失败按下面的证据顺序排查:
记录目标 PID、可执行路径、进程所有者和完整性级别。确认调试器/ProcDump 进程使用的账号、token 和架构。判断进程对象 ACL、组织策略、EDR 或受保护进程机制是否拒绝访问。
只在获得授权后,于故障窗口临时提升并记录审批与操作人。采集结束立即退出高权限会话,复核没有常驻监控、计划任务或调试器残留。
同一账号能打开测试进程、另一安全上下文的受控测试服务被拒绝、授权临时提升后成功,这组三段式实验比用系统关键进程做反例更安全。不要以 LSASS、受保护进程或生产核心服务作为教学靶标。
所有 dump 都先按高敏证据处理
Full dump 可能包含 token、连接串、Cookie、请求体、客户数据、明文密钥、文件路径和已经“释放”但仍残留在页面中的字节。扩展名是 .dmp 不会降低数据等级。ProcDump -mt、WinDbg .dump /mr 和 /mR 都只是减少某些数据,不能作为脱敏证明。
采集目录应满足以下条件:
本地加密存储,ACL 只允许故障处理角色和受控服务身份。不使用桌面、下载目录、公共共享盘或自动同步网盘。文件产生后立即记录 SHA-256、目标构建身份、采集工具版本和访问人。
传输走受控证据库,启用静态/传输加密、访问审计和到期销毁。分析前使用合成数据验证流程;真实 dump 不在普通编辑器、在线反编译网站或第三方 AI 服务中打开。
完整转储绝不能当作普通附件上传到公共工单、聊天群、邮件或无访问控制的 CI 制品区。 即便只发给同事,也要先按组织的数据分级与事故证据流程审批。需要外部厂商协助时,优先生成最小充分副本,并明确合同、传输、访问、地域和销毁边界。
清理不是删掉最后一个 .dmp
ProcDump 监控可用 Ctrl+C 结束,也可从另一会话取消:
.\procdump.exe -cancel <target-pid>取消事件会影响监控同一目标的 ProcDump 实例,团队脚本要先列出 owner 和实例,避免误停别人的取证。若曾用 procdump -i 注册机器级 AeDebug 事后调试器,结束时必须撤销:
.\procdump.exe -u不要把 -i 当作普通单次采集参数,它会改变机器级崩溃处理入口。live 调试器使用 qd 或 .detach 保留目标,并验证进程重新响应;若修改过线程 suspend count,还要配对恢复。
证据交接和保留期结束后,清理清单包括:
dump、CAB、WinDbg 日志和临时导出文本。TTD .run、.idx、录制日志和监控残留。传输暂存、副本、失败上传分片和分析机下载目录。
private PDB、临时源码映射和构建制品副本。downstream symbol cache 与调试扩展缓存。ProcDump 监控进程、AeDebug 注册和临时高权限会话。
符号 cache 是可重建派生数据,可以在确认路径后整体删除。AgeStore 支持按年龄或容量管理并可用 -l 预演,但依赖 NTFS Last Access Time;现代 Windows 默认配置常使该时间不可用。不要为了清一次缓存贸然修改文件系统行为并重启生产机。
常见失败要回到证据链定位
| 现象 | 先看什么 | 常见原因 | 修复后怎样再验证 |
|---|---|---|---|
| ProcDump 报访问拒绝 | PID、owner、token、ACL | 跨安全上下文、策略或受保护进程 | 用同用户测试进程验证工具,再按审批临时提升 |
| dump 能打开但某地址不可读 | dump 类型与目标地址范围 | Mini 未采集该内存 | 在隔离环境用 Mini/Full 对照,不对原文件强行补数据 |
| 只有系统栈,没有业务源码行 | lm、.sympath、!sym noisy | private PDB 缺失、网络失败或身份 mismatch | .reload /f 后由 !lmi 核对 GUID/age |
| PDB 文件名正确仍拒载 | RSDS 身份、GUID/age | 来自另一次同名构建 | 恢复原构建 PDB,不忽略 mismatch |
-e 1 很快写满目录 | 触发日志、过滤、-n | 可处理 first-chance 异常过于频繁 | 降为 -e 或增加经验证过滤与硬上限 |
-h 没抓到服务挂死 | 进程是否有 GUI 窗口 | -h 只看窗口消息响应 | 改用多时点 PID dump、线程与应用超时证据 |
| attach 后服务更慢或不响应 | 暂停时长、线程 suspend/freeze | break、noninvasive 或残留 suspend | 恢复计数、qd/.detach,验证请求重新流动 |
| 公共符号服务器不可达 | TLS、代理、CA、DNS、缓存 | 企业网络限制或证书链失败 | 使用受控代理/预热缓存,保留证书校验 |
排障完成的标准不是“换管理员后能跑”,而是能说明哪一层失败、为什么失败、修复是否只扩大了必要权限,以及现场是否恢复。
团队把符号和转储当成一条受控供应链
成熟团队不让 dump 与 PDB 依赖某位开发者的笔记本。建议按职责拆成四层:
采集层:只负责识别目标、评估暂停与容量、按批准策略写出最小充分 dump。证据层:保存摘要、构建清单、访问审计、保留期限和销毁状态。符号层:发布不可变业务 PDB,分离 private/public 存储,提供只读查询和缓存。
分析层:使用隔离工作站与固定调试器基线,输出命令、符号身份和可复核结论。
符号服务应有单一发布 owner、只读消费者、构建身份索引、备份恢复演练和退役策略。Microsoft 公共符号服务放在业务符号之后,只作为系统模块来源。内部服务不可用时,分析应明确降级为地址与导出符号,不把不完整栈包装成最终结论。
转储策略则按问题逐级升级:线程/异常先从 Triage 或 Mini 起,证据明确缺少 private memory 时再申请 MiniPlus/Full。每次升级都重新评估暂停、文件大小、敏感内容、传输和保留期。这样,WinDbg 的价值不再是“某个人会敲 !analyze -v”,而是团队能证明一个地址属于哪次构建、一个判断依赖哪些内存、一次取证留下了什么影响,并在结论交付后把高敏证据彻底退出系统。
