pwndbg
Pwndbg 拥有许多强大的功能。你可以随时通过输入 pwndbg
命令来查看所有可用命令的列表。以下是一些易于通过屏幕截图展示的小功能子集。
参数
所有函数调用点都标注了这些函数的参数。这在调试符号的情况下效果最佳,但也适用于最常见的情况,即使用导入的函数(例如通过 GOT 或 PLT 的 libc 函数)。
上下文
每次 GDB 停止时(例如断点或单步执行),都会打印当前执行上下文的实用摘要,显示所有寄存器、堆栈、调用帧、反汇编,以及递归地解引用所有指针。所有内存地址都根据它们表示的内存类型进行颜色编码。
可以使用 set context-output /path/to/file
将上下文输出重定向到文件(包括其他 tty),同时保留其他输出。
拆分/布局上下文
可以使用 contextoutput
命令将上下文部分分布在不同的 tty 中。
示例:contextoutput stack /path/to/tty true
可以使用 Python 在启动 pwndbg 时创建 tmux 布局,并将上下文分布在拆分中。
python
import atexit
import os
from pwndbg.commands.context import contextoutput, output, clear_screen
bt = os.popen('tmux split-window -P -F "#{pane_id}:#{pane_tty}" -d "cat -"').read().strip().split(":")
st = os.popen(F'tmux split-window -h -t {bt[0]} -P -F '+'"#{pane_id}:#{pane_tty}" -d "cat -"').read().strip().split(":")
re = os.popen(F'tmux split-window -h -t {st[0]} -P -F '+'"#{pane_id}:#{pane_tty}" -d "cat -"').read().strip().split(":")
di = os.popen('tmux split-window -h -P -F "#{pane_id}:#{pane_tty}" -d "cat -"').read().strip().split(":")
panes = dict(backtrace=bt, stack=st, regs=re, disasm=di)
for sec, p in panes.items():
contextoutput(sec, p[1], True)
contextoutput("legend", di[1], True)
atexit.register(lambda: [os.popen(F"tmux kill-pane -t {p[0]}").read() for p in panes.values()])
end
如果你喜欢简单,可以尝试使用 splitmind 进行配置
注意上面的例子使用了 splitmind 和以下配置:
python
import splitmind
(splitmind.Mind()
.tell_splitter(show_titles=True)
.tell_splitter(set_title="Main")
.right(display="backtrace", size="25%")
.above(of="main", display="disasm", size="80%", banner="top")
.show("code", on="disasm", banner="none")
.right(cmd='tty; tail -f /dev/null', size="65%", clearing=False)
.tell_splitter(set_title='Input / Output')
.above(display="stack", size="75%")
.above(display="legend", size="25")
.show("regs", on="legend")
.below(of="backtrace", cmd="ipython", size="30%")
).build(nobanner=True)
end
观察表达式
您可以添加要由上下文观察的表达式。 这些表达式会在每次上下文刷新时进行评估和显示。
可以通过 contextwatch
命令(别名为 ctx-watch
和 cwatch
)添加表达式。
默认情况下,表达式会以调试语言进行解析和评估,并可以使用以下方式添加:
contextwatch BUF
ctx-watch ITEMS[0]
或者,可以通过使用可选的 cmd
参数(值为 execute
)来提供要执行的任意 gdb 命令,并在上下文中打印结果:
contextwatch execute "ds BUF"
cwatch execute "x/20x $rsp"
Ghidra
借助 radare2 或 rizin 可以显示 ghidra 反编译器的反编译源代码。
但是,这需要一些先决条件。
-
首先:你必须安装了 radare2 或 rizin,并且 gdb 必须能够找到它(在路径中)
-
其次:你必须为 radare2 安装 ghidra 插件 r2ghidra 或为 rizin 安装 ghidra 插件 rz-ghidra
-
第三:必须在 gdb 使用的 python 上下文中安装 r2pipe(或者,如果您使用的是 rizin,请安装 rzpipe)
可以通过将 ghidra
添加到 set context-sections
或手动调用 ctx-ghidra [function]
来将反编译的源代码显示为上下文的一部分。
请注意,对 radare2/r2ghidra 和 rizin/rz-ghidra 的第一次调用都相当慢!后续对反编译源代码的请求会更快。而且它确实会占用一些资源,因为 r2pipe/rzpipe 会保留 radare2/rizin 实例以启用更快的后续分析。
考虑到这些性能损失,不总是启动它是合理的。因此,它包含一个选项,仅在需要时使用 set context-ghidra
启动它:
set context-ghidra always
:始终触发 ghidra 上下文set context-ghidra never
:除了手动调用时,从不触发 ghidra 上下文set context-ghidra if-no-source
:如果没有可用的源代码,则调用 ghidra
备注:插件会尝试猜测正确的当前行并用 “–>” 标记它,但它可能会出错。
反汇编
Pwndbg 使用 Capstone Engine 来显示反汇编指令,但也利用其对指令的内省来提取内存目标和条件代码。
所有绝对跳转都被折叠起来,只显示相关的指令。
此外,如果当前指令是条件指令,Pwndbg 会显示它是否被评估,用绿色复选标记或红色 X 标记,并根据需要折叠指令。
模拟
Pwndbg 利用 Unicorn Engine 来仅显示将实际被模拟的指令。在每个调试器停止时(例如断点或单步执行),接下来的几条指令会被静默地模拟,并且只显示将实际执行的指令。
这在单步执行跳转表、PLT 条目,甚至在 ROPping 时都非常有用!
堆检查
Pwndbg 通过一些内省函数来启用对 glibc 分配器 ptmalloc2 的内省。
IDA Pro 集成
Pwndbg 将传统的 IDA Pro 集成颠倒过来。与其将代码粘贴到 IDA 中需要您进行交互,不如通过在 IDA 中安装一个小的 XMLRPC 服务器,Pwndbg 可以完全访问 IDA 知道的一切。
这允许提取注释、反编译的源代码行、断点和同步调试(单步执行会更新 IDA 中的光标)。
由于公开了完整的 IDA API,因此可以基于此功能构建新工具,以进一步增强 Pwndbg 的实用性。
您还可以连接到托管在不同机器上的 Ida Pro XMLRPC 服务器。为了实现它,您需要更改:
- Ida Pro XMLRPC 服务器主机(在 ida_script 中;默认情况下它绑定到 localhost)
- 负责连接的配置参数(参见
config
命令)
配置、自定义
有两个命令可以设置各种选项:
-
theme
- 设置特定的输出颜色/样式 -
config
- 设置参数,例如是否模拟当前指令附近的代码、ida rpc 连接信息、十六进制转储字节/宽度(等等)
当然,您可以在 pwndbg 初始化后生成它并将其放入 .gdbinit
中,以使其在 pwngdb 会话之间保持持久性。
这可以通过 configfile
/themefile
命令看到和实现。
QEMU 兼容性
Pwndbg 旨在与最小实现或其他调试器不友好的 GDB 串行协议实现一起使用。其中一个实现是 QEMU 用户模式仿真 (qemu-user
) 使用的实现,CTF 玩家经常使用它来执行和调试跨架构二进制文件。
Vanilla GDB、PEDA 和 GEF 在这种情况下都表现糟糕。
GEF
PEDA
Vanilla GDB
Pwndbg
但是,Pwndbg 绕过了 GDB 存根的限制,为您提供了尽可能最好的调试器环境。
进程状态检查
使用 procinfo
命令来检查当前进程状态,例如 UID、GID、组、SELinux 上下文和打开的文件描述符!Pwndbg 在远程 GDB 调试(例如使用 Android 手机)中尤其出色,而 PEDA、GEF 和 vanilla GDB 在这种情况下会阻塞。
ROP Gadgets
Pwndbg 通过进程中的实际地址使使用 ROPGadget 变得容易。
只需使用 rop
命令!
搜索
Pwndbg 使搜索目标内存空间变得容易,它具有完整且易于使用的界面。无论您是在搜索字节、字符串,还是各种大小的整数值或指针,只需一个简单的命令即可。
查找泄漏
可以使用
leakfind
命令查找泄漏链。它递归地检查地址范围中的指针,并报告找到的所有指针。
望远镜
使用 telescope
命令可以轻松检查内存转储。它递归地解引用一个内存范围,让您一次看到所有内容。作为额外的奖励,Pwndbg 会检查所有可用的寄存器,看看它们是否指向内存范围。
虚拟内存映射
Pwndbg 增强了标准内存映射列表,并允许轻松搜索。
Windbg 兼容性
Pwndbg 具有完整的 windbg 兼容层。您可以随心所欲地使用 dd
、dps
、eq
,甚至 eb eip 90
。
- 高级词汇注释:
- introspection¹ [/ɪntrəˈspɛkʃən/] (n.) 内省;反省 指的是检查程序自身结构和状态的能力。
- dereferencing² [/ˌdiːˈrɛfərənsɪŋ/] (n.) 解引用 指的是通过指针访问其指向的内存位置。
- emulation³ [/ˌemjuˈleɪʃən/] (n.) 仿真;模拟 指的是在一个系统上模仿另一个系统的行为。
- allocator⁴ [/ˈæləkeɪtər/] (n.) 分配器 指的是负责动态分配内存的程序模块。