pwndbg patch-revert 命令详解:撤销运行时指令补丁与恢复原始内存
pwndbg patch-revert 命令详解撤销运行时指令补丁与恢复原始内存【免费下载链接】pwndbgExploit Development and Reverse Engineering with GDB LLDB Made Easy项目地址: https://gitcode.com/GitHub_Trending/pw/pwndbgpatch-revert是 pwndbg 中用于撤销patch命令所打补丁的核心配套命令它通过回写补丁前保存的原始字节将目标地址的内存恢复到补丁前的状态。本文基于仓库文档与 patch.py 源码完整讲解patch-revert的用法、参数、批量回滚机制与底层实现原理帮助你在动态调试、绕过校验、指令级热修改等场景中安全地“反悔”任何已写入的内存修改。命令概览usage: patch-revert [-h] addresspatch-revert需要一个位置参数address要回滚补丁的目标地址执行后会把该地址的指令字节恢复为调用patch之前的内容。位置参数说明address要回滚补丁的地址Address to revert patch on可选参数说明-h,--help显示本命令的帮助信息并退出该命令的完整参数定义位于 patch.py 中的parser2parser2 argparse.ArgumentParser(descriptionRevert patch at given address.) parser2.add_argument(address, typeint, helpAddress to revert patch on)它与patch、patch-list同属于 MISC杂项命令类别对应文档见 patch.md 与 patch-list.md。补丁生命周期patch → patch-list → patch-revertpatch-revert本身并不独立完成“修改”动作它依赖patch命令建立的回滚记录。三者构成完整的补丁管理闭环patch address ins将ins汇编为机器码写入指定地址并在内部记录“原始字节 → 新字节”的映射patch-list列出当前会话中所有尚未回滚的补丁及其前后指令patch-revert address按地址回滚单个补丁传-1则一次回滚全部。值得注意的是补丁记录仅存在于当前 GDB/LLDB 会话内存中进程重启或调试会话结束后即失效因此patch-revert必须在同一会话内、对仍存活的调试目标使用。源码实现回滚是如何工作的补丁记录的存储结构在 patch.py 中所有补丁被保存在模块级字典里# Keep old patches made so we can revert them patches: dict[int, tuple[bytes, bytes]] {}键是补丁地址int值是(old_mem, new_mem)二元组old_mem是打补丁前从目标地址读出的原始字节new_mem是汇编后写入的新字节。当patch命令执行时patch.py它会依次完成汇编、读取原值、记录映射、写入内存四个步骤new_mem pwndbg.aglib.asm.asm(ins) # 1. 汇编指令 old_mem pwndbg.aglib.memory.read(address, len(new_mem)) # 2. 读取原字节 patches[address] (old_mem, new_mem) # 3. 记录回滚信息 pwndbg.aglib.memory.write(address, new_mem) # 4. 写入新字节 pwndbg.lib.cache.clear_caches() # 清理缓存其中汇编通过 asm.py 委托给pwndbg.lib.zig.asm由 Zig 工具链根据当前调试目标的架构如 x86-64、aarch64、mips 等完成交叉汇编相关架构映射见 zig.py。patch-revert 的三种分支patch_revert的完整逻辑位于 patch.py共覆盖四种情况def patch_revert(address: int) - None: if not patches: print(message.notice(No patches to revert)) return if address -1: for addr, (old, _new) in patches.items(): pwndbg.aglib.memory.write(addr, old) print(message.notice(fReverted patch at {addr:#x})) patches.clear() elif address in patches: old, _new patches.pop(address) pwndbg.aglib.memory.write(address, old) print(message.notice(fReverted patch at {address:#x})) else: print(message.error(fAddress {address:#x} not found in patch list)) pwndbg.lib.cache.clear_caches()无补丁记录若patches为空直接输出提示No patches to revert并返回不做任何内存写入address -1批量回滚遍历字典中所有地址逐一写回old原始字节并打印Reverted patch at 0x...随后patches.clear()清空全部记录。这是“一次撤销所有补丁”的快捷入口常用于结束调试会话前的整体清理命中单个地址从字典中pop出该地址的记录写回原始字节实现精准回滚地址不存在输出Address 0x... not found in patch list错误提示不做任何修改。无论成功与否在无记录提前返回的路径之外函数末尾都会调用pwndbg.lib.cache.clear_caches()清空 pwndbg 的各类缓存确保后续disasm、telescope等命令读取到的是回滚后的真实内存而不是缓存中的旧数据。这一点在 test_context_commands.py 中有对应的验证逻辑——该测试通过patch $rip5 nop;...修改指令后断言反汇编输出确实变为nop印证了补丁写入与缓存清理的实际效果。关于“连续补丁同一地址”的注意事项从数据结构上看patches[address] (old_mem, new_mem)是覆盖式赋值若你在同一地址上先后打了两次补丁第二次执行patch时读取到的old_mem是第一次补丁后的字节因此记录被覆盖为“第一次补丁后的状态 → 第二次补丁后的状态”。此时执行patch-revert恢复到的是最近一次补丁前的状态而非最初的原始指令。若需要精确回退多步请为不同的地址分别打补丁或及时patch-revert后再进行下一次修改。实战示例假设正在调试一个 x86-64 程序需要临时绕过某处分支判断然后恢复原状pwndbg patch $rip5 nop;nop;nop;nop;nop Patched 5 bytes at 0x5555555551c5 pwndbg patch-list ────────────────────────────────────[ Patches: ]──────────────────────────────────── 0x5555555551c5 (5 bytes) from: mov edi, 0x1337; mov esi, 0xdeadbeef to : nop; nop; nop; nop; nop pwndbg patch-revert 0x5555555551c5 Reverted patch at 0x5555555551c5批量回滚所有补丁pwndbg patch-revert -1 Reverted patch at 0x5555555551c5 Reverted patch at 0x555555555200对未打补丁的地址执行回滚则会得到错误提示pwndbg patch-revert 0x555555555300 Address 0x555555555300 not found in patch list适用前提与限制patch-revert带有OnlyWhenRunning装饰器见 patch.py仅在调试会话正在运行时可用未附加/启动目标时无法执行回滚依赖会话内的patches记录切换目标、重启调试会话或目标进程退出后记录即丢失address参数使用 Pythonint解析支持0x...十六进制与$reg寄存器表达式-1被保留为“全部回滚”的特殊值因此无法用于回滚地址恰为0xFFFFFFFFFFFFFFFF的单条补丁写入依赖调试器对目标内存的可写能力例如在 qemu-user 的某些旧版本下可能受限参见 test_aarch64.py 中关于 qemu-user 8.2.2 不支持 GDB 写内存的说明。延伸阅读patch.mdpatch命令用法含-q/--quiet静默参数patch-list.mdpatch-list命令用法查看当前全部补丁patch.pypatch、patch-revert、patch-list三个命令的完整源码asm.py 与 zig.py指令汇编与多架构支持实现memory.pymemory.write底层写内存实现【免费下载链接】pwndbgExploit Development and Reverse Engineering with GDB LLDB Made Easy项目地址: https://gitcode.com/GitHub_Trending/pw/pwndbg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考