恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
x64dbg erun/ego/er/eg 命令详解:跳过首次异常直接运行
首页
资讯中心
/
x64dbg erun/ego/er/eg 命令详解:跳过首次异常直接运行
x64dbg erun/ego/er/eg 命令详解:跳过首次异常直接运行
发布时间:2026/9/19 15:18:51
x64dbg erun/ego/er/eg 命令详解跳过首次异常直接运行【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg导读在 x64dbg 中调试加壳程序、恶意软件或使用异常作为控制流如 SEH 反调试、异常驱动的保护逻辑的目标时最常见的痛点就是程序一启动就抛出一堆首次异常first-chance exception调试器在每条异常处都停下来导致根本无法顺畅地跑到真正的断点。erun及其别名ego、er、eg正是为此设计的命令它释放调试器锁、让程序继续运行并且在运行期间把所有首次异常直接转交回被调试程序debuggee处理而不是让调试器拦截。本文将以 docs/commands/debug-control/erun.md 为主体结合 src/dbg/commands/cmd-debug-control.cpp 与 src/dbg/debugger.cpp 的源码实现完整讲解该命令的语法、执行原理、与run/serun的差异以及实战使用场景。读完本文你将掌握如何在 x64dbg 命令行与脚本中一口气跨过所有首次异常直达目标断点。命令语法与参数根据 erun.md 的定义erun [arg1]erun主命令名命令注册时同时绑定了一组别名见 src/dbg/x64dbg.cppdbgcmdnew(erun,egun,er,eg, cbDebugErun, true); //run skip first chance exceptions因此以下四个写法完全等价均会触发跳过首次异常并继续运行的行为命令说明erun主命令egun别名 1er别名 2短命令eg别名 3短命令[arg1]可选参数指定一个地址或表达式作为目标位置。当提供该参数时x64dbg 会在运行之前于该位置放置一个一次性断点single-shot breakpoint程序运行到该地址后自动停下来随后该断点即被消耗。具体实现见下文参数与一次性断点小节。命令的行为语义原文档对erun的行为描述非常精炼Free the lock and allow the program to run, passing all first-chance exceptions to the debuggee.释放锁并允许程序运行将所有首次异常转交给被调试程序。这句话包含两个关键动作释放调试锁Free the lockx64dbg 的调试循环在暂停时会持有WAITID_RUN等待信号erun通过unlock(WAITID_RUN)唤醒调试循环使程序恢复执行跳过首次异常passing all first-chance exceptions to the debuggee与普通的run不同erun会在运行前设置跳过异常标志调试循环在收到EXCEPTION_DEBUG_EVENT且为首次异常时不暂停、直接以DBG_EXCEPTION_NOT_HANDLED状态交还系统由被调试程序的异常处理器如 SEH继续处理。与 run / serun 的区别在 src/dbg/commands/cmd-debug-control.cpp 中三个命令的实现对比一目了然bool cbDebugRun(int argc, char* argv[]) { skipInt3Stepping(1, argv); return cbDebugRunInternal(argc, argv, history_clear); } bool cbDebugErun(int argc, char* argv[]) { if(!dbgisrunning()) dbgsetskipexceptions(true); else { dbgsetskipexceptions(false); return true; } return cbDebugRunInternal(argc, argv, history_clear); } bool cbDebugSerun(int argc, char* argv[]) { cbDebugContinue(argc, argv); return cbDebugRunInternal(argc, argv, history_clear); }命令首次异常处理说明run/go/r/g按异常过滤器正常处理遇到配置为需要断下的首次异常如加载 DLL 时的常见异常会暂停erun/ego/er/eg全部转交给被调试程序不拦截任何首次异常一路运行到底serun/sego先Continue再运行吞掉swallow当前异常后继续运行详见 serun.md从源码可以推断三者的适用场景差异run常规继续运行适用于大多数普通调试流程erun适用于目标程序频繁抛出无害的首次异常例如未处理的EXCEPTION_ACCESS_VIOLATION探测、EXCEPTION_ILLEGAL_INSTRUCTION自检、反调试陷阱等希望调试器无视这些异常直到命中真正的断点serun适用于调试器当前正停在某个异常上希望先以已处理的方式继续相当于在异常对话框中选择继续再运行。参数与一次性断点erun [arg1]的第二个参数会转换为一个一次性断点其逻辑位于公共的cbDebugRunInternal中bool cbDebugRunInternal(int argc, char* argv[], HistoryAction history) { // History handling if(history history_record) HistoryRecord(); else HistoryClear(); // Set a singleshot breakpoint at the first parameter if(argc 2 !DbgCmdExecDirect(StringUtils::sprintf(bp \%s\, ss, argv[1]).c_str())) return false; // Dont run twice if the program is already running if(dbgisrunning()) return false; GuiSetDebugStateAsync(running); unlock(WAITID_RUN); PLUG_CB_RESUMEDEBUG callbackInfo; callbackInfo.reserved 0; plugincbcall(CB_RESUMEDEBUG, callbackInfo); return true; }关键点内部调用bp命令当argc 2时erun会通过DbgCmdExecDirect执行等价于bp 地址, ss的命令即SetBPX的一次性singleshoot模式。一次性断点在命中后自动删除因此不会污染断点列表适合跑到某个地址就停一次的临时目标参数表达式支持由于bp的地址参数支持表达式解析arg1可以是401000、kernel32.CreateFileW、entry等任意能被表达式解析器求值的写法重复运行保护如果程序已经在运行中dbgisrunning()为真erun不会重复触发而是直接返回避免二次unlock造成状态错乱GUI 与插件回调恢复运行前会调用GuiSetDebugStateAsync(running)通知界面更新状态并通过plugincbcall(CB_RESUMEDEBUG, ...)通知所有已加载插件见 src/dbg/plugin_loader.h 相关回调机制。底层原理首次异常如何被跳过1. 跳过标志的设立cbDebugErun在程序未运行时调用dbgsetskipexceptions(true)该函数定义于 src/dbg/debugger.cppvoid dbgsetskipexceptions(bool skip) { bSkipExceptions skip; skipExceptionCount 0; }它设置全局静态标志bSkipExceptions定义于 src/dbg/debugger.cpp并重置跳过计数skipExceptionCount。注意erun还有一个细节当程序已经在运行时再次输入erun会调用dbgsetskipexceptions(false)取消跳过并直接返回——也就是说erun在运行态下相当于一个取消跳过开关用于恢复对异常的拦截。2. 异常分发路径中的判断当被调试程序抛出异常时调试循环在异常处理函数中执行如下判断src/dbg/debugger.cppif(ExceptionData-dwFirstChance) //first chance exception { if(filter.logException) { if(exceptionName.size()) dprintf(QT_TRANSLATE_NOOP(DBG, First chance exception on %p (%.8X, %s)!\n), addr, ExceptionCode, exceptionName.c_str()); else dprintf(QT_TRANSLATE_NOOP(DBG, First chance exception on %p (%.8X)!\n), addr, ExceptionCode); } dbgsetcontinuestatus(filter.handledBy ExceptionHandledBy::Debuggee ? DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE); if((bSkipExceptions || filter.breakOn ! ExceptionBreakOn::FirstChance) (!maxSkipExceptionCount || skipExceptionCount maxSkipExceptionCount)) return; }这段代码揭示了erun跳过异常的完整机制判定依据ExceptionData-dwFirstChance非零表示这是首次异常first-chance exception。Windows 调试 API 中异常会先以首次异常的形式投递给调试器若调试器不处理系统会再次以末次异常last-chance投递继续状态根据异常过滤器的handledBy配置设置DBG_EXCEPTION_NOT_HANDLED转交被调试程序处理或DBG_CONTINUE调试器直接吞掉跳过条件当bSkipExceptions为真即erun已开启跳过模式并且跳过次数未达到上限maxSkipExceptionCount时函数直接return不执行后续的lock(WAITID_RUN)暂停逻辑程序因此得以连续运行日志输出即使被跳过异常仍会以First chance exception on ...的形式记录到日志中方便用户事后追溯哪些异常被忽略了暂停时复位一旦程序真正暂停例如命中一次性断点或用户pausesrc/dbg/debugger.cpp 会调用dbgsetskipexceptions(false)复位标志因此跳过模式不会跨暂停残留。3. 与 eStepInto / eStepOver / eStepOut 的家族关系erun并非孤立的命令。在 src/dbg/x64dbg.cpp 中可以看到完整的e 前缀命令族它们共享同一个跳过首次异常的理念dbgcmdnew(erun,egun,er,eg, cbDebugErun, true); //run skip first chance exceptions dbgcmdnew(eStepInto,esti, cbDebugeStepInto, true); //StepInto skip first chance exceptions dbgcmdnew(eStepOver,estep,esto,est, cbDebugeStepOver, true); //StepOver skip first chance exceptions dbgcmdnew(eStepOut,ertr, cbDebugeStepOut, true); //rtr skip first chance exceptions因此如果你需要在单步eStepInto/eStepOver/eStepOut参见 docs/commands/debug-control/eStepInto.md 等文档时同样跳过首次异常可以直接使用带e前缀的对应命令而erun则是这套机制在自由运行场景下的版本。实战使用场景场景一快速越过异常密集的启动代码调试使用异常做自校验的加壳程序时入口点附近往往连续抛出多个首次异常。常规run会频繁暂停此时erun即可让程序一直运行到第一个真正配置为需要断下的断点例如 DLL 加载断点或主动设置的bp期间所有首次异常都被转交目标进程处理。场景二运行到指定地址后停下希望跳过所有首次异常但运行到401000处暂停一次erun 401000erun会在运行前内部执行bp 401000, ss放置一次性断点命中后断点自动消耗之后可继续手动调试。也可结合表达式erun kernel32.VirtualAlloc场景三在脚本中配合单步命令使用在 x64dbg 的脚本scriptload加载的脚本文件或命令行脚本中erun同样可以直接调用且注册时debugonly参数为true见dbgcmdnew的第三个参数意味着它仅在调试会话中有效。若在脚本中需要先跳过异常再单步可参考 src/dbg/simplescript.cpp 中关于单步过erun的注释脚本引擎在执行erun后会等待程序再次暂停因此其后的脚本指令会在命中下一次暂停时继续执行。另外脚本命令列表中明确收录了erunsrc/dbg/script_commands.txt脚本编辑器会据此提供语法高亮与补全。场景四运行中取消跳过模式如果在程序运行过程中例如在另一个线程的脚本中输入erun根据cbDebugErun的 else 分支它不会再次解锁运行而是执行dbgsetskipexceptions(false)取消异常跳过相当于把后续异常拦截恢复为正常行为。这与暂停后恢复运行是两种不同语义使用时需注意当前程序状态。结果变量按照原文档的说明erun命令不会设置任何结果变量result variables例如$result或$_pid等。因此无法通过$result判断命令是否成功要判断是否已恢复运行可通过后续暂停事件、日志输出First chance exception on ...与Resumed等状态信息或dbgisrunning类查询来确认。总结要点内容命令/别名erun、egun、er、eg核心行为释放调试锁继续运行并将所有首次异常转交被调试程序处理可选参数[arg1]地址/表达式运行前放置一次性断点结果变量无底层实现cbDebugErun →dbgsetskipexceptions(true)→ 异常分发路径 bSkipExceptions 判断相关命令run不跳过、serun吞掉当前异常、eStepInto/eStepOver/eStepOut单步跳过异常当你在逆向分析中频繁被首次异常打断时erun是让调试流程一气呵成直达目标断点的最直接工具。理解其一次性断点 跳过首次异常的组合机制并配合serun、e前缀单步命令按需选用即可在异常密集的目标上保持高效的调试节奏。【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考