Pwndbg contextunwatch 命令详解:从 context 中移除监视表达式
【免费下载链接】pwndbgExploit Development and Reverse Engineering with GDB & LLDB Made Easy项目地址: https://gitcode.com/GitHub_Trending/pw/pwndbg
本篇文章围绕 pwndbg 的contextunwatch(别名ctx-unwatch/cunwatch)命令展开,讲解如何通过编号移除由contextwatch(cwatch)添加的、显示在 context 输出expressions区块中的监视表达式。读完本文后,你将掌握监视表达式的添加、编号查看与按编号删除的完整流程,并理解其底层实现与相关配置。
命令概览
contextunwatch用于删除一个此前被加入监视的表达式,是contextwatch的逆向操作。它归属于 pwndbg 的 CONTEXT 命令类别,完整用法如下:
usage: contextunwatch [-h] num命令参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
num | 必填,整数 | 要从 context 中移除的表达式编号(从 1 开始) |
-h/--help | 可选 | 显示帮助信息并退出 |
该命令拥有两个别名,与cwatch(contextwatch的别名)一一对应:
ctx-unwatchcunwatch
在实际调试中,你可以使用cunwatch代替完整命令,例如:
cunwatch 1与 contextwatch 的配套关系
contextunwatch本身并不独立存在,它的完整语义必须结合 contextwatch 来理解。
contextwatch命令的作用是添加一个要在 context 上显示的表达式:
usage: contextwatch [-h] [{eval,execute}] expression它支持两种模式:
| 模式 | 说明 |
|---|---|
eval(默认) | 表达式按被调试语言进行解析求值,结果内联显示 |
execute | 表达式作为一条 GDB 命令执行,输出显示在下一行 |
典型用法:
# 监视变量/表达式 cwatch BUF cwatch ITEMS[0] # 执行命令 cwatch execute "ds BUF" cwatch execute "x/20x $rsp" cwatch execute "info args"一旦添加成功,监视项会集中显示在context输出的expressions区块中。要移除其中某个监视项,就使用cunwatch并指定其编号:
cunwatch 2contextwatch的文档中同样明确写道:"To remove an expression, seecunwatch.",二者构成一对完整的增删操作。
编号规则与使用示例
监视表达式的编号从1开始,按添加顺序递增。假设你依次执行了:
cwatch $rip cwatch execute "p/z $rsp" cwatch BUF那么context的expressions区块会大致显示为:
[ EXPRESSIONS ] 1: $rip = 0x7ffff7d7852e 2: p/z $rsp $1 = 0x7ffffffde500 3: BUF = 0x7ffffffde570此时:
cunwatch 2会移除第 2 项(execute "p/z $rsp"),剩余的$rip与BUF自动重新编号为 1 和 2。
info args类的execute监视同样适用。下图展示了cwatch execute "info args"添加到 context 后,expressions区块中以1: info args为标题、逐行输出参数的典型效果:
边界与容错
- 编号必须落在有效区间
1 <= num <= len(expressions)内; - 若传入非法编号(如
0、负数或大于监视项总数的数字),命令不会崩溃,而是输出错误提示Invalid input并直接返回; - 传入非整数参数时由 argparse 负责解析并报错退出。
源码实现解析
contextunwatch的实现位于 pwndbg/commands/context.py,核心代码非常精简:
expressions = [] @pwndbg.commands.Command( parser, aliases=["ctx-unwatch", "cunwatch"], category=CommandCategory.CONTEXT ) def contextunwatch(num: int) -> None: if num < 1 or num > len(expressions): print(message.error("Invalid input")) return expressions.pop(int(num) - 1)可以提炼出三个实现要点:
- 全局列表存储:所有监视项保存在模块级全局变量
expressions(context.py#L569)中,元素为(expression, cmd)二元组。contextwatch通过expressions.append((expression, cmd))追加,contextunwatch通过expressions.pop(...)删除。 - 1 基索引:命令要求用户传入的编号从 1 开始,内部删除时换算为
int(num) - 1作为列表下标,与用户直觉保持一致。 - 边界校验:删除前先检查
num是否在[1, len(expressions)]区间内,越界时打印红色错误信息Invalid input,避免IndexError泄漏给用户。
监视项的展示由context_expressions(context.py#L630)负责:遍历expressions,以f"{i + 1}: {ctx_color.highlight(exp)}"生成带编号的标题行;eval模式下将求值结果以= value内联到同一行,execute模式下将命令输出追加到下一行;表达式求值失败时捕获gdb.error并把错误信息作为值展示。
expressions 区块与相关配置
expressions是 context 输出中的独立区块。在默认配置context-sections中它被默认启用:
regs disasm code ghidra stack backtrace expressions threads heap_tracker last_signal该配置项在 pwndbg/commands/context.py#L177-L181 中定义,既决定了区块是否显示,也控制其顺序。
调试中你可能想单独操作这个区块:
- 只显示
expressions区块:context expressions - 临时隐藏
expressions区块:context --off expressions - 重新显示:
context --on expressions - 查看所有 context 相关配置:
config context
context命令的完整用法可参考 context 命令文档,区块开关逻辑见 context.py#L726-L738。
值得注意的一个细节:context_expressions带有@serve_context_history装饰器,这意味着 expressions 区块的快照也会进入 context 历史,供contextprev/contextnext回溯查看(见 context.py#L629-L667)。
测试验证
仓库的集成测试 tests/library/dbg/tests/test_context_commands.py 对cwatch与cunwatch的完整生命周期做了验证:
# Check if cwatch expressions are also stored in the history gdb.execute("cwatch $rip") gdb.execute("cwatch execute 'p/z $rsp'") fourth_ctx = gdb.execute("ctx", to_string=True) assert "1: $rip = " in fourth_ctx assert "2: p/z $rsp\n$1 = 0x" in fourth_ctx gdb.execute("cunwatch 2") gdb.execute("cunwatch 1")该测试(test_context_commands.py#L581-L605)覆盖了以下行为:
cwatch $rip以1: $rip = <值>的形式显示;cwatch execute 'p/z $rsp'以2: p/z $rsp标题加$1 = 0x...输出行的形式显示;- 监视项会进入 context 历史,
contextprev回溯时重新展示旧的 GDB 变量(如$1); - 最终按编号
cunwatch 2、cunwatch 1依次删除,验证了从尾部到头部按编号移除的路径。
总结
contextunwatch是 pwndbg context 监视体系中的"删除端",与contextwatch配合可实现监视表达式的动态管理:
- 添加:
cwatch <表达式>或cwatch execute "<命令>" - 查看编号:直接执行
context(或ctx)查看expressions区块中每行的N:前缀 - 删除:
cunwatch <编号>,编号从 1 开始,非法编号会得到Invalid input提示
从源码看,其实现基于全局expressions列表与 1 基索引的pop操作,逻辑简单可靠;从测试看,它与 context 历史、多监视项共存等特性协同良好。掌握这一命令,你就能在长会话调试中随时增删观察项,让 context 输出始终聚焦于当前最关心的数据。
【免费下载链接】pwndbgExploit Development and Reverse Engineering with GDB & LLDB Made Easy项目地址: https://gitcode.com/GitHub_Trending/pw/pwndbg
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考