ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

x64dbg 断点命令条件:SetBreakpointCommandCondition/bpcommandcond 使用与实现原理

2026/9/19 4:43:31 拓冰建站 浏览量
x64dbg 断点命令条件:SetBreakpointCommandCondition/bpcommandcond 使用与实现原理 x64dbg 断点命令条件SetBreakpointCommandCondition/bpcommandcond 使用与实现原理【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg导读在 x64dbg 中条件断点并不仅仅意味着满足条件才停下它还可以把日志输出、命令执行与是否暂停三者解耦各自独立配置触发条件。SetBreakpointCommandCondition别名bpcommandcond就是用来设置软件断点命中命令command text执行门槛的命令当断点命令条件未设置时断点命令在调试器准备暂停时执行一旦设置了命令条件则只有条件表达式求值为非 0 时命令才会被执行。本文将完整讲解该命令的参数语义、别名、引用与转义规则并结合 src/dbg/commands/cmd-conditional-breakpoint-control.cpp 与 src/dbg/debugger.cpp 的源码还原其在断点命中流程中的求值、执行与持久化机制帮助你在逆向与恶意样本分析中精确控制断点副作用的触发时机。命令概览与语义SetBreakpointCommandCondition设置软件断点的命令条件。官方文档原文对它的语义定义如下Sets the command condition of a software breakpoint. When command condition is not specified, the command will be executed when the debugger would break, otherwise it will be executed when the condition is satisfied.翻译过来即当命令条件未指定时断点命令在调试器将要中断break时执行当命令条件已指定时只有条件满足求值为非 0时命令才会执行。这个设计与SetBreakpointCondition设置断点条件决定调试器是否暂停是两条独立的轴break conditionSetBreakpointCondition /bpcond/bpcnd决定断点命中后调试器是否停止command condition本文命令决定断点命中后绑定的命令是否执行。两者互不替代你可以让命令在断点命中时照常执行、同时让调试器永不暂停break condition设为0也可以反过来让命令仅在某个额外条件下执行。这一条件解耦机制在自动化分析、批量打日志、API 挂钩统计等场景非常实用。该命令是 x64dbg 命令体系中条件断点控制Conditional Breakpoint Control一组命令的成员同组还包括SetBreakpointName、SetBreakpointCondition、SetBreakpointLog、SetBreakpointLogCondition、SetBreakpointCommand、SetBreakpointFastResume、SetBreakpointSingleshoot、SetBreakpointSilent等完整列表见 docs/commands/conditional-breakpoint-control/index.rst总体行为模型见 docs/introduction/ConditionalBreakpoint.md。参数说明命令使用两个参数参数含义说明arg1断点地址软件断点所在的内存地址支持表达式见下文[arg2]命令条件可省略省略时等价于默认条件即命令在调试器将要中断时执行命令本身不设置任何结果变量官方文档 This command does not set any result variables。命令的注册位于 src/dbg/x64dbg.cppdbgcmdnew(SetBreakpointCommandCondition,bpcommandcond, cbDebugSetBPXCommandCondition, true); //set breakpoint commandCondition从注册行可以看到SetBreakpointCommandCondition有一个内置别名bpcommandcond注册格式中的逗号即表示主名,别名二者完全等价。由于arg1是地址你可以在其中使用表达式或伪寄存器例如SetBreakpointCommandCondition EIP, EAX1 SetBreakpointCommandCondition 401000, $breakpointcounter5 SetBreakpointCommandCondition entry, 1 bpcommandcond 401000地址与条件的解析方式命令内部实现位于 src/dbg/commands/cmd-conditional-breakpoint-control.cpp。软件断点版本的回调cbDebugSetBPXCommandCondition第 211-214 行只是把类型固定为BPNORMAL后转发给通用实现bool cbDebugSetBPXCommandCondition(int argc, char* argv[]) { return cbDebugSetBPXCommandConditionCommon(BPNORMAL, argc, argv); }通用实现cbDebugSetBPXCommandConditionCommon第 57-60 行与同组的 Name/Condition/Log/LogCondition/Command 等命令共享同一个模板cbDebugSetBPXTextCommon第 9-30 行。其解析流程可以归纳为参数数量校验IsArgumentsLessThan(argc, 2)要求至少提供arg1断点地址否则直接返回失败可选参数处理argc 2时取argv[2]作为条件值未提供时使用空字符串即命令条件未指定的默认状态断点查找通过BpGetAny(BPNORMAL, argv[1], bp)在软件断点表中查找地址。注意这里传入的是原始参数串也就是说arg1可以是地址表达式查找失败时打印No such breakpoint %s写入字段调用BpSetCommandCondition(bp.addr, Type, value)把条件写入断点对象失败时打印Cant set command condition on breakpoint %s刷新界面DebugUpdateBreakpointsViewAsync()异步通知 GUI 的断点视图刷新使修改立刻反映在 BreakpointsView 中。底层写入函数BpSetCommandCondition位于 src/dbg/breakpoint.cpp在持锁EXCLUSIVE_ACQUIRE(LockBreakpoints)的前提下将字符串原样存入BREAKPOINT结构体的commandCondition字段src/dbg/breakpoint.h 中声明为std::string commandCondition; // condition to execute the command。它是纯字符串存储求值延迟到断点命中时刻进行设置命令本身不校验表达式合法性——因此一个写错的表达式不会在设置时报错只会在断点命中求值时触发错误处理见下文。断点命中时的求值与执行流程命令条件的真正作用点在断点命中处理函数中位于 src/dbg/debugger.cpp。x64dbg 命中一个断点后会依次评估三类条件断点条件决定是否暂停、日志条件决定是否打日志、命令条件决定是否执行命令。命令条件的求值逻辑如下源码注释为证if(!bp.commandCondition.empty()) { commandCondition getConditionValue(bp.commandCondition); if(commandCondition -1) { dputs(QT_TRANSLATE_NOOP(DBG, Error when evaluating command condition.)); breakCondition -1; // Force breaking when an error occurs commandCondition 0; // Dont execute any command if an error occurs } } else { // NOTE: This behavior was changed in a breaking way, but too many people were confused if(breakCondition ! -1) commandCondition 1; // If no condition is set, always execute the command else commandCondition 0; // Dont execute any command if an error occurs }这段代码揭示了三条关键规则未设置命令条件默认态命令条件取值为1只要断点条件本身没有求值出错命令随调试器将要中断一起执行——这正是官方文档所说的 executed when the debugger would break设置了命令条件调用getConditionValue求值src/dbg/debugger.cpp非 0 为真、0 为假表达式0\0、1\0有短路优化其余通过valfromstring解析表达式得到数值求值出错打印Error when evaluating command condition.并强制把断点条件设为 -1强制中断同时不执行命令。也就是说无效的命令条件表达式会让断点无论如何都停与官方文档 If any expression is invalid, the condition will be triggered 的总体约定一致。求值完成后命令的执行位于 第 1092-1117 行if(!bp.commandText.empty() commandCondition) //command { //TODO: commands like run/step etc will fuck up your shit varset($breakpointcondition, (breakCondition ! 0) ? 1 : 0, false); varset($breakpointlogcondition, (logCondition ! 0) ? 1 : 0, true); ... if(StringUtils::StartsWith(bp.commandText, scriptcmd )) commandSuccess ScriptCmdExecAwait(...); else commandSuccess cmddirectexec(bp.commandText.c_str()); ... }要点只有commandText非空且commandCondition为真时才执行命令两者是与的关系执行前会先写入系统变量$breakpointcondition断点条件值与$breakpointlogcondition日志条件值供命令脚本读取命令以scriptcmd前缀开头时走脚本命令等待通道ScriptCmdExecAwait否则走cmddirectexec直接执行命令执行失败会强制中断breakCondition -1命令还可以通过改写$breakpointcondition变量反过来控制调试器是否暂停第 1109-1116 行 读取该变量回写断点条件。由此可以看出SetBreakpointCommandCondition设置的条件是整个命中后命令执行门控中的一环与 SetBreakpointCommand设置命令文本配套使用没有命令文本命令条件毫无意义没有命令条件命令则绑定在调试器将要中断这个默认时机上。引用、转义与 GUI 侧的生成方式命令条件本质是表达式而 x64dbg 表达式里经常出现逗号与字符串字面量。官方文档对这类情况的处理建议是当表达式包含逗号或字符串字面量时需要对命令参数进行引用和转义。相关文档中的参考示例来自SetBreakpointCondition同样适用于本命令SetBreakpointCondition 401000, streq(utf8(rax), \C:\directory\\\)即用双引号包裹整个表达式内部的引号以\转义。若条件表达式不含逗号、引号则可以直接书写例如SetBreakpointCommandCondition 401000, EAX1。从 GUI 的断点编辑/导出代码也能看到官方的标准做法在 src/gui/Src/Utils/Breakpoints.cpp 中断点保存时会生成exec(QString(SetBreakpointCommandCondition %1, \%2\).arg(addrText).arg(DbgCmdEscape(bp.commandCondition)));即在条件两侧包裹双引号并通过DbgCmdEscapesrc/gui/Src/Utils/StringUtil.cpp完成转义。DbgCmdEscape优先调用桥接层导出的CommandEscape函数注册于 src/dbg/_dbgfunctions.cpp内部实现在 src/dbg/commandparser.cpp 的Command::Escape对与{加反斜杠转义对反斜杠按是否位于特殊字符之前/字符串末尾做翻倍处理以保护尾部反斜杠不被闭合引号吞掉若桥接函数不可用则退化为简单替换→\、{→\{。断点视图的导出功能同样生成本命令src/gui/Src/Gui/BreakpointsView.cpp 等只有设置了命令条件的断点才会输出形如SetBreakpointCommandCondition addr, condition的行并复用相同的escape转义逻辑。也就是说无论你是手敲命令、在断点编辑对话框中填写还是用导出断点功能生成命令脚本最终走的都是同一条命令解析通道。持久化与数据库字段断点的命令条件会随数据库一起保存/加载序列化代码位于 src/dbg/breakpoint.cpp保存第 918 行以 JSON 字符串字段commandCondition写入json_object_set_new(jsonObj, commandCondition, json_string(breakpoint.commandCondition))加载第 983 行通过loadStringValue(value, breakpoint.commandCondition, commandCondition)还原到内存迁移第 987-992 行源码注释记录了 2023-06-10 的一次行为变更——命令条件的默认值从$breakpointcondition改为1。为了兼容旧数据库BpCacheLoad接收migrateCommandCondition标志当检测到旧库且命令文本与命令条件都不为空时把命令条件改写为$breakpointcondition以保留旧版本跟随断点条件执行的行为。这条迁移逻辑从侧面印证了默认语义的演变新版本中未设置命令条件 始终在调试器将要中断时执行命令而旧版本用户若依赖仅在断点条件成立时执行命令则需要显式将命令条件写为$breakpointcondition。另外断点文本以cmdif(condition, command)形式呈现在反汇编注释中src/dbg/_exports.cpp供插件与 GUI 读取。五种断点类型的对应命令SetBreakpointCommandCondition仅针对软件断点BPNORMAL。x64dbg 的命令系统还提供了其余四种断点类型的同语义命令注册均位于 src/dbg/x64dbg.cpp底层全部复用了同一个cbDebugSetBPXCommandConditionCommon模板断点类型命令注册行软件断点SetBreakpointCommandCondition别名bpcommandcondx64dbg.cpp#L200硬件断点SetHardwareBreakpointCommandConditionx64dbg.cpp#L213内存断点SetMemoryBreakpointCommandConditionx64dbg.cpp#L226库/DLL 断点SetLibrarianBreakpointCommandConditionx64dbg.cpp#L239异常断点SetExceptionBreakpointCommandConditionx64dbg.cpp#L252对应回调cbDebugSetBPXHardwareCommandCondition、cbDebugSetBPXMemoryCommandCondition、cbDebugSetBPXDLLCommandCondition、cbDebugSetBPXExceptionCommandCondition定义于 src/dbg/commands/cmd-conditional-breakpoint-control.cpp第 273 行 等它们与软件断点版本唯一的区别是传入的BP_TYPE不同参数与语义完全一致。GUI 侧在编辑各类型断点时也会分别生成对应命令src/gui/Src/Utils/Breakpoints.cpp。如果你面对的是硬件/内存/异常断点套用本文的用法即可。实战示例示例 1仅在 EAX 为 1 时执行断点命令先在 0x401000 下软件断点并绑定命令再设置命令条件bp 401000 SetBreakpointCommand 401000, log \EAX1 hit at {p:eip}\ SetBreakpointCommandCondition 401000, EAX1此后每次命中 0x401000只有当 EAX 等于 1 时才执行日志命令其余命中不执行命令是否暂停取决于断点条件。示例 2让断点命令在满足条件时执行、但调试器永不暂停SetBreakpointCondition 401000, 0 SetBreakpointCommand 401000, log {p:eip} SetBreakpointCommandCondition 401000, 1break condition为0使调试器永不暂停命令条件为1使命令无条件执行——适用于静默采集执行轨迹类自动化场景。示例 3每命中 3 次执行一次命令SetBreakpointCommandCondition 401000, ($breakpointcounter%3)0$breakpointcounter在每次命中时由调试器写入命中次数src/dbg/debugger.cpp配合取模即可实现节流式命令执行。示例 4条件中含字符串字面量需要引用与转义对比以反斜杠结尾的路径SetBreakpointCommandCondition 401000, streq(utf8(rax), \C:\directory\\\)注意不要在断点命令文本中放入run、step等会改变被调试程序运行状态的命令——文档与源码debugger.cpp中的//TODO: commands like run/step etc will fuck up your shit都明确指出这类命令在此处使用不稳定。需要依据条件控制暂停时请使用break condition、command condition或$breakpointcondition变量详见 docs/introduction/ConditionalBreakpoint.md。小结SetBreakpointCommandCondition别名bpcommandcond为软件断点的命令设置执行门槛未设置时命令随调试器将要中断执行设置后仅当表达式求值为非 0 时执行条件与断点文本SetBreakpointCommand配套使用二者缺一不可命令条件求值出错会强制中断并跳过命令条件仅在命中时求值设置命令本身不校验表达式表达式含逗号/引号时需按文档规范引用与转义GUI 与导出功能即采用DbgCmdEscape/Command::Escape的同一套规则命令条件随数据库以 JSON 字段commandCondition持久化且存在 2023-06-10 起的默认值迁移逻辑旧库自动改写为$breakpointcondition硬件、内存、DLL、异常断点均有同语义命令共用同一实现模板参数与用法一致。如需深入了解整套条件断点行为模型与表达式语法可继续阅读 docs/introduction/ConditionalBreakpoint.md、docs/introduction/Expressions.md 与 docs/introduction/Expression-functions.md。【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考