reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
# WinDbg 命令速查与操作序列
|
||||
|
||||
WinDbg 命令三类:普通命令(`.exr`/`g`/`r`,点开头)、扩展命令(`!analyze`/`!process`,叹号开头、来自扩展 DLL)、伪寄存器(`$<名>`)。符号语法 `模块!符号`(`nt!KeWaitForSingleObject`)。官方参考: Microsoft Learn 调试器命令参考(debuggercmds)。
|
||||
|
||||
## 命令族速查
|
||||
|
||||
### 会话与运行
|
||||
|
||||
- `windbg -p <pid>` / `windbg <exe>`;`-g` 跳过初始断点;`-z <dump>` 打开 dump;`-k` 内核调试连接
|
||||
- `g` 继续;`gh`/`gn` 继续(异常交给程序/忽略);`Ctrl+Break` 中断;`q` 退出
|
||||
- `.restart` 重启目标;`.detach` 脱离;`.kill` 终止
|
||||
|
||||
### 断点
|
||||
|
||||
- `bp <模块!符号|地址>`;`bu <符号>` 未解析符号断点(模块加载后自动生效——目标 DLL 未加载时首选)
|
||||
- `bm <通配>` 批量断点(如 `bm nt!Io*`);`bl` 列表;`bd`/`be` 禁用/启用;`bc *` 清空
|
||||
- 条件断点: `bp addr ".if (rax==0) { } .else { gc }"`——不满足条件自动继续
|
||||
- 命令断点: `bp addr "r; k; gc"` 命中时执行命令后继续(日志式观察)
|
||||
|
||||
### 单步与栈
|
||||
|
||||
- `p` 步过;`t` 步入;`pa <addr>` 步过到地址;`ta <addr>` 步入到地址;`gu` 执行到返回;`pt` 执行到 call 返回
|
||||
- `k` / `kb` / `kv` 栈回溯(参数/符号帧);`kn` 带帧号;`dps rsp` 按指针看栈内容
|
||||
- `.frame <n>` 切栈帧;`.ecxr` 设异常上下文(dump 分析开局);`.exr <addr>` 显示异常记录;`.cxr <addr>` 手动设上下文
|
||||
|
||||
### 寄存器与内存
|
||||
|
||||
- `r` / `r rax` / `r eax=0`;`r $t0=...` 伪寄存器(脚本临时变量)
|
||||
- `db`/`dd`/`dq`/`du` 读内存(字节/双字/四字/Unicode);`dps` 按指针解释
|
||||
- `eb`/`ed` 写内存(`eb 0x401000 90`);`u <addr>` 反汇编(`u 地址 L数量`)
|
||||
- 搜索: `s -d 0x0 L?10000000 0xdeadbeef`(值)、`s -a 0x0 L?10000000 "text"`(ASCII 字符串)——在进程虚拟地址空间找常量/串
|
||||
- 内存映射: `!address <addr>` 区域信息(权限/映射);`!vad` 用户态 VAD 树
|
||||
|
||||
### 符号
|
||||
|
||||
- `.sympath srv*C:\symbols*https://msdl.microsoft.com/download/symbols`;`.symfix` 用默认符号服务器
|
||||
- `.reload /f [模块]` 强制重载符号;`lm`/`lmv m <模块>`/`lmi <模块>` 模块与镜像信息
|
||||
- `x <模块>!*<关键字>*` 搜索符号(如 `x nt!*ExAlloc*`)
|
||||
|
||||
### 扩展命令(常用子集)
|
||||
|
||||
- 崩溃: `!analyze -v`(EXCEPTION_CODE/FAULTING_IP/STACK_TEXT/PROCESS_NAME)
|
||||
- 进程/线程: `!process 0 0`;`!process <EPROCESS> 1`;`!thread`;`!teb`;`!peb`
|
||||
- 句柄/堆: `!handle <句柄>`;`!heap -a`;`!pool <地址>`(内核池块)
|
||||
- 内核对象: `!object <地址>`;`!devobj`/`!drvobj`(设备/驱动对象);`!irp <地址>`;`!stacks 0`(全栈汇总)
|
||||
- 其他: `!dlls`(进程模块树)、`!runaway`(线程 CPU 时间)、`!locks`(锁)
|
||||
|
||||
### dump 与转储
|
||||
|
||||
- 用户态全量: `.dump /ma C:\x.dmp`(含句柄/内存,取证标准);`.dump /f`(full)
|
||||
- 内核: 目标机 `%SystemRoot%\Minidump\*.dmp`(小转储);完全 dump 需配置内核 dump 设置
|
||||
- `.writemem <文件> <起> <止>` 导出内存区段;`.readmem` 读回
|
||||
|
||||
### TTD(时间旅行调试,需管理员)
|
||||
|
||||
- 录制: `ttd.exe -out C:\traces target.exe args`;`ttd.exe -attach <pid> -out ...`;`-monitor <名>`;`-ring`(环形 2GB 上限)
|
||||
- 打开: WinDbg `File > Open` 选 `.run`;索引: `!tt.index`(首次慢,之后快)
|
||||
- 回放: `g-` 往回跑;`t-`/`p-` 往回单步;`!tt 50` 跳百分比;`!tt 位置` 跳 `事件:步数`
|
||||
- 断点: `!tt br <寄存器> [值]`(值变化处停,`br-` 往回找);`!tt bm <地址范围>`(内存访问处停)
|
||||
- 数据模型: `dx @$cursession.TTD.Calls("模块!函数")`;`dx @$cursession.TTD.Memory(起, 止, "rwec")`(内存访问记录)
|
||||
- `ttd.exe -stop all` 停止所有录制;`-help` 全参数
|
||||
|
||||
## 常用操作序列(组合套路)
|
||||
|
||||
### 1. 崩溃 dump 分析(minidump 标准开局)
|
||||
|
||||
```
|
||||
windbg -z C:\dump.dmp
|
||||
.sympath srv*C:\symbols*https://msdl.microsoft.com/download/symbols; .reload /f
|
||||
.ecxr # 异常上下文设现场(WER dump 的当前上下文在 WerpReportFault 里不可信)
|
||||
k # 真实栈回溯
|
||||
!analyze -v # 自动化分析:FAULTING_IP / STACK_TEXT 逐帧核对
|
||||
```
|
||||
|
||||
### 2. 校验绕过(断 API → 改返回 → 继续)
|
||||
|
||||
```
|
||||
windbg 目标.exe(-g 可跳过初始断点)
|
||||
bp kernel32!CreateFileW # 或目标校验 API
|
||||
g → 命中后:
|
||||
r rax=0 # 改返回值
|
||||
gu; g # 出函数后继续
|
||||
```
|
||||
|
||||
### 3. 驱动/内核模块符号与深度分析
|
||||
|
||||
```
|
||||
!process 0 0 → 找目标进程 EPROCESS
|
||||
.process /p <EPROCESS>; .reload /f
|
||||
lmv m <驱动名> # 基址/版本/路径
|
||||
bp <驱动名>!<函数> # 驱动内符号断点
|
||||
!analyze -v(内核崩溃时出 bugcheck + 故障驱动)
|
||||
```
|
||||
|
||||
### 4. TTD 录制 → 回放找解密/校验点
|
||||
|
||||
```
|
||||
ttd.exe -out C:\traces target.exe # 管理员命令行录制
|
||||
WinDbg 打开 .run → !tt.index
|
||||
dx @$cursession.TTD.Calls("模块!可疑函数") # 看调用次数/参数分布
|
||||
!tt br <寄存器> → 定位值变化点 → 前向/后向单步看上下文
|
||||
```
|
||||
|
||||
### 5. 栈损坏现场恢复(live 会话)
|
||||
|
||||
```
|
||||
命中崩溃 → .exr <EXCEPTION_RECORD 地址>(!analyze -v 的 STACK_TEXT 里取)
|
||||
.cxr <CONTEXT 地址> → k → kv
|
||||
```
|
||||
|
||||
## 实现教训(内化)
|
||||
|
||||
- `!analyze -v` 是起点不是终点——`STACK_TEXT` 后必须 `.ecxr` + `k` 手工核对真实调用链
|
||||
- 符号未加载时一切输出都是裸偏移——先 `.symfix` + `.reload /f`,断点用 `bu`(未解析也可设)
|
||||
- 条件断点用 `.if/.else + gc` 语法(不是 gdb 的 `if` 后缀);命令断点实现日志式观察不中断
|
||||
- `s` 搜索在用户态可用 `L?<范围>`;内核态地址空间搜索量大,先缩小范围
|
||||
- TTD 的 `!tt bm`/`br` 是「找内存/寄存器事件」的利器——比反复重跑目标快得多
|
||||
- 栈损坏场景 `.ecxr`/`.cxr` 是唯一可靠回溯路径,别信 `k` 的直接输出
|
||||
|
||||
## 使用注意
|
||||
|
||||
- 全部在沙箱内执行([[re-analyze/platform-tips]] 最高原则);attach/内核调试需管理员权限
|
||||
- 结论写 [[re-analyze/analysis-contract]];dump 产物 sha256 与 [[re-triage]] 初勘值对照;驱动场景配合 [[re-kernel]]
|
||||
@@ -0,0 +1,46 @@
|
||||
# WinDbg 工具特有坑与边界
|
||||
|
||||
## 版本差异(经典版 vs 商店版 vs WDK)
|
||||
|
||||
- **经典版(WinDbg 10.0.x)**:随 Windows SDK "Debugging Tools for Windows" 安装;传统 Win32 UI,`windbg.exe`/`kd.exe`/`cdb.exe` 同包
|
||||
- **商店版(WinDbg 1.x,WinDbg Next)**:`winget install Microsoft.WinDbg` 或 Store;Chromium 新 UI,命令与经典版兼容(同一套调试引擎),附加/断点/内存视图的 UI 入口不同——教程截图对不上时按命令窗口操作,命令是通用的
|
||||
- **WDK**:装内核调试工具链(kd.exe/kdnet.exe、`bcdedit` 相关脚本、驱动测试工具)——只做用户态调试不需要装整个 WDK
|
||||
- **32/64 位 WinDbg 分开**:经典版有 x86/x64 两个可执行文件——64 位 dump 用 32 位 WinDbg 打开会报格式错;商店版自动处理
|
||||
- **命令兼容性**:`!` 扩展命令由扩展 DLL 提供(`ntsdexts`/`ext` 等),版本旧时个别扩展缺失——`!analyze` 等核心命令在所有版本都有
|
||||
|
||||
## 符号服务器坑
|
||||
|
||||
- **未配置符号 → 全裸偏移**:`lm` 行尾 `(no symbols)`、`k` 输出 `模块!+0x1a`——`.sympath srv*C:\symbols*https://msdl.microsoft.com/download/symbols` 后 `.reload /f`
|
||||
- **符号服务器不可达/代理**:内网环境拉不到符号会挂起(重试很久)——`.sympath` 指向本地符号缓存优先,配 `_NT_SYMBOL_PATH` 时先确认网络可达
|
||||
- **私有符号(未公开)**:系统 DLL 的公有符号只到函数粒度,行号/局部变量需要私有符号——分析系统组件逻辑时以反汇编为准,别依赖 `dv` 的局部变量
|
||||
- **`bu` vs `bp`**:`bu`(unresolved)对尚未加载的模块符号有效(模块加载后自动绑定)——设 DLL 内断点用 `bu`,`bp` 会因符号未解析失败
|
||||
- **过期符号缓存**:符号缓存陈旧与二进制不匹配(服务包更新后)——`!analyze -v` 出现乱地址时清掉 `C:\symbols` 里对应条目重新拉
|
||||
|
||||
## 内核调试坑
|
||||
|
||||
- **PatchGuard(内核保护)限制**:本地内核调试(`File > Kernel Debug > Local`)仅测试机可用且能力受限(PatchGuard 干扰断点/单步);正式内核分析用双机/VM 传输
|
||||
- **传输配置必须两边一致**:串口参数(debugport/baudrate)或 NET 参数(hostip/port/key)在宿主与目标必须完全匹配——`bcdedit /dbgsettings` 重查配置;VM 管道串口用 `\\.\pipe\com_1` 两边同名
|
||||
- **kdnet key 有效期**:`kdnet.exe` 生成的 key 与目标网卡绑定,换网卡/重装后需重新生成
|
||||
- **内核调试不能暂停全部内核线程**:`g` 后系统在跑,断点只在事件时刻停——时序类 bug 用 `!analyze -v` 或 TTD(用户态)思路替代
|
||||
- **wow64 内核调试**:32 位进程线程栈在 x86 层,`!process` 字段按位数对——跨位数核对时先确认进程位数
|
||||
|
||||
## 异常/栈现场坑
|
||||
|
||||
- **WER dump 的当前上下文不可信**:Windows Error Reporting 抓的 dump 停在 `WerpReportFault` 报告路径里——直接 `k` 看到的是报告代码的栈;必须 `.ecxr` 恢复异常上下文后再 `k`(`.exr -1` 先看异常记录也行)
|
||||
- **`.cxr` vs `.ecxr`**:`.cxr <addr>` 手动指定 CONTEXT 地址;`.ecxr` 自动取当前异常上下文——dump 分析用 `.ecxr`,live 现场用 `.exr` 拿地址后 `.cxr`
|
||||
- **栈损坏时 `k` 假象**:栈指针被踩后 `k` 输出乱地址——`.exr`/`.cxr` 恢复现场是唯一可靠路径;`!analyze -v` 的 `STACK_TEXT` 里直接取现场地址
|
||||
- **`!analyze -v` 是辅助不是结论**:它按启发式给 FAULTING_IP/STACK_TEXT,混淆/罕见场景会指向错误位置——逐帧核对 `STACK_TEXT`,必要时手工 `.exr`/`k`
|
||||
|
||||
## TTD 限制
|
||||
|
||||
- **管理员权限必需**:ttd.exe 录制需要管理员;非管理员运行静默失败或录不出轨迹
|
||||
- **仅用户态**:不能录内核/驱动;PPL 保护进程无法注入录制
|
||||
- **轨迹文件巨大**:数分钟可到数 GB(无上限)——`-maxfile <MB>` 限制或 `-ring`(2GB 环形覆盖);索引 `.idx` 约两倍轨迹大小
|
||||
- **回放只读**:轨迹里不能写内存/改寄存器——「验证假设」在回放中做不了,只能观察;要改就重新录制或转常规调试
|
||||
- **录制开销高**:录制期间目标明显变慢(数倍);`-numvcpu` 可调;个别框架(Electron 类)录制时可能死锁/崩溃——录不了就退回常规断点调试
|
||||
- **`.run` 文件含敏感信息**:轨迹含进程内存/文件路径/寄存器值——分享轨迹等于分享数据,注意脱敏(与 [[re-malware]] 报告同原则)
|
||||
|
||||
## 使用注意
|
||||
|
||||
- 全部在沙箱内执行([[re-analyze/platform-tips]] 最高原则);attach/内核调试需管理员权限
|
||||
- 版本相关行为(扩展命令集、UI 入口)以实际安装版本为准;命令窗口是跨版本最稳定的界面
|
||||
Reference in New Issue
Block a user