
x64dbg scriptcmd 命令完全指南在脚本上下文中执行任意命令【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbgscriptcmd是 x64dbg 脚本系统中最灵活的命令转发器它把scriptcmd之后的所有文本原样交给命令处理器执行从而让运行中的脚本可以调用任意调试器命令。本文围绕官方文档 docs/commands/script/scriptcmd.md 展开结合 src/dbg/commands/cmd-script.cpp 与 src/dbg/simplescript.cpp 等源码实现讲清它的参数规则、执行语义、线程模型以及如何配合断点回调SetBreakpointCommand实现命中断点即执行脚本的自动化工作流并给出可复制的完整示例。命令总览把一切转发给命令处理器scriptcmd是 x64dbg 的脚本专属命令注册于 src/dbg/x64dbg.cpp 的dbgcmdnew(scriptcmd, cbScriptCmd, false)其核心行为可以用一句话概括scriptcmd之后的所有内容原样转发给命令处理器执行。这一点与 x64dbg 中的普通命令截然不同。普通命令通过空格切分参数argc/argv而scriptcmd不做任何参数切分——scriptcmd后面的整段文本被当作一条完整命令提交。以文档中的例子为准scriptcmd add rax, 0x1245实际执行的是add rax, 0x1245这条命令即把0x1245加到寄存器rax上。换句话说scriptcmd等价于把字符串塞进命令行解释器再回车。参数解析的源码实现在 src/dbg/commands/cmd-script.cpp 中cbScriptCmd的实现揭示了这一行为bool cbScriptCmd(int argc, char* argv[]) { if(IsArgumentsLessThan(argc, 2)) return false; auto scriptcmd strchr(argv[0], ); if(scriptcmd nullptr) return false; while(isspace(*scriptcmd)) scriptcmd; return ScriptCmdExecAwait(scriptcmd, false, nullptr) ! ScriptCommandOutcome::Abort; }注意这里的细节argv[0]是包含完整命令文本的原始字符串strchr(argv[0], )定位到scriptcmd之后的第一个空格指针越过空格后即为待转发命令的起始位置前导空白会被isspace循环跳过因此scriptcmd add rax, 1多个空格也能正常执行最终通过ScriptCmdExecAwait将命令提交到脚本执行队列只有返回ScriptCommandOutcome::Abort才判定为失败其余结果Continue/Pause都视为命令成功。无参数时IsArgumentsLessThan(argc, 2)保证单独输入scriptcmd不带任何转发内容会返回false即失败因为此时没有可转发的命令。返回值与结果变量scriptcmd不设置任何结果变量。这是它与msgyn、call等命令的重要区别——例如 cmd-script.cpp 中cbScriptMsgyn会把用户选择写入$RESULT而scriptcmd不写入$RESULT也不写入任何其他变量。如果需要在脚本中判断被转发命令的执行结果不能依赖结果变量而应让被调用的命令自行完成状态记录例如用var/mov写入脚本变量或用log输出日志或者利用scriptcmd失败后脚本终止这一行为来传递错误。执行语义阻塞直到命令完成scriptcmd是阻塞式命令它会一直等待被转发的命令执行完毕之后才继续脚本的下一行脚本执行由单一专用线程脚本队列scriptQueue串行处理所有提交给脚本的命令按提交顺序依次执行互不干扰。这一语义在 src/dbg/simplescript.cpp 的ScriptCmdExecAwait中得到了完整实现。该函数优先尝试抢占式直接执行如果脚本线程当前正因调试事件让出yield执行权则直接在调用线程上执行命令并合并结果否则将命令封装为 lambda 提交到scriptQueue.await(...)等待脚本专用线程按队列顺序执行——这正是按提交顺序执行、无交叉干扰的线程模型的来源。一个值得注意的细节ScriptCmdExecAwait在开头就捕获当前脚本状态scriptState注释明确说明这个函数可能通过断点命令或插件回调中的dbgcmdexecdirect(scriptcmd)被调用提前捕获状态是为了防止状态被队列重置参见 src/dbg/simplescript.cpp。也就是说scriptcmd不仅能在脚本里使用还能被插件在断点回调中通过DbgCmdExecDirect触发此时同样走这一套阻塞语义。与调试器运行状态的配合阻塞语义还体现在 scriptInternalCmdExec命令执行后脚本会进入等待循环直到被调试进程暂停while(bIsDebugging dbgisrunning()) Sleep(1);然后才继续后续脚本行。因此如果scriptcmd转发的是run、StepOver这类让程序继续运行的命令脚本会同步等待程序再次暂停这与 docs/commands/script/scriptrun.md、docs/commands/script/scriptexec.md 所描述的等待语义一脉相承。典型实战断点回调中执行脚本scriptcmd最常见的用途是配合 SetBreakpointCommand对应仓库路径 docs/commands/conditional-breakpoint-control/SetBreakpointCommand.md实现断点命中 → 自动执行一段脚本的自动化回调。官方文档给出了完整示例fn_addr module.dll:$0x1234 // module.dll RVA 0x1234 bp fn_addr SetBreakpointCommand fn_addr, scriptcmd call mycallback // TODO: make sure the script is not unloaded (using run) mycallback: log fn({arg.get(0)}, {arg.get(1)}) ret逐行解读fn_addr module.dll:$0x1234用表达式求出module.dll内 RVA0x1234处的绝对地址$前缀表示 RVA 偏移存入脚本变量fn_addrbp fn_addr在该地址下普通断点SetBreakpointCommand fn_addr, scriptcmd call mycallback把scriptcmd call mycallback绑定为该断点的回调命令。断点命中时x64dbg 执行这条命令scriptcmd再把它转发成脚本内部的call mycallback——即调用脚本中mycallback:标签处的子过程回调子过程用log记录被调试函数的两个参数arg.get(0)、arg.get(1)ret返回调用点。断点回调中的执行链该工作流在断点引擎侧有对应的配套逻辑。src/dbg/debugger.cpp 处对断点命令文本以scriptcmd 前缀做特判而在断点命中处理流程中脚本会先通过ScriptInterruptAwait(ScriptInterrupt::YieldDebugEvent)让出执行权、并在执行潜在scriptcmd前对调试器加锁见 src/dbg/debugger.cpp注释明确写道 Pause debugger before a potential scriptcmd, which would race otherwise——即在scriptcmd前先暂停调试器避免竞态。这说明scriptcmd并不是简单的字符串投递而是与调试器暂停/恢复状态深度耦合的同步原语。回调的注意事项保持脚本已加载示例中的// TODO: make sure the script is not unloaded (using run)提醒我们断点回调发生时脚本必须仍处于加载状态否则call mycallback找不到标签。用scriptload加载脚本后不要在执行回调前卸载它参数传递被调试函数的头两个参数可用arg.get(0)、arg.get(1)读取调用约定相关更多细节参见 docs/commands/script/call.md非脚本上下文同样可用scriptcmd也可在命令行直接输入此时它同样把后续文本转发给命令处理器——但由于没有加载脚本通常只有配合已加载的脚本或断点回调才有意义。进阶scriptcmd call与脚本状态的交互scriptcmd转发call这类分支命令时脚本引擎有专门的处理逻辑。在 src/dbg/simplescript.cpp 的scriptExecCommand中case STATUS_CONTINUE_BRANCH: // If the user executes scriptcmd call xxx, start running. if(state SCRIPT_PAUSED) ScriptRunAsync(scriptIp, gui); break;当脚本处于暂停状态SCRIPT_PAUSED时通过scriptcmd call xxx调用标签会让脚本自动切换为运行状态ScriptRunAsync继续执行而ret返回时simplescript.cpp引擎会根据调用前脚本的运行状态决定是否再次暂停——例如单步越过erun时命中断点触发scriptcmd call的场景脚本会在标签处暂停恢复运行后在erun之后再次暂停。这套状态机保证了嵌套调用断点回调里再触发回调也能正确恢复现场。仓库中的测试用例 src/tests/scriptcmd_call/ 专门验证了这一行为test.fastresume.txt 在两个断点OuterHit/InnerHit上分别绑定scriptcmd call onouter/scriptcmd call oninner用$outer、$inner两个变量断言快速恢复fast-resume模式下每个回调恰好执行一次plugin.cpp 则演示了从插件侧通过DbgCmdExecDirect(scriptcmd call ...)在CB_BREAKPOINT回调中触发脚本标签并用$plugin_direct_mode变量控制测试模式——印证了注释中可从插件回调调用scriptcmd的设计意图相关测试在 src/tests/CMakeLists.txt 中注册为scriptcmd_call与scriptcmd_call_threads两个测试目标。常见用法速查场景写法说明转发寄存器运算命令scriptcmd add rax, 0x1245在脚本中修改寄存器断点回调调用脚本子过程SetBreakpointCommand addr, scriptcmd call mycallback命中断点自动执行脚本逻辑转发 GUI/内存命令scriptcmd dump rax在脚本流程中切换视图插件回调触发脚本DbgCmdExecDirect(scriptcmd call onXxx)见 src/tests/scriptcmd_call/plugin.cpp转发运行控制命令scriptcmd erun注意阻塞语义脚本会等待程序再次暂停小结scriptcmd的价值在于它把脚本语言和调试器命令语言打通脚本本身只提供流程控制标签、call/ret、Jxx、log等见 docs/commands/script/index.rst而所有 x64dbg 命令都可以通过scriptcmd在脚本上下文中直接调用。结合断点命令、插件回调与源码中严谨的阻塞/暂停协调机制它可以支撑起断点自动化日志、参数记录、内存修改、反调试绕过等常见的逆向工程与恶意软件分析自动化场景——这也是它在 x64dbg 官方测试套件中被专门覆盖的原因所在。进一步阅读脚本命令家族docs/commands/script/index.rst断点回调命令SetBreakpointCommand脚本子过程调用call脚本加载与执行scriptload、scriptrun、scriptexec源码实现cmd-script.cpp、simplescript.cpp【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考