尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

x64dbg 插件开发核心 API 全指南:`_plugin_` 系列导出函数详解

x64dbg 插件开发核心 API 全指南:`_plugin_` 系列导出函数详解 x64dbg 插件开发核心 API 全指南_plugin_系列导出函数详解【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg导读x64dbg 为插件开发者提供了一套以_plugin_前缀命名的导出函数覆盖调试控制、日志输出、菜单构建、事件回调、命令注册、表达式与格式化函数扩展等全部核心能力。本文以 docs/developers/plugins/API 文档集中的 24 个 API 文档为主体逐一讲解每个函数的签名、参数、返回值与典型应用场景并结合仓库源码src/dbg/_plugins.h、src/dbg/_plugins.cpp、src/bridge/bridgemain.h剖析底层实现原理。读完本文你将能够独立编写出具备菜单、命令、事件监听与表达式扩展能力的完整 x64dbg 插件。一、API 总览插件与调试器之间的桥梁x64dbg 的插件 API 全部以_plugin_前缀导出声明集中定义在头文件 src/dbg/_plugins.h第 411-451 行为extern C导出块实现集中在 src/dbg/_plugins.cpp。它们本质上是调试器内部功能的薄封装层插件调用这些函数后内部会转交到对应的插件管理模块如pluginregistercallback、plugincmdregister、pluginmenuadd等。按照功能用途24 个 API 可分为以下几类分类函数调试控制_plugin_debugpause、_plugin_debugskipexceptions、_plugin_waituntilpaused、_plugin_startscript日志输出_plugin_logprintf、_plugin_logputs菜单构建_plugin_menuadd、_plugin_menuaddentry、_plugin_menuaddseparator、_plugin_menuclear、_plugin_menuentrysetchecked、_plugin_menuentryseticon、_plugin_menuseticon事件回调_plugin_registercallback、_plugin_unregistercallback命令注册_plugin_registercommand、_plugin_unregistercommand表达式函数_plugin_registerexprfunction、_plugin_registerexprfunctionex、_plugin_unregisterexprfunction格式化函数_plugin_registerformatfunction、_plugin_unregisterformatfunction工具函数_plugin_hash插件本身的入口约定pluginit/plugstop/plugsetup导出及CB*回调导出参见 docs/developers/plugins/basics.md。注意pluginit时通过PLUG_INITSTRUCT.pluginHandle拿到的句柄是本文几乎所有注册类 API 的第一个参数。二、调试控制类 API这类 API 让插件可以影响调试会话的暂停/继续行为是编写脱壳机unpacker、自动化调试脚本类插件的关键。2.1_plugin_debugpause将调试器控制权交还用户void _plugin_debugpause();该函数把调试状态设置为paused并阻塞等待直到用户通过run命令继续运行被调试程序debuggee后才会返回。官方文档明确建议当你在编写一个需要 x64dbg 交互支持的脱壳机例如开发调试阶段时使用它。从源码看其实现src/dbg/_plugins.cppPLUG_IMPEXP void _plugin_debugpause() { DebugUpdateGuiSetStateAsync(GetContextDataEx(hActiveThread, UE_CIP), paused); lock(WAITID_RUN); dbgsetforeground(); dbgsetskipexceptions(false); // Plugin callback PLUG_CB_PAUSEDEBUG pauseInfo { nullptr }; plugincbcall(CB_PAUSEDEBUG, pauseInfo); wait(WAITID_RUN); }可以看到它依次做了四件事异步通知 GUI 更新为暂停状态、获取WAITID_RUN运行锁、将调试器窗口置前并取消跳过异常设置dbgsetskipexceptions(false)、广播CB_PAUSEDEBUG回调后阻塞等待run。这也解释了文档中“不会返回直到用户继续运行”的行为来源。2.2_plugin_debugskipexceptions控制首轮异常的处理void _plugin_debugskipexceptions( bool skip //skip flag );设置调试器是否跳过首轮异常first-chance exceptions常用于运行被调试程序且不想被一堆首轮异常打断的脱壳机或自动化插件。skip为true时跳过。实现上直接调用内部函数dbgsetskipexceptions(skip)src/dbg/_plugins.cpp声明见 src/dbg/debugger.h。2.3_plugin_waituntilpaused阻塞等待暂停完成bool _plugin_waituntilpaused();阻塞直到调试器进入暂停状态。返回值语义与直觉相反返回true表示被调试程序仍然活跃调试会话还在、暂停已完成返回false表示被调试程序已经停止运行调试结束。源码实现src/dbg/_plugins.cppPLUG_IMPEXP bool _plugin_waituntilpaused() { while(bIsDebugging dbgisrunning()) //wait until the debugger paused { Sleep(1); GuiProcessEvents(); //workaround for scripts being executed on the GUI thread } return DbgIsDebugging(); }值得注意的是循环内每 1ms 调用一次GuiProcessEvents()——源码注释指出这是针对脚本在 GUI 线程上执行场景的 workaround保证等待期间 GUI 消息仍能得到处理避免界面假死。2.4_plugin_startscript异步执行回调void _plugin_startscript( CBPLUGINSCRIPT cbScript //callback );创建一个新线程来异步运行回调函数回调类型为typedef void (*CBPLUGINSCRIPT)();。实现上调用dbgstartscriptthread(cbScript)src/dbg/_plugins.cpp。该 API 常用于在非调试线程中执行耗时任务如批量分析避免阻塞 GUI。三、日志输出类 API3.1_plugin_logprintfprintf 风格日志void _plugin_logprintf( const char* format, //format string ... //additional arguments );向日志窗口打印一条格式化消息格式串规范与标准 C 的printf完全一致。源码实现使用dprintf_args_untranslated(format, args)src/dbg/_plugins.cpp内部经由va_list处理可变参数_untranslated后缀表示该消息不会参与 GUI 翻译流程。3.2_plugin_logputs整行文本输出void _plugin_logputs( const char* text //text to print );向日志窗口输出一行文本该文本可以包含换行符。与_plugin_logprintf的区别在于它不做格式化。实现对应dputs_untranslated(text)src/dbg/_plugins.cpp。日志输出相关的 GUI 行为如 ClearLog、EnableLog 命令可参考 docs/commands/gui/ClearLog.md。四、菜单构建类 API插件在plugsetup阶段通过PLUG_SETUPSTRUCTsrc/dbg/_plugins.h拿到 7 个预置菜单句柄hMenu插件主菜单、hMenuDisasm反汇编窗口、hMenuDump转储窗口、hMenuStack栈窗口、hMenuGraph图形窗口、hMenuMemmap内存映射窗口、hMenuSymmod符号/模块窗口。菜单类 API 均以这些句柄为起点构建层级菜单。4.1_plugin_menuadd添加子菜单int _plugin_menuadd( int hMenu, //menu handle to add the new child menu to const char* title //child menu title );向指定菜单添加一个子菜单hMenu可以是之前添加的子菜单句柄也可以是插件主菜单句柄。返回子菜单句柄全局唯一失败返回 -1。实现转交pluginmenuadd(hMenu, title)src/dbg/_plugins.cpp。4.2_plugin_menuaddentry添加菜单项bool _plugin_menuaddentry( int hMenu, //menu handle to add the new child menu to int hEntry, //plugin-wide identifier for the menu entry const char* title //menu entry title );向菜单添加一个可点击的菜单项。关键参数是hEntry这是一个插件内全局唯一的菜单项标识符当用户点击该菜单项时x64dbg 会通过CB_MENUENTRY回调把hEntry原样回传给插件回调结构PLUG_CB_MENUENTRY仅含int hEntry一个字段见 docs/developers/plugins/Callbacks/plugcbmenuentry.rst插件据此区分用户点了哪个菜单。成功返回true。4.3_plugin_menuaddseparator添加分隔线bool _plugin_menuaddseparator( int hMenu //menu handle to add the separator to );在菜单中添加一条分隔线成功返回true。4.4_plugin_menuclear清空菜单bool _plugin_menuclear( int hMenu //menu handle of the menu to clear );移除菜单中所有条目和子菜单但不删除菜单本身。常用于菜单动态刷新场景每次右键弹出前先menuclear再重新menuaddentry。成功返回true。4.5_plugin_menuentrysetchecked设置勾选状态void _plugin_menuentrysetchecked( int pluginHandle, //plugin handle int hEntry, //handle of the menu entry bool checked //new checked state );设置菜单项的勾选状态。文档特别提醒调用该函数会把菜单项变为可勾选checkable状态默认在点击时自动切换勾选如果你需要不同的行为例如单选互斥必须在每次点击时按你的期望状态显式调用本函数。注意第一个参数是插件句柄pluginHandle与多数菜单 API 不同。4.6_plugin_menuentryseticon/_plugin_menuseticon设置图标void _plugin_menuentryseticon( int pluginHandle, //plugin handle int hEntry, //handle of the menu entry const ICONDATA* icon //icon data ); void _plugin_menuseticon( int hMenu, //handle of the menu const ICONDATA* icon //icon data );分别为菜单项、菜单设置图标。ICONDATA定义于 src/bridge/bridgemain.htypedef struct { const void* data; duint size; } ICONDATA;即数据指针 字节大小可承载 PNG 等任意图像格式数据。GUI 侧对应GuiMenuSetIcon/GuiMenuSetEntryIconsrc/bridge/bridgemain.h。五、事件回调类 API5.1_plugin_registercallback注册事件回调void _plugin_registercallback( int pluginHandle, //plugin handle CBTYPE cbType, //event type CBPLUGIN cbPlugin //callback function );为插件注册某个调试事件的回调。官方文档明确指出两条重要约束每个插件对同一事件只能注册一个回调重复注册同一事件会覆盖之前注册的回调回调函数原型为void CBPLUGIN( CBTYPE bType, //event type (useful when you use the same function for multiple events) void* callbackInfo //pointer to a structure of information (see above) );bType参数让你可以用同一个函数处理多个事件再按类型分发。callbackInfo指向对应事件的结构体具体结构定义见 src/dbg/_plugins.h 的PLUG_CB_*系列各回调的详细说明在 docs/developers/plugins/Callbacks 目录下。CBTYPE枚举定义于 src/dbg/_plugins.h文档列出的核心事件如下事件常量callbackInfo 结构触发时机CB_INITDEBUGPLUG_CB_INITDEBUG*开始调试会话CB_STOPDEBUGPLUG_CB_STOPDEBUG*结束调试会话CB_CREATEPROCESSPLUG_CB_CREATEPROCESS*创建进程CB_EXITPROCESSPLUG_CB_EXITPROCESS*进程退出CB_CREATETHREADPLUG_CB_CREATETHREAD*创建线程CB_EXITTHREADPLUG_CB_EXITTHREAD*线程退出CB_SYSTEMBREAKPOINTPLUG_CB_SYSTEMBREAKPOINT*系统断点命中CB_LOADDLLPLUG_CB_LOADDLL*DLL 加载CB_UNLOADDLLPLUG_CB_UNLOADDLL*DLL 卸载CB_OUTPUTDEBUGSTRINGPLUG_CB_OUTPUTDEBUGSTRING*目标输出调试字符串CB_EXCEPTIONPLUG_CB_EXCEPTION*异常发生CB_BREAKPOINTPLUG_CB_BREAKPOINT*断点命中CB_PAUSEDEBUGPLUG_CB_PAUSEDEBUG*调试暂停CB_RESUMEDEBUGPLUG_CB_RESUMEDEBUG*调试恢复CB_STEPPEDPLUG_CB_STEPPED*单步完成CB_ATTACHPLUG_CB_ATTACHED*附加进程源码注释在附加前、CB_INITDEBUG之后触发CB_DETACHPLUG_CB_DETACHED*分离进程源码注释在分离前、CB_STOPDEBUG之前触发CB_DEBUGEVENTPLUG_CB_DEBUGEVENT*任何调试事件CB_MENUENTRYPLUG_CB_MENUENTRY*点击插件菜单项CB_WINEVENTPLUG_CB_WINEVENT*窗口事件CB_WINEVENTGLOBALPLUG_CB_WINEVENTGLOBAL*全局窗口事件CB_LOADDBPLUG_CB_LOADSAVEDB*加载数据库CB_SAVEDBPLUG_CB_LOADSAVEDB*保存数据库CB_FILTERSYMBOLPLUG_CB_FILTERSYMBOL*符号过滤CB_TRACEEXECUTEPLUG_CB_TRACEEXECUTE*追踪执行此外源码中的CBTYPE枚举还包含CB_SELCHANGED、CB_ANALYZE、CB_ADDRINFO、CB_VALFROMSTRING、CB_VALTOSTRING、CB_MENUPREPARE、CB_STOPPINGDEBUG、CB_STARTTRACE、CB_STOPTRACE、CB_DBOPERATION、CB_DBLOADOPERATION等扩展事件src/dbg/_plugins.h供需要更精细控制的高级插件使用。实现上_plugin_registercallback只是pluginregistercallback(pluginHandle, cbType, cbPlugin)的封装src/dbg/_plugins.cpp。另外docs/developers/plugins/basics.md 还介绍了免注册的替代方式直接导出一个与事件同名的CDECL导出函数如CBMENUENTRY即可自动注册为CB_MENUENTRY的回调注意导出名中不要使用下划线。5.2_plugin_unregistercallback注销回调bool _plugin_unregistercallback( int pluginHandle, //plugin handle CBTYPE cbType //callback type to remove );注销之前通过_plugin_registercallback注册的回调只能注销自己注册过的回调。成功返回true。插件应在卸载时plugstop清理所有注册的回调。六、命令注册类 API6.1_plugin_registercommand注册命令bool _plugin_registercommand( int pluginHandle, //plugin handle const char* command, //command name CBPLUGINCOMMAND cbCommand, //function that is called when the command is executed bool debugonly //restrict the command to debug-only );注册一个可在命令栏或脚本中使用的命令。命令回调原型bool CBPLUGINCOMMAND( int argc, //argument count (number of arguments 1) char* argv[] //array of arguments (argv[0] is the full command, arguments start at argv[1]) );参数约定与 C 的main一致argc为参数个数加 1argv[0]是完整命令本身实际参数从argv[1]开始。debugonly为true时当没有正在调试的目标时该命令永远不会被执行。文档特别强调务必检查返回值——true表示注册成功false表示注册失败例如其他插件已经注册了同名命令。实现转交plugincmdregister(...)src/dbg/_plugins.cpp。6.2_plugin_unregistercommand注销命令bool _plugin_unregistercommand( int pluginHandle, //plugin handle const char* command //command name );移除插件之前注册的命令成功返回true。七、表达式函数类 APIx64dbg 的表达式系统参见 docs/introduction/Expressions.md支持用户自定义函数本组 API 让插件向表达式引擎注入自己的函数。7.1_plugin_registerexprfunction注册整数表达式函数bool _plugin_registerexprfunction( int pluginHandle, //plugin handle const char* name, //name of expresison function int argc, //number of arguments CBPLUGINEXPRFUNCTION cbFunction, //callback function void* userdata //user data );注册一个所有参数均为整数类型的表达式函数。回调类型typedef duint(*CBPLUGINEXPRFUNCTION)(int argc, const duint* argv, void* userdata);argv是参数数组userdata是注册时传入的指针会在回调时原样带回插件可用它传递额外上下文。注册成功返回true。7.2_plugin_registerexprfunctionex注册支持字符串参数的表达式函数bool _plugin_registerexprfunctionex( int pluginHandle, //plugin handle const char* name, //name of expresison function const ValueType returnType, //type of return value const ValueType* argTypes, //type of arguments size_t argc, //number of arguments CBPLUGINEXPRFUNCTIONEX cbFunction, //callback function void* userdata //user data );与_plugin_registerexprfunction相比本函数支持字符串类型的参数和返回值文档明确说明这是两者唯一区别。类型系统定义如下typedef enum { ValueTypeNumber, ValueTypeString, // Types below cannot be used for values, only for registration ValueTypeAny, ValueTypeOptionalNumber, ValueTypeOptionalString, ValueTypeOptionalAny, } ValueType;注意枚举后三项ValueTypeAny及Optional*系列只能用于注册时的类型声明不能作为实际值类型。回调类型为typedef struct { const char* ptr; // Should be allocated with BridgeAlloc bool isOwner; // When set to true BridgeFree will be called on ptr } StringValue; typedef struct { ValueType type; duint number; StringValue string; } ExpressionValue; typedef bool(*CBPLUGINEXPRFUNCTIONEX)(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);ExpressionValue是一个带类型标签的联合体式的结构根据type是ValueTypeNumber还是ValueTypeString读取number或string字段。字符串内存管理约定StringValue.ptr必须用BridgeAlloc分配声明见 src/bridge/bridgemain.h当isOwner为true时x64dbg 会调用BridgeFree自动释放ptr。这些结构体同样定义于 src/dbg/_plugins.h。7.3_plugin_unregisterexprfunction注销表达式函数bool _plugin_unregisterexprfunction( int pluginHandle, //plugin handle const char* name //expression function name );移除插件之前用_plugin_registerexprfunction或_plugin_registerexprfunctionex注册的表达式函数成功返回true。八、格式化函数类 API8.1_plugin_registerformatfunction注册字符串格式化函数bool _plugin_registerformatfunction( int pluginHandle, //plugin handle const char* type, //the name of format function CBPLUGINFORMATFUNCTION cbFunction, //callback function void* userdata //user data );注册一个字符串格式化函数使插件能够扩展 x64dbg 的格式化系统格式化的完整用法见 docs/introduction/Formatting.md。type参数是格式串中;之前的那部分名称命名有严格约束必须以_或字母开头后续只能包含_、.、字母和数字。回调类型typedef FORMATRESULT(*CBPLUGINFORMATFUNCTION)(char* dest, size_t destCount, int argc, char* argv[], duint value, void* userdata);返回类型FORMATRESULT枚举src/dbg/_plugins.htypedef enum { FORMAT_ERROR, //generic failure (no message) FORMAT_SUCCESS, //success FORMAT_ERROR_MESSAGE, //formatting failed but an error was put in the buffer (there are always at least 511 characters available). FORMAT_BUFFER_TOO_SMALL //buffer too small (x64dbg will retry until the buffer is big enough) } FORMATRESULT;其中FORMAT_BUFFER_TOO_SMALL表示目标缓冲区dest容量destCount不够大此时x64dbg 会自动扩大缓冲区并重试因此回调实现应当如实上报该状态而不是截断输出。FORMAT_ERROR_MESSAGE表示格式化失败但已在缓冲区写入错误信息x64dbg 保证至少有 511 个字符可用。注册成功返回true。8.2_plugin_unregisterformatfunction注销格式化函数bool _plugin_unregisterformatfunction( int pluginHandle, //plugin handle const char* type //string format function name );移除之前注册的格式化函数成功返回true。九、工具函数_plugin_hashduint _plugin_hash( const void* data, //data to hash duint size //size (in bytes) of the data to hash );对任意数据块计算哈希并返回x64dbg 内部在多处使用该函数。源码实现为PLUG_IMPEXP duint _plugin_hash(const void* data, duint size) { return murmurhash(data, (size_t)size); }底层算法是MurmurHash3实现位于 src/dbg/murmurhash.h64 位构建下使用MurmurHash3_x64_128种子0x1337取 128 位哈希的低 64 位32 位构建下使用MurmurHash3_x86_32同样种子0x1337。duint是 x64dbg 定义的与地址宽度一致的无符号整数类型64 位构建为unsigned long long32 位构建为unsigned int。如果你的插件需要在不同架构上保持哈希一致性注意该函数的结果位数会随构建架构变化。十、实战组合一个完整的插件骨架综合以上 API一个典型插件在pluginit拿到pluginHandle后会在plugsetup阶段注册菜单与命令并通过回调响应事件。核心流程如下// plugsetup拿到菜单句柄后构建菜单 extern C __declspec(dllexport) void plugsetup(PLUG_SETUPSTRUCT* setupStruct) { // 1. 在插件主菜单下添加子菜单与菜单项 int hChild _plugin_menuadd(setupStruct-hMenu, My Plugin); _plugin_menuaddentry(hChild, 1, Action One); // hEntry 1 _plugin_menuaddentry(hChild, 2, Action Two); // hEntry 2 _plugin_menuaddseparator(hChild); _plugin_menuaddentry(hChild, 3, Toggle Option); // hEntry 3 // 2. 注册事件回调与命令 _plugin_registercallback(pluginHandle, CB_MENUENTRY, menuEntryCallback); _plugin_registercommand(pluginHandle, mycmd, myCommandCallback, true); // 仅调试时可用 } // 统一回调按事件类型分发 void menuEntryCallback(CBTYPE cbType, void* callbackInfo) { if (cbType CB_MENUENTRY) { int hEntry ((PLUG_CB_MENUENTRY*)callbackInfo)-hEntry; switch (hEntry) { case 1: _plugin_logprintf(Action One clicked\n); break; case 3: _plugin_menuentrysetchecked(pluginHandle, 3, !currentState); break; // 手动控制勾选 } } } // 命令回调argv[0] 为完整命令参数从 argv[1] 开始 bool myCommandCallback(int argc, char* argv[]) { if (argc 1) _plugin_logprintf(mycmd arg: %s\n, argv[1]); return true; } // plugstop清理注册 extern C __declspec(dllexport) bool plugstop() { _plugin_unregistercommand(pluginHandle, mycmd); _plugin_unregistercallback(pluginHandle, CB_MENUENTRY); return true; }卸载时plugstop务必按官方规范注销所有命令与回调docs/developers/plugins/basics.md这是保证插件可安全热卸载、不产生悬挂回调的关键。总结_plugin_系列 24 个 API 构成了 x64dbg 插件能力的完整骨架调试控制_plugin_debugpause、_plugin_debugskipexceptions、_plugin_waituntilpaused、日志输出_plugin_logprintf、_plugin_logputs、菜单构建_plugin_menuadd*系列、事件驱动_plugin_registercallback、命令扩展_plugin_registercommand、表达式与格式化扩展_plugin_registerexprfunction[ex]、_plugin_registerformatfunction以及哈希工具_plugin_hash。所有函数的声明与实现分别集中在 src/dbg/_plugins.h 与 src/dbg/_plugins.cpp回调结构定义可查阅 docs/developers/plugins/Callbacks插件入口与导出约定见 docs/developers/plugins/basics.md。掌握这些 API即可针对反混淆、脱壳、自动化分析等场景编写功能完整的 x64dbg 插件。【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表