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,135 @@
---
name: re-gdb
description: >
GDB/pwndbg/gef 调试:attach、断点、内存读写。
触发词:gdb、调试、pwndbg、attach
capabilities: [debugging]
---
# GDB/pwndbg/gef 动态调试
## 何时使用 / 何时不用
- 用:Linux 目标动态调试(attach/启动/断点/内存读写);core 文件分析;Wine 下调试 PE 进程
- 不用:Windows 原生目标(走 [[re-x64dbg]],或 Wine 内 gdb 见 [[re-analyze/platform-tips]] Linux 分支);macOS 目标(走 [[re-lldb]])
- 不用:只读内存不调试(默认转储优先,走 [[re-memdump]])
## 工具准备
参考 [[re-analyze/platform-tips]]:动态执行默认沙箱;Linux 分支的 Wine 进程 attach 经验;`直读 vs 转储` 决策——attach 失败即转 [[re-memdump]]。
### gdb
- Linux: `apt install gdb` / `dnf install gdb` / `pacman -S gdb`
- macOS: `brew install gdb`(需自签证书,一般直接用 lldb 更顺)
- WSL: Linux 包直接可用(跨 Windows 边界 attach 不可行,见 [[re-analyze/platform-tips]] WSL 分支)
- 验证: `gdb --version`
### pwndbg / gef(选其一)
- pwndbg: 官方 portable 安装脚本(Linux/macOS 主路径):
```sh
curl --proto '=https' --tlsv1.2 -LsSf 'https://install.pwndbg.re' | sh -s -- -t pwndbg-gdb
```
LLDB 版把 `-t` 换成 `pwndbg-lldb`;另有 Homebrew(`brew install pwndbg/tap/pwndbg-gdb`)、Nix 与发行版包可选。仓内 `git clone + ./setup.sh` 属 legacy/开发用(内部调 sudo 需 root),不再是主路径
- gef:
```sh
curl -L https://github.com/hugsy/gef/raw/master/gef.py -o ~/.gdbinit
```
- 验证: 进入 gdb 出现 pwndbg/gef banner
- 注意: 两者不要同时装(hook 互相干扰);pwndbg portable 版经包装脚本加载、不写 `~/.gdbinit`,与 gef 的 `~/.gdbinit` 注入方式不同;版本滚动较快,功能差异以各自官方 README 为准(详见 [[gotchas]])
### checksec(二进制防护检查)
- pwndbg 内置 `checksec` 命令(装好 pwndbg 即用)
- 或 `pip install pwntools` → `pwn checksec --file ./target`
- 验证: `gdb -q -ex 'checksec' -ex quit ./target` 输出 NX/Canary/RELRO/PIE
## 操作步骤
1. **attach 前查 ptrace 权限**:
```sh
cat /proc/sys/kernel/yama/ptrace_scope
# 1 = 仅父进程可 attach(默认);0 = 任意同属主;容器内常被强制禁止
sudo sysctl -w kernel.yama.ptrace_scope=0 # 临时放宽(重启还原)
```
```sh
gdb -q -p <pid> # 同属主或 root;失败(Operation not permitted)→ 见坑 1
```
沙箱容器内 attach 常被 seccomp 拦 → 直接走 [[re-memdump]] 转储。
2. **断点/单步/条件断点**:
```
(gdb) file ./target
(gdb) b *0x401000 # 地址断点
(gdb) b sym.check if argc == 2 # 条件断点
(gdb) r arg1 arg2 # 运行并传参
(gdb) ni / si # 单步(跳过/进入调用)
(gdb) c # 继续
(gdb) info b # 列出断点
```
带参数动态分析命令: `gdb -q -ex 'b main' -ex 'r' -ex 'x/10i $rip' ./target`
- 数据断点: `watch *(int*)0x601000`(写触发)/ `rwatch`(读触发)——查密钥写入时刻/解密落点
- 系统调用断点: `catch syscall openat`——理清文件/网络行为,配合 `commands ... end` 自动打印参数后继续
- 断点命中自动化(不改执行流,批量验证参数):
```
(gdb) b check
(gdb) commands
silent
printf "arg=%s\n", $rdi
continue
end
```
3. **查看/修改内存与寄存器**:
```
(gdb) x/20wx $rsp # 栈上 20 个 word
(gdb) x/s 0x601000 # 字符串
(gdb) p $rax # 寄存器
(gdb) set $rax = 0 # 改寄存器
(gdb) set {int}0x601000 = 0x90909090 # 写内存(绕过校验)
(gdb) find 0x400000, 0x410000, "flag{" # 内存搜索字符串
```
4. **反调试绕过**:
- 改标志位(anti-debug 常见检查点):
```
(gdb) p $eflags
(gdb) set $eflags = $eflags | 0x100 # 置 TF 位
```
- ptrace 自检: `ptrace(PTRACE_TRACEME)` 返回值被检查 → 断在调用点直接 `set $eax = 0`(x86)续跑
- 时间差检测(rdtsc): 先 `p $rax` 记两次调用差值,超阈值即退出——断到比较点 patch 比较寄存器
- 以上修改只影响本次运行,不改文件(需持久化 patch 再动二进制并重新哈希对照)
5. **gcore 转储(默认转储优先)**:
```
(gdb) gcore out
```
或外部命令: `gcore -o out <pid>`(gdb 包附带,含寄存器/线程 ELF notes)
按 [[re-analyze/platform-tips]]「直读 vs 转储」: 默认转储优先;脱壳须等 OEP 解密后再 dump;core 直接 `gdb ./target core` 复盘(`bt` 看崩溃栈、`info proc mappings` 看映射)。
6. **脚本化批处理(-x / python)**:
```
gdb -q -batch -x script.gdb ./target # 非交互跑完整脚本
```
script.gdb 里可含 `commands ... end`、`define` 自定义命令、`python` 内嵌 Python(gdb 内置 Python 解释器,pwndbg/gef 即基于此)——重复性分析(批量打印调用参数、跑通一条路径)固化成脚本复用;交互式分析结论用 `gdb -q -ex ... -ex quit` 一行式落档。
## 跨域联合
- [[re-address-space]]:基址换算(info proc mappings 与链接地址对齐)
- [[re-binary-core]]:工作流第 6 步(Linux 调试器)
- [[re-anti-analysis]]:脱壳验证(断 OEP)与反调试绕过
- [[re-ctf]]:pwn 调试
- [[re-malware]]:Linux 恶意样本动态观察
- 与 [[re-memdump]] 互补(attach 失败→转储)
## 常见坑与陷阱
- **ptrace 被禁 → 转储兜底**:yama ptrace_scope=1 时非父进程 attach 被拒;容器 seccomp 直接杀 attach——不要死磕,按 [[re-analyze/platform-tips]] 转 [[re-memdump]]
- **反调试(ptrace 自检、时间差)**:样本用 `ptrace(PTRACE_TRACEME)` 自检或 rdtsc 时间差检测调试器——先静态定位检查点再断点 patch
- **Wine 进程 attach**:Wine 下 PE 进程是 Linux 进程,gdb 可 attach,但地址空间混 PE 映射与 Wine 结构——按 [[re-analyze/platform-tips]] Linux 分支经验处理(查 `/proc/<pid>/maps` 定位 PE 镜像段)
- 调试器注入痕迹(LD_PRELOAD/环境变量)会被检测——用 `unset env LD_PRELOAD` 类方式清理后 attach
- **时钟对抗分三类**:现象——样本检测到时间异常(计时倍率不对、单步耗时异常、时钟源非预期)后退出或改变行为;原因——时钟对抗分三类:时间倍率检测/单步延迟检测/VM 时间源检测;对策——先判定类别再分别应对:时间倍率类恢复真实时钟或 patch 比较点,单步延迟类用硬件断点减少被测量步数,VM 时间源类按 [[re-analyze/platform-tips]] 沙箱分支的环境指纹思路处理
- **断点失效 ≠ 代码没执行**:现象——在目标地址下断从不触发,误判该路径没跑、直接跳过关键逻辑;原因——四种机制使"断点没断"≠"代码没执行":自修改代码(int3 字节被运行时覆盖或校验)、内存重映射(代码换到新映射、旧地址失效)、异常机制(流程经异常处理路径跳转,不走断点指令)、反调试绕过(样本扫描 0xCC/校验代码段字节后改道);对策——先分四类排查:`x/i` 看断点处是否仍为 int3(自修改)、查 `/proc/<pid>/maps` 比对映射变化(重映射)、在异常上下文里找真实跳转目标(异常机制)、静态先找 0xCC 扫描与段校验点(反调试),再决定换断点位置 / 下内存断点 / patch 检查点(见 [[re-binary-core]] 分析方法论 R17)
- **单步异常 → 查反调试(陷阱旗 / 异常处理)**:现象——`si` 单步时触发未预期的 SIGTRAP/`#DB`,或单步后样本行为跳变(时间差类见"时钟对抗分三类"坑);原因——陷阱旗检测(样本读 TF 位 / 利用单步异常自身做文章)与异常处理机制反调试(int3 由样本自身 handler 接管、SEH 链承担流程跳转、异常即控制流);对策——先排除时间检测,再静态定位 `pushf`/`lahf` 后查 TF 的检查点与 int3 写入点,断 handler 入口看真实流向,patch 检查点或改用硬件断点(见 [[re-binary-core]] 分析方法论 R18)
- 命令速查(断点/内存/脚本/pwndbg-gef 命令族)见 [[commands]];工具特有坑与版本差异见 [[gotchas]]

View File

@@ -0,0 +1,141 @@
# GDB 命令速查与操作序列
gdb 本体 + 增强前端二选一(pwndbg / gef;安装方式见 [[re-gdb]])。命令按族分组;pwndbg/gef 命令以各自官方 README 为准。
## 会话与运行族
| 命令 | 作用 |
|---|---|
| `gdb ./target` / `gdb -q -p <pid>` | 打开程序 / 静默附加 |
| `attach <pid>` / `detach` / `kill` | 附加 / 脱离 / 杀进程 |
| `r <args>` / `r < infile` | 运行并传参 / 输入重定向 |
| `c` / `si` / `ni` | 继续 / 步入 / 步过 |
| `finish` | 跑完当前函数停在返回处 |
| `until <addr>` | 运行到指定行/地址 |
| `set follow-fork-mode child` | 跟随子进程(fork 型样本) |
| `set detach-on-fork off` | fork 后两边都停住 |
| `set disable-randomization on` | 关 ASLR(PIE 地址固定,复盘方便) |
| `handle SIGALRM nostop noprint pass` | 不打断信号(超时类反调试常用) |
## 断点族
| 命令 | 作用 |
|---|---|
| `b *0x401000` / `b sym` / `b file.c:10` | 地址/符号/行断点 |
| `b sym if argc == 2` | 条件断点 |
| `hbreak` | 硬件断点(DR 寄存器,4 个上限) |
| `watch *(int*)0x601000` / `rwatch` / `awatch` | 写/读/读写数据断点 |
| `catch syscall <名>` | 系统调用断点(openat/write 等) |
| `commands ... end` | 命中自动执行(`silent` + printf + continue 批量打参) |
| `condition <n> <expr>` | 给已下断点加条件 |
| `ignore <n> <count>` | 跳过前 N 次命中 |
| `info b` / `disable` / `enable` / `delete` | 断点管理 |
## 内存与寄存器族
| 命令 | 作用 |
|---|---|
| `x/20wx $rsp` | 按格式看内存(`x/s` 字符串、`x/i` 指令、`x/30gx` 8 字节) |
| `p $rax` / `p *(int*)0x601000` | 寄存器/解引用 |
| `set $rax = 0` / `set {int}0x601000 = 0` | 改寄存器/写内存(本次运行内) |
| `find 0x400000, 0x410000, "flag{"` | 内存搜索字符串/字节 |
| `disassemble /r 0x401000` | 反汇编带原始字节 |
| `info registers` / `info proc mappings` | 寄存器全览 / 进程映射 |
| `dump memory out.bin 0x400000 0x401000` | 导出内存区间到文件(供 [[re-memdump]] 分析) |
| `bt` / `frame <n>` / `info locals` / `info args` | 调用栈回溯与帧切换 |
## core 与进程族
| 命令 | 作用 |
|---|---|
| `gcore <file>` | 当前进程转储 core(默认转储优先,见 [[re-memdump]]) |
| `gdb ./target core` | 复盘 core(`bt`、`info proc mappings`、`x/gx $rsp` 起点) |
| `info threads` / `thread <n>` | 线程切换(多线程样本) |
| `info sharedlibrary` | 已加载共享库(断点不命中先看它) |
## pwndbg 命令族(装 pwndbg 后可用)
| 命令 | 作用 |
|---|---|
| `checksec` | NX/Canary/RELRO/PIE 检查 |
| `vmmap` | 内存映射图(PIE 基址、栈/堆/库范围) |
| `heap` / `bins` / `tcache` | 堆结构/空闲链表([[re-exploit]] 分析用) |
| `cyclic 200` / `cyclic -l <pattern>` | 生成/定位偏移(栈溢出定位) |
| `search "str"` / `search -t dword 0xdeadbeef` | 内存搜索 |
| `telescope $rsp` | 栈内容指针链展开 |
| `context` | 寄存器+反汇编+栈上下文(每步自动刷新) |
## gef 命令族(装 gef 后可用)
| 命令 | 作用 |
|---|---|
| `checksec` | 同 pwndbg |
| `context` / `telescope` | 上下文 / 指针链 |
| `xinfo 0x...` | 地址属于哪个映射/符号 |
| `heap bins` / `heap chunks` | 堆结构 |
| `xuntil` | 运行到地址(不设断点) |
## 脚本族(-ex / -x / python)
- 一行式: `gdb -q -ex 'b main' -ex 'r' -ex 'x/10i $rip' -ex quit ./target`
- 批处理: `gdb -q -batch -x script.gdb ./target`(script.gdb 内 `define` 自定义命令 + `commands` 断点组)
- Python: gdb 内置 Python 解释器,`python` 块或 `-ex 'python ...'`——pwndbg/gef 即 gdb Python API 的实现
## 操作序列(组合套路)
### 1. 授权校验比较点定位与绕过(带参数 + 条件断点)
```
gdb -q ./target
b main; r <input> # 带样本输入启动
b strcmp # 或校验函数
commands # 命中自动打印参数
silent
printf "a=%s b=%s\n", $rdi, $rsi
continue
end
c # 收集全部比较参数 → 静态还原校验逻辑
```
### 2. core 复盘(崩溃样本定位)
```
gdb ./target core
bt # 崩溃调用链
info proc mappings # 映射基线(PIE 偏移核对)
x/20gx $rsp # 栈现场
# 需要环境再现场景时用 rr 录制重放(见 [[re-crash-triage]])
```
### 3. pwndbg 堆利用分析(UAF/double free 定位)
```
vmmap # 堆范围
heap # 堆块总览
bins # fastbin/tcache 空闲链状态
# 下断点监控 malloc/free 参数($rdi 地址)对照块链变化
```
### 4. 反调试自检绕过(ptrace 自检 patch)
```
静态定位 ptrace(PTRACE_TRACEME) 调用点([[re-ida]] / [[re-ghidra]])
gdb -q ./target
b *<ptrace返回后指令>; r
set $rax = 0 # 伪造"未被跟踪"
c # 后续比较点同样 patch,或一次性静态改二进制
```
## 实现教训(内化)
- `b *地址` 的 `*` 表示"精确地址"(去符号解析),贴反编译地址时必加;贴文件偏移必须 + ASLR 基址,先 `vmmap`/`info proc mappings` 核对
- `commands` 里 `silent` 不加会每命中打一次 "Breakpoint n..." 噪声;printf 用 gdb 格式(`%s` 要传地址,`$rdi` 即参数)
- 断点不命中 ≠ 代码没执行:先查 `info b` 命中次数、`info sharedlibrary` 模块加载、`x/i` 断点处字节是否还是 int3(自修改代码覆盖)
- gdb 的 `set $reg` 只影响本次运行;要持久化得改二进制并重新哈希对照([[re-patching]])
- Python 脚本里 `gdb.execute("...")` 抛异常会中断脚本,批量跑包 try/except 并打印进度
- `find` 的地址范围参数是 `start, end`(逗号分隔,逗号后可有空格),写错会按错误语法报错——范围先 `info proc mappings` 确认
## 使用注意
- 动态执行默认沙箱([[re-analyze/platform-tips]] 最高原则);attach 失败即转 [[re-memdump]] 转储
- 修改/转储产物 sha256 存档([[re-triage]]);结论写入 [[re-analyze/analysis-contract]]

View File

@@ -0,0 +1,36 @@
# GDB 工具特有坑与边界
## ptrace 权限与沙箱坑
- **yama ptrace_scope**:`/proc/sys/kernel/yama/ptrace_scope` = 1(默认)时非父进程 attach 被拒(`Operation not permitted`)——同属主也不行;`sudo sysctl -w kernel.yama.ptrace_scope=0` 临时放宽(重启还原),或让目标以子进程方式跑(`gdb ./target` 而非 attach)
- **容器 seccomp 拦 ptrace**:docker/沙箱内 attach 常直接失败——不硬磕,走 [[re-memdump]] 转储路线
- **Wine 进程 attach**:Wine 下 PE 进程是 Linux 进程可 attach,但地址空间混 PE 映射与 Wine 结构——`/proc/<pid>/maps` 定位 PE 镜像段(wine 版本/位数不同基址不同),反调试与进程模型按 Linux 侧处理
## 断点机制坑(断点失效 ≠ 代码没执行)
- **自修改代码覆盖 INT3**:壳/自解密运行时把断点字节改写——`x/i` 看断点处还是不是 0xCC;解密完成后重新下断
- **内存重映射**:代码换到新映射(`mmap`/`mprotect` 后),旧地址失效——`info proc mappings` 前后对照
- **异常路径跳转**:流程经异常处理(handler/SEH)走,不经过断点指令——在 handler 入口下断看真实流向
- **0xCC 扫描检测**:样本扫描断点字节/校验代码段后改道——静态先找扫描点(见 [[re-anti-analysis]] 反调试方法论)
## 反调试对抗坑
- **ptrace 自检**:`ptrace(PTRACE_TRACEME)` 返回值检查——断调用返回后 `set $eax=0`;注意一次 ptrace 会话只能 attach 一次,gdb 已占用后样本再 ptrace 会失败,这本身就是检测点
- **rdtsc 时间差**:单步延迟被测量——降低单步频率、改用硬件断点减少被测量步数,或 patch 比较点
- **陷阱旗(TF)检测**:`si` 触发莫名 SIGTRAP/`#DB`,或单步后行为跳变——静态找 `pushf`/`lahf` 后查 TF 的检查点(见 SKILL.md 坑)
- **信号被样本接管**:`handle SIGTRAP nostop` 之类改动要谨慎——样本可能利用单步异常自身做控制流
- **时序/多线程竞态**:断点命中时机影响行为(多线程边跑边下断会错过)——先 `Ctrl+C`/`interrupt` 暂停再下断
## 环境与版本坑
- **PIE/ASLR 地址漂移**:无符号样本每次运行地址变——`set disable-randomization on` 固定;复盘 core 时先 `info proc mappings` 求偏移再对反编译地址
- **pwndbg 与 gef 冲突**:同时装 = 初始化脚本互相干扰或后装覆盖前装,常见残留 Python 报错——二选一;gef 与 legacy `./setup.sh` 版 pwndbg 都写 `~/.gdbinit`,切换前先清旧文件,portable 版 pwndbg 走包装脚本不占 `~/.gdbinit`
- **pwndbg 依赖版本**:pwndbg 依赖较新的 gdb(Python 3 API);发行版自带 gdb 过旧时安装或加载会报错——先 `gdb --version` 核对(如 Debian 老版本自带 gdb 10.x 与新版 pwndbg 不兼容)
- **gdb 版本差异**:`catch syscall` 需 Linux gdb(macOS 的 lldb 走 `[[re-lldb]]`);`dump memory`/`gcore` 各版本行为一致但文件名默认带 pid
- **LD_PRELOAD/环境注入痕迹**:调试器注入的 `LD_PRELOAD` 可被检测——`unset env LD_PRELOAD` 类方式清理后 attach;样本自身依赖 `LD_PRELOAD` 时先记录原始值
## 使用注意
- 动态执行默认沙箱 + 网络隔离([[re-analyze/platform-tips]] 最高原则);attach 失败即转 [[re-memdump]]
- 修改只影响本次运行;持久化 patch 后重新 sha256 对照([[re-triage]] / [[re-patching]])
- 结论写入 [[re-analyze/analysis-contract]];工具版本差异以目标环境实际行为为准