reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
---
name: re-windbg
description: >
WinDbg 调试(Windows 用户态+内核)。触发词:WinDbg、windbg、内核调试、kd、!analyze
capabilities: [debugging]
---
# WinDbg 动态调试(Windows 用户态 + 内核)
## 何时使用 / 何时不用
- 用:Windows 用户态进程调试(启动/附加、断点、单步、寄存器);崩溃/异常分析(`!analyze -v`);内核调试(双机/VM/本地 kd);驱动与内核模块分析(配合 [[re-kernel]]);崩溃 dump(minidump/full dump)分析
- 用:时间旅行调试(TTD)——`ttd.exe` 录制 .run 轨迹后任意回放,适合「复现一次慢慢查」的校验/解密逻辑(见 [[commands]] TTD 节)
- 不用:Linux 目标(走 [[re-gdb]]);macOS 目标([[re-lldb]]);只需轻量 GUI 调试([[re-x64dbg]] 更快)
- 不用:只做静态分析/反编译([[re-ida]] / [[re-ghidra]] / [[re-binaryninja]]);无需与运行态互动的纯静态流程不需要调试器
- 不用:WSL 内跨边界 attach Windows 进程([[re-analyze/platform-tips]] WSL 分支:跨边界走 Windows 侧工具)
## 工具准备
参考 [[re-analyze/platform-tips]] Windows 分支——attach 需要管理员权限;调试属动态执行,默认沙箱内进行([[re-analyze/platform-tips]] 最高原则)。
### WinDbg(微软商店版 / Windows SDK / WDK)
- 商店版(新 UI WinDbg):`winget install Microsoft.WinDbg`(或 Microsoft Store 搜索 "WinDbg")
- 经典版:Windows SDK 安装器勾选 "Debugging Tools for Windows";`choco install windbg`
- WDK(含内核调试工具 kd.exe/kdnet.exe):`winget install Microsoft.WindowsWDK` 或 Visual Studio 安装器勾选 WDK
- 验证: 打开 WinDbg,`File > Open Executable` 加载任意 exe 能停在初始断点;命令窗口 `ver` 输出版本号
- 版本差异: 商店版(WinDbg 1.x,Chromium UI)与经典版(WinDbg 10.0.x)命令兼容,UI 与附加流程不同;dump 分析两者通用(见 [[gotchas]])
### Windows 符号(Windows SDK 符号 / 公共符号服务器)
- 符号路径: `.sympath srv*C:\symbols*https://msdl.microsoft.com/download/symbols`(或设环境变量 `_NT_SYMBOL_PATH`)
- 内核模块符号: 内核调试下 `.reload /f nt`(强制从符号服务器拉取)
- 验证: `!analyze -v` 输出中出现函数名而非 `+0x1a` 裸偏移
### 双机/虚拟机内核调试环境
- 目标机(被调试): `bcdedit /debug on` + `bcdedit /dbgsettings serial debugport:1 baudrate:115200`(串口)或 `bcdedit /dbgsettings net hostip:<宿主机IP> port:50000 key:<kdnet.exe生成的key>`(NET 网卡,Windows 10+ 推荐)
- VM 场景: VMware/Hyper-V 给目标 VM 添加串口设备(Named Pipe `\\.\pipe\com_1` / `-vmconnect`),宿主 WinDbg `File > Kernel Debug > COM` 填管道名
- 本地内核调试(仅测试机,需测试签名): `bcdedit /set testsigning on` 重启后,WinDbg `File > Kernel Debug > Local`
- 验证: 目标机重启停在 "Waiting to reconnect" 或进入调试等待后,宿主 WinDbg 附加成功、`g` 后 `Ctrl+Break` 能中断、`lm` 列出模块
### TTD(时间旅行调试,Windows 10 1903+)
- 录制: `ttd.exe -out C:\traces target.exe`(或 `-attach <pid>` 附加录制;`-monitor <进程名>` 监控启动)
- 打开: WinDbg `File > Open` 选 `.run` 轨迹文件(或 `Open Trace File`)
- 验证: `ttd.exe -help` 有输出;录一段后用 WinDbg 打开,`!tt` 能跳到任意位置、`g-` 能往回跑(详见 [[commands]] TTD 节)
## 操作步骤
1. **附加/启动用户态目标**:
- 启动: `File > Open Executable` 选目标 exe,停在初始断点(ntdll 加载完成处)
- 附加: `File > Attach to Process` 按 PID/进程名选目标(**管理员权限**启动 WinDbg 才能附加高权限进程)
- 命令行: `windbg -p <pid>` / `windbg 目标.exe`;`-g` 跳过初始断点直接运行
2. **断点 / 单步 / 寄存器**:
- 符号断点: `bp kernel32!CreateFileW`;地址断点: `bp 0x401000`;`bl` 列表、`bd`/`be` 禁用/启用、`bc *` 清空
- 未加载模块的符号用 `bu`(unresolved,模块加载后自动绑定)——目标 DLL 按需加载时 `bu` 是正解
- 命令断点: `bp 地址 "r rax; k; gc"`——命中时打印现场后自动继续,日志式观察不打断流程
- 单步: `g` 继续、`p` 步过、`t` 步入、`gu` 执行到当前函数返回
- 寄存器: `r` 全部、`r rax` 查看、`r eax=0` 修改(绕过校验常用)
- 内存/反汇编: `u 0x401000` 反汇编、`dd`/`db` 读内存、`dps rsp` 看栈内容
- 搜索: `s -d 0x0 L?10000000 0xdeadbeef`(值)、`s -a 0x0 L?10000000 "text"`(ASCII 串)——找硬编码常量/密钥用
- 符号搜索: `x 模块!*关键字*`(如 `x kernel32!*Virtual*`)——不确定精确符号名时模糊匹配
3. **异常分析 `!analyze -v`**:
- 目标崩溃停下后: `!analyze -v` → 读 `EXCEPTION_CODE`、`FAULTING_IP`、`STACK_TEXT`、`PROCESS_NAME`
- 内核蓝屏对应 bugcheck 码(`BUGCHECK_CODE`,如 0xD1 驱动访问无效内存)——先记码再往下查,常见码含义要能对上故障方向
- 现场恢复: 从 `STACK_TEXT` 取 `EXCEPTION_RECORD` 地址 `.exr <addr>`(异常记录),再取 `CONTEXT` 地址 `.cxr <addr>` 恢复寄存器现场,之后 `k` 出真实调用栈(栈损坏时唯一可靠的栈回溯方式)
- dump 现场更简单: 打开 dump 后直接 `.ecxr`(自动用异常上下文设寄存器现场)→ `k`——minidump 分析标准开局
- dump 分析: `File > Open Crash Dump` 打开 `.dmp`(用户态用 `.dump /ma` 生成;内核蓝屏用 `%SystemRoot%\Minidump\*.dmp` 或完全 dump),同样 `!analyze -v` 出 bugcheck 码与故障模块
4. **内核调试(双机 / VM / 本地 kd)**:
- 目标机配置见「工具准备」;配置后重启,宿主 `File > Kernel Debug` 按所用传输(COM/NET)连接
- VM 管道串口流程: 目标 VM 加串口 Named Pipe → 目标机 `bcdedit /dbgsettings serial` → 宿主 `File > Kernel Debug > COM` 填管道名(`\\.\pipe\com_1`)→ 目标机重启等连
- 连接后: `g` 让目标继续跑;`Ctrl+Break` 随时中断回调试器;`!process 0 0` 确认会话活着
- 本地调试: `bcdedit /set testsigning on` 重启后 `File > Kernel Debug > Local`(仅测试机,不影响生产机的用法)
5. **扩展命令**:
- `!process 0 0`(全部进程列表)、`!process <EPROCESS> 1`(单进程详情+线程);`.process /p <EPROCESS>` 切到目标进程上下文后再 `k`/`!thread`
- `!teb`(当前线程 TEB)、`!peb`(当前进程 PEB——命令行、加载模块、环境块)
- `lm`(模块列表,行尾 `(deferred)`=符号未加载、`(no symbols)`=无符号)、`lmv m <模块>`(版本+路径)、`lmi <模块>`(镜像头)
- `kv`(带符号完整栈回溯,驱动分析常用)、`!analyze -v` 后按 `STACK_TEXT` 逐帧核对
- 驱动专项: `lmv m 驱动名` 拿基址 → `.reload /f 驱动名` 加载符号 → 深挖转 [[re-kernel]]
6. **TTD 回放(校验/解密逻辑慢查)**:
```
ttd.exe -out C:\traces target.exe # 录制
WinDbg 打开 .run → g- / t- / p- # 往回跑
!tt 50 # 跳到轨迹 50% 处
!tt 7213:36 # 跳指定位置(事件序号:步数)
```
- 断点前移/后移: `!tt br` 在某寄存器值变化处停;`!tt bm` 在内存访问处停
- 首次打开轨迹先 `!tt.index` 建索引(之后打开跳过);回放中途也可断点 `bp`(在轨迹上工作)
- 查询 API: `dx @$cursession.TTD.Calls("模块!函数")` 统计调用次数/参数(如 `...Calls("ntdll!mem*")`)
- TTD 限制: 需管理员运行、用户态专用、轨迹文件很大(数 GB)、回放只读不能写内存(见 [[gotchas]])
7. **伪寄存器与脚本化(简单自动化)**:
- 伪寄存器: `r $t0 = 0` 起临时变量;`$$ > <文件>` 把命令输出重定向到文件(如 `$$ > c:\log.txt`)
- 条件执行: `.if (rax==0) { ... } .else { ... }`——配合 `gc` 做断点内逻辑
- `!runaway` 看线程 CPU 时间(找忙等/死循环线程);`!locks` 查锁状态(挂起排查)
## 跨域联合
- [[re-binary-core]]:工作流第 6 步 Windows 调试器(用户态+内核)
- [[re-kernel]]:内核调试与驱动/rootkit 运行时验证固定调用本技能
- [[re-anti-analysis]]:反调试对抗(内核级检测点)、脱壳后验证
- [[re-malware]]:恶意样本崩溃 dump 分析与内核组件
- [[re-cracking]]:授权校验崩溃定位(`!analyze -v` 快速找崩溃原因)
- 与 [[re-x64dbg]] 互补:轻量 GUI 断点调试用 x64dbg,内核/异常现场恢复/轨迹回放用 WinDbg
## 常见坑与陷阱
- **符号未配置 → 全是裸偏移无函数名**:现象——`lm` 行尾 `(no symbols)`,`k` 输出 `ntdll!+0x1a`;原因——符号路径为空或没 `_NT_SYMBOL_PATH`;对策——`.sympath srv*C:\symbols*https://msdl.microsoft.com/download/symbols` 后 `.reload /f`,内核模块同理(先确认符号服务器可达)
- **内核调试配置错 → 目标机蓝屏死等或连不上**:现象——目标机重启后停在 debug 等待或直接进系统未中断;原因——bcdedit 传输类型/端口与宿主不一致,或物理机单机本地调试受限(PatchGuard);对策——用 VM 串口管道最稳(两边都对 `\\.\pipe\com_1`),`bcdedit /dbgsettings` 重查配置,物理机场景优先 KDNET
- **32/64 位命令与寄存器差异**:现象——64 位目标下 `r eax` 改错值、`!teb` 字段对不上;原因——x64 上下文用 `rax/rbx...`(低 32 位是 `eax` 等)、wow64 目标线程栈在 x86 层;对策——先确认目标位数,wow64 场景 `.load wow64exts` + `!wow64exts.sw` 切到 x86 上下文
- **栈损坏时 `k` 是假象**:现象——调用栈乱(地址不像代码);原因——栈指针被破坏/内存踩踏,常规回溯不可信;对策——用 `.exr` 拿异常记录、`.cxr` 恢复 CONTEXT 后再 `k`,必要时 `!analyze -v` 的 `STACK_TEXT` 里直接取现场
- **蓝屏 dump 打不开**:现象——`Open Crash Dump` 报格式错;原因——minidump 不完整(磁盘满)或用的 32 位 WinDbg 读 64 位 dump;对策——目标机确认内核页交换文件(crash dump 需要 pagefile)足够大,改用同位数 WinDbg
- **RPC 调用统一入口 NdrStubCall3(svchost 功能逆向)**:现象——要拦/分析某个系统功能(如 Toast 通知),不知道它经什么通道进 svchost;原因——功能实现经 RPC 到 svchost 进程,入口难找;对策——Process Monitor 看目标进程加载 rpcrt4.dll + RpcView 确认 RPC 目标进程;**所有 RPC 服务端 stub 统一走 rpcrt4 的 NdrStubCall3**(x64;NdrStubCall2 是旧版 x86,ReactOS/Wine 源码可印证)——在其下断 `kvn` 看调用来源;筛选目标调用:第三参数(r8)指向 RPC_MESSAGE(+0x1C 是 ProcNum 方法编号、+0x28 是接口描述指针 RpcInterfaceInformation → RPC_SERVER_INTERFACE 的 InterfaceId 在 +0x04);**opnum 由 MIDL 按方法声明顺序从 0 编号**(如 PostNotification3 排第 0x29 位 → opnum=0x29),ObjectStublessClientN 中 rax=N 即 ProcNum;坑:NdrStubCall3 处理 svchost 内所有 RPC 接口,**必须按 InterfaceId + ProcNum 双重筛选**,只拦目标方法(拦错会把 Edge 等其他功能搞挂)
- TTD 限制、版本差异与符号服务器细节见 [[gotchas]]