x64dbg 插件开发指南:_plugin_logputs 日志输出 API 深入解析
2026/9/19 12:52:14 网站建设 项目流程

x64dbg 插件开发指南:_plugin_logputs 日志输出 API 深入解析

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

_plugin_logputs是 x64dbg 为插件开发者提供的核心日志输出接口,用于向 x64dbg 主界面的日志窗口(Log Window)打印一行文本。本指南以官方 API 文档 logputs.rst 为主体骨架,深入源码剖析其底层实现链路、与_plugin_logprintf等姊妹 API 的区别、以及基于_plugin_logputs的 UTF-8 日志输出最佳实践。读完本文,你将能够在自己的 x64dbg 插件中正确、安全、高效地向日志窗口输出调试信息。

函数签名与基本用法

_plugin_logputs的原型定义如下(见 logputs.rst):

void _plugin_logputs( const char* text //text to print );

参数说明

参数类型含义
textconst char*要写入日志窗口的文本。该文本可以包含换行符(line breaks),也就是说你可以一次性传入多行内容。

返回值

该函数没有返回值(void),且不存在失败时的错误码或错误标志——调用后文本即被异步提交到日志窗口。正因如此,_plugin_logputs非常适合在无需关心返回状态的场景中直接调用,例如回调处理函数中的信息打印。

最小可运行示例

在 x64dbg 插件中,最常见的调用场景是在pluginit之后、任意回调或命令处理函数中输出状态信息:

extern "C" __declspec(dllexport) void CBMENUENTRY(CBTYPE cbType, PLUG_CB_MENUENTRY* info) { _plugin_logputs("MyPlugin: menu entry clicked"); }

输出结果会以独立的一行出现在 x64dbg 的Log 视图中,用户可以通过视图 → Log(或快捷键)随时查看。

源码级实现:从插件导出到日志窗口的完整调用链

_plugin_logputs并不是一个孤立函数,它在 x64dbg 源码中的实现横跨「插件导出层 → 控制台输出层 → GUI 异步桥接层」三级,理解这条链路有助于你判断它在何时何地调用是安全的。

第一步:插件 API 导出包装(src/dbg/_plugins.cpp

x64dbg 将所有_plugin_前缀的 API 集中实现在 src/dbg/_plugins.cpp 中,并在 src/dbg/_plugins.h 中对外声明。_plugin_logputs的实现仅有一行,直接转发给调试器核心的控制台输出函数:

// src/dbg/_plugins.cpp:51 PLUG_IMPEXP void _plugin_logputs(const char* text) { dputs_untranslated(text); }

注意函数名中的_untranslated后缀:这意味着_plugin_logputs不会对文本执行 x64dbg 的翻译(GUI Translate)处理,它打印的是插件提供的原始文本,而不是查表翻译后的文本。这与调试器内部使用的dputs(会先调用GuiTranslateText再输出)形成鲜明对比。

第二步:控制台输出层(src/dbg/console.cpp

dputs_untranslated定义于 src/dbg/console.cpp:

void dputs_untranslated(_In_z_ const char* Text) { GuiAddLogMessageAsync(Text); // Only append the newline if the caller didn't if(*Text && Text[strlen(Text) - 1] != '\n') GuiAddLogMessageAsync("\n"); }

这里有两个关键行为值得注意:

  1. 自动补换行dputs_untranslated会检查文本末尾是否已经是\n,如果没有则自动追加一个换行符,保证日志窗口中的输出总是以完整的一行呈现。这正是文档中「prints a single line to the log window」的底层保障。
  2. 异步派发:文本通过GuiAddLogMessageAsync提交,这是一个基于StringConcatTaskThread_的异步任务(见 src/dbg/console.cpp),它把字符串拼接任务交给后台任务线程处理,最终调用桥接函数GuiAddLogMessage将消息送达 GUI 进程。这意味着_plugin_logputs的调用开销极小,且不会阻塞调用线程——即使 GUI 暂时繁忙,日志也会在后台排队输出。

第三步:与桥接层的关系

GuiAddLogMessage是 x64dbg 调试器(dbg 进程)与 GUI 进程之间的桥接(bridge)函数之一,定义在 src/bridge/bridgemain.h 等桥接头文件中。插件调用_plugin_logputs时,最终消息会通过该桥接通道异步传送到 GUI 的 Log 视图。这一设计使得插件可以在调试回调(如断点命中回调)中安全地打印日志,而无需担心与 GUI 线程的同步竞争问题。

与 _plugin_logprintf 的区别与选型建议

x64dbg 还提供了格式化的日志 API_plugin_logprintf(见 logprintf.rst),两者在 src/dbg/_plugins.cpp 中共享同一套输出通道:

PLUG_IMPEXP void _plugin_logprintf(const char* format, ...) { va_list args; va_start(args, format); dprintf_args_untranslated(format, args); va_end(args); }
API签名适用场景
_plugin_logputs(text)单个字符串输出静态或已拼接完成的文本、多行文本
_plugin_logprintf(format, ...)printf 风格变参需要格式化数值、地址(如%p%llx)、混排字符串时

选型建议:

  • 需要打印寄存器值、内存地址或整数时,优先使用_plugin_logprintf,例如_plugin_logprintf("RIP = %p\n", rip);
  • 需要输出多行、或整段拼接好的信息时,优先使用_plugin_logputs,因为它天然支持文本中的换行符,且不会对文本做任何解释处理;
  • 若你的插件需要输出富文本(HTML 格式的着色日志),可以进一步了解_plugin_lograw_html(实现在 src/dbg/_plugins.cpp)。

使用_plugin_logputs输出 UTF-8 文本的注意事项

x64dbg 的日志窗口对文本编码有明确要求:日志输出期望的是 UTF-8 编码的字节流。虽然_plugin_logputs直接透传文本、不做翻译,但若传入的是本地代码页(如中文环境下的 GBK/CP936)编码的字符串,日志窗口可能出现乱码。

推荐做法是:在插件中统一使用 UTF-8 编码的字符串字面量,或在输出前将宽字符串转换为 UTF-8。例如:

#include <string> // 假设从界面控件取得宽字符串文本 void logWideText(const std::wstring& wtext) { // 转换为 UTF-8 后再交给 _plugin_logputs(此处示意,可结合项目实际的转换工具函数) std::string utf8text(wtext.begin(), wtext.end()); _plugin_logputs(utf8text.c_str()); }

在真实测试与插件回调中的典型用法

x64dbg 仓库自带的测试插件(src/tests/)大量使用了_plugin_logputs来输出断言与状态信息,是学习其实际调用姿势的第一手材料:

  • 在 src/tests/database_callbacks/plugin.cpp 中,测试插件在数据库操作回调(CB_DBOPERATION/CB_DBLOADOPERATION)里将拼接好的文本通过_plugin_logputs(text.c_str())输出,用于验证数据库回调事件的触发顺序与内容正确性;
  • 在 src/tests/issue3808/plugin.cpp 中,回归测试插件用_plugin_logputs("[issue3808] Priming ZF=1 CF=0 through the command path")输出测试执行路径标记,配合断言日志实现回归验证。

此外,调试器自身的命令处理代码也会调用_plugin_logputs输出错误提示,例如 src/dbg/commands/cmd-analysis.cpp 中analx相关命令在参数不足、重定位表无效时输出错误信息。这说明该 API 不仅在插件生态中使用,也是 x64dbg 内部命令层向用户呈现消息的标准通道之一。

与测试框架的结合

_plugin_logputs输出的内容会进入与用户可见的同一日志窗口。对于编写自动化回归测试的开发者而言,可以在测试脚本(仓库 src/tests/run.py 驱动的自动化流程)中解析 Log 输出,以此断言插件行为是否符合预期——这正是上述 issue 回归测试插件的使用模式。

线程安全与调用时机

结合前面的源码分析,可以总结出以下实践要点:

  1. 任意线程可调用:由于输出通过异步任务线程派发,_plugin_logputs不要求在特定线程(如 GUI 线程)中调用,调试回调线程、命令处理线程中均可安全使用;
  2. 不阻塞调试流程:日志写入是异步的,不会因为 GUI 渲染缓慢而拖慢断点回调等关键路径;
  3. 结尾换行自动处理:文本末尾无\n时自动补齐,因此不需要手动拼接换行;但如果你传入的文本以\n结尾(如多行文本最后一行),则不会重复追加空行;
  4. 不要传入空指针dputs_untranslated内部会调用strlen(Text),传入nullptr会导致未定义行为,调用前请确保text非空。

总结

维度结论
原型void _plugin_logputs(const char* text);(见 logputs.rst)
行为向日志窗口异步输出一行文本,文本可含换行,末尾自动补\n
实现位置src/dbg/_plugins.cpp → src/dbg/console.cpp
编码要求传入 UTF-8 编码文本
返回值
适用场景输出整段/多行/静态文本;格式化输出请用_plugin_logprintf

_plugin_logputs是 x64dbg 插件开发中最常用、最基础的日志 API 之一。理解它的源码实现,不仅能帮助你写出更健壮的插件日志代码,也能让你在调试插件行为、阅读其他插件源码(以及 x64dbg 自身命令源码)时更加得心应手。后续如需深入了解插件 API 全貌,可继续阅读 插件 API 索引 与 插件开发基础。

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

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

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

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

立即咨询