x64dbg 插件开发指南:使用 GuiDumpAtN 将第 N 个内存转储窗口定位到指定虚拟地址
2026/9/19 20:01:25 网站建设 项目流程

x64dbg 插件开发指南:使用 GuiDumpAtN 将第 N 个内存转储窗口定位到指定虚拟地址

【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg

导读

GuiDumpAtN是 x64dbg 桥接(Bridge)层提供给插件与脚本的 GUI 控制函数之一,用于将指定的第 N 个内存转储(Dump)窗口跳转到给定的虚拟地址va,从而在该窗口中展示该地址处的内存数据。它与单窗口版本的 GuiDumpAt 的区别在于:多了一个index参数,可精确控制目标 Dump 标签页。读完本文,你将掌握该函数的完整调用契约、在桥接层与 Qt GUI 层的完整消息传递链路,以及它在dump命令中的实际用法,从而在自己的插件中实现"把数据定位到指定 Dump 窗口"的能力。

函数签名与核心语义

原文档给出的函数原型如下:

void GuiDumpAtN(duint va, int index)

参数说明

参数类型含义
vaduint要转储(dump)的目标虚拟地址。duint是 x64dbg 定义的无符号整数类型,在 32 位构建下为 32 位、64 位构建下为 64 位,因此该函数在 x32dbg 与 x64dbg 中均可正常工作
indexint目标内存转储窗口的索引编号,即 CPU 视图标签页中 "Dump N" 的N

返回值

该函数不返回任何值void),调用方无法通过返回值获知目标窗口是否存在或操作是否成功;若需要确认结果,只能结合后续的读取操作或日志自行判断。

与 GuiDumpAt 的分工

  • GuiDumpAt:不带索引,把当前活动的Dump 窗口定位到va
  • GuiDumpAtN:带索引index,把指定的第 N 个 Dump 窗口定位到va,并会将该标签页切换为当前页。

调用示例

原文档的示例为占位性质,这里给出可直接编译使用的完整示例。插件在获得PLUG_EXPORT导出的插件实例后,即可在任何上下文(包括调试回调中)调用:

#include "bridgemain.h" // 将第 2 个 Dump 窗口定位到当前 EIP/RIP 指向的地址 void DemoDumpAtCurrentIp() { duint ip = 0; // 获取当前活动线程的程序计数器(x32dbg 中为 EIP,x64dbg 中为 RIP) if(DbgGetRegDumpEx("cip", &ip, sizeof(ip))) { GuiDumpAtN(ip, 2); // 第 2 个 Dump 窗口跳转到当前指令地址 GuiShowCpu(); // 确保 CPU 视图可见 GuiFocusView(GUI_DUMP); // 聚焦到 Dump 视图 } }

va既可以是具体的绝对虚拟地址,也可以来自表达式计算结果(如DbgEval返回的模块基址、变量值等)。因为duint是原生指针宽度,向该函数传递任何合法用户态地址都是安全的。

桥接层实现:一条 GUI 控制消息的诞生

GuiDumpAtN的声明位于桥接头文件 src/bridge/bridgemain.h,实现位于 src/bridge/bridgemain.cpp:

BRIDGE_IMPEXP void GuiDumpAtN(duint va, int index) { _gui_sendmessage(GUI_DUMP_AT_N, (void*)va, (void*)(duint)index); }

可以看到,这个函数本身并不直接操作任何窗口控件,而是把请求封装成一条GUI 消息:消息类型为GUI_DUMP_AT_Nparam1携带虚拟地址vaparam2携带窗口索引index,通过_gui_sendmessage异步投递给 GUI 线程。这正是 x64dbg 调试器核心(dbg 模块)与 GUI(Qt 界面)解耦的典型模式:dbg 侧的任何线程都能安全地发起 GUI 操作,而不必关心 Qt 控件与线程亲和性

消息 ID 与参数类型的对应关系定义在桥接宏中(src/bridge/bridgemain.h):

msg(GUI_DUMP_AT_N, int index, duint va)

该宏声明了消息槽的参数形态,并在桥接层负责把(duint va, int index)的调用参数与消息的两个void*载荷互相转换。

GUI 侧处理:从信号到 Dump 标签页的完整链路

消息到达 GUI 线程后,由 Qt 侧的桥接对象接收。在 src/gui/Src/Bridge/Bridge.cpp 中:

case GUI_DUMP_AT_N: emit dumpAtN((duint)param1, (int)(duint)param2); break;

Bridge类将消息转换为 Qt 信号dumpAtN(duint va, int index)(信号声明见 src/gui/Src/Bridge/Bridge.h)。该信号在 CPU 多转储视图组件中被连接(src/gui/Src/Gui/CPUMultiDump.cpp):

connect(Bridge::getBridge(), SIGNAL(dumpAtN(duint, int)), this, SLOT(printDumpAtNSlot(duint, int)));

最终的槽函数printDumpAtNSlot(src/gui/Src/Gui/CPUMultiDump.cpp)完成了窗口定位动作:

void CPUMultiDump::printDumpAtNSlot(duint va, int index) { int tabindex = GetDumpWindowIndex(index); if(tabindex == 2147483647) return; CPUDump* current = qobject_cast<CPUDump*>(widget(tabindex)); if(!current) return; setCurrentIndex(tabindex); current->printDumpAt(va); current->mHistory.addVaToHistory(va); }

其关键行为可以归纳为四点:

  1. 按名称定位标签页GetDumpWindowIndex(index)(src/gui/Src/Gui/CPUMultiDump.cpp)遍历标签页,寻找 native name 恰好等于"Dump " + index的页签。这说明index语义上与界面标签页标题 "Dump 1"、"Dump 2" 中的数字一一对应;
  2. 静默失败:若找不到对应窗口(返回2147483647,即INT_MAX哨兵值),或对应页签不是CPUDump类型,函数直接返回,不做任何 UI 变更,也不会报错;
  3. 切换当前页setCurrentIndex(tabindex)会先把目标 Dump 标签页设为当前显示页,因此调用后用户会直接看到该窗口被激活;
  4. 刷新与历史记录current->printDumpAt(va)让该窗口滚动到新地址并重新渲染内存字节,mHistory.addVaToHistory(va)则把该地址记入窗口的导航历史,用户可以用回退/前进功能在地址之间往返。

实际入口:dump命令如何复用 GuiDumpAtN

GuiDumpAtN不仅是插件 API,也是内置命令dump的底层实现之一。在 src/dbg/commands/cmd-gui.cpp 的cbDebugDump中:

bool cbDebugDump(int argc, char* argv[]) { if(IsArgumentsLessThan(argc, 2)) return false; duint addr = 0; if(!valfromstring(argv[1], &addr)) { dprintf(QT_TRANSLATE_NOOP("DBG", "Invalid address \"%s\"!\n"), argv[1]); return false; } if(argc > 2) { duint index = 0; if(!valfromstring(argv[2], &index)) { dprintf(QT_TRANSLATE_NOOP("DBG", "Invalid address \"%s\"!\n"), argv[2]); return false; } GuiDumpAtN(addr, int(index)); } else { ACTIVEVIEW activeView; GuiGetActiveView(&activeView); int dumpIndex; if(sscanf_s(activeView.title, "Dump %d", &dumpIndex) == 1) GuiDumpAtN(addr, dumpIndex); else GuiDumpAt(addr); } GuiShowCpu(); GuiFocusView(GUI_DUMP); return true; }

由此可以梳理出dump命令(命令文档)的两种分支行为:

  • 带第三个参数dump <addr> <index>直接把第index个 Dump 窗口定位到addr,内部调用GuiDumpAtN
  • 不带第三个参数:先读取当前活动视图,若活动视图标题形如"Dump N"(即当前正停留在某个 Dump 标签页),则把该窗口编号提取出来交给GuiDumpAtN,从而在当前Dump 窗口中定位;否则回退到GuiDumpAt

addrindex都通过valfromstring解析,因此地址支持 x64dbg 表达式语法(如module.entry、寄存器名、变量等),index也接受表达式计算结果。

与其他相关 API 的配合

在实际插件场景中,GuiDumpAtN常与以下桥接函数配合使用,形成完整的"定位并聚焦"体验:

  • GuiDumpAt:无索引版本,作用于当前 Dump 窗口,适合只需操作一个转储视图的场景;
  • GuiShowCpu():确保 CPU 视图(含 Dump 标签页)处于可见状态;
  • GuiFocusView(GUI_DUMP):把焦点切换到 Dump 视图,GUI_DUMP常量在桥接头文件中定义。

一个实用的组合思路:插件在分析堆、对象或字符串时,先通过DbgMemFindBaseAddr等内存 API 拿到数据所在页基址,再用GuiDumpAtN(base, 1)把主 Dump 窗口定位到该页,配合GuiFocusView(GUI_DUMP)让用户立刻看到数据 —— 整个过程与dump命令的内部路径完全一致,确保插件行为与内置命令保持统一。

注意事项与适用前提

  • 索引从 1 开始:Dump 标签页的命名是 "Dump 1"、"Dump 2" 等,index应传入对应数字;传入不存在或未打开的索引时,GUI 侧会静默返回,不会产生错误提示,插件侧应避免依赖返回值;
  • 线程安全GuiDumpAtN通过桥接消息机制跨线程投递,可从调试回调(如插件命令、断点回调)中直接调用,无需手动切到 GUI 线程;
  • 32/64 位一致性duint按构建位数自适应,无需在插件中区分 x32dbg 与 x64dbg;
  • 行为可预期:调用后目标窗口不仅刷新内容,还会被设为当前标签页并记录导航历史,这一点与用户手动在 GUI 中操作 Dump 窗口的体验一致。

如需了解桥接函数的完整清单,可参阅 开发文档索引 与 GuiDumpAt 的互链关系。

【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询