Skip to content

基本用法和技巧

动态调试

  • 窗口区域:
    • 左上 -- 反汇编
    • 右上 -- 寄存器
    • 右下 -- 栈区
    • 左下 -- 内存
  • Ctrl+G 跳转到指定地址
  • 通过函数头部断点进行栈回溯
    • F2 下断点
    • 根据栈帧结构,程序运行到函数头部 push ebp 处时,栈顶指针指向函数返回地址(刚刚通过 call 把 eip 压栈)
    • 跳转到 esp 中的地址(^G输入 或右键地址->在反汇编中转到指定DWORD),即为该函数的返回地址,在调用该函数的函数中
    • 在上一层函数中重复操作,可以进行栈回溯
    • 另一种方法 “运行到返回(X)”后单步步进或步过,让函数自己返回跳转到上一层函数。
  • 双击栈区地址显示以该地址为基的偏移
  • 判断参数个数的技巧:在目标函数的 call 指令处下断点,记录执行 call 之前的 esp,再步过,记录执行 call 之后的 esp,两个 esp 的差值就是被调函数内部自己做的栈平衡(stdcall),以此判断参数个数。 -- 如相差8字节,x86下若一个参数4字节,则有两个参数。同理 cdecl 可以通过 call 之后的栈平衡操作(add esp ?)来判断。

以下为 x64dbg (及其 32 位版本 x32dbg) 的全面、专业使用指南与逆向分析技巧总结。该内容涵盖基础操作、核心功能、调试策略及高级技巧,旨在建立从“观察者”到“控制者”的动态调试思维体系。


一、 工具概述与基础架构

x64dbg 是一款开源的、用户模式(User-Mode)的 Windows 调试器。其核心设计理念是现代化的界面与强大的插件扩展性。

  • x32dbg.exe:专门用于调试 32 位(x86)可执行文件。

  • x64dbg.exe:专门用于调试 64 位(x64)可执行文件。

  • 适用场景:恶意代码分析、CTF 逆向、漏洞挖掘、协议分析。

1. 界面布局 (CPU 视图)

CPU 视图是调试的核心工作区,分为四个主要象限:

  • 左上:反汇编窗口 (Disassembly)

    • 显示程序的汇编代码、地址(Address)、机器码(Bytes)和注释(Comment)。

    • EIP/RIP 指针:高亮显示的行代表当前 CPU 即将执行的指令。

  • 右上:寄存器窗口 (Registers)

    • 实时显示 CPU 寄存器(EAX/RAX, EBX/RBX, EIP/RIP, ESP/RSP 等)的数值。

    • 标志位 (Flags):显示 ZF (零标志), OF (溢出标志), CF (进位标志) 等,直接决定条件跳转(JZ, JNE)的结果。

  • 左下:内存转储窗口 (Dump)

    • 显示内存中的原始数据(Hex 和 ASCII/Unicode)。用于查看变量值、解密后的字符串或文件结构。
  • 右下:栈窗口 (Stack)

    • 显示当前线程的栈空间内容。用于追踪函数调用参数、返回地址(Return Address)和局部变量。

二、 核心控制与快捷键

熟练掌握快捷键是提高调试效率的基础。

快捷键 功能 描述
F9 运行 (Run) 程序继续执行,直到遇到下一个断点或异常。
F2 软件断点 (Breakpoint) 在当前选中行设置/取消 INT 3 断点。
F7 单步步入 (Step Into) 执行当前指令。遇到 CALL 指令时,进入子函数内部。
F8 单步步过 (Step Over) 执行当前指令。遇到 CALL 指令时,执行完整个子函数,停在下一行。
F4 运行到选定位置 程序运行直到 EIP/RIP 命中所选中的行(相当于临时断点)。
Ctrl + F2 重载 (Restart) 重新加载当前调试的程序(从头开始)。
Alt + F9 运行到用户代码 当程序陷入系统 DLL(如 ntdll.dll)时,快速跳出并返回程序领空。
- / + 后退/前进 在反汇编视图的浏览历史中导航(不影响执行流)。
Space 汇编 (Assemble) 修改当前指令(Patch 代码)。
Shift + F9 运行并传递异常 把调试器拦截的异常传递给程序,按照程序自己的逻辑处理。
Ctrl + F9 执行到返回 执行到当前函数的最后一条指令。
Alt + K 打开调用堆栈窗口 查看调用堆栈

命令行:

命令 功能
bphc BreakPoint Hardware Clear,清除所有硬件断点

三、 断点机制 (Breakpoints)

断点是拦截程序执行流的核心手段。x64dbg 支持三种主要断点:

1. 软件断点 (Software Breakpoint, F2)

  • 原理:调试器将目标地址的第一个字节修改为 0xCC (指令 INT 3)。CPU 执行到此指令时触发异常,控制权移交调试器。

  • 优点:数量无限制。

  • 缺点:修改了内存代码,可能被程序检测(自校验/CRC 校验)。

2. 硬件断点 (Hardware Breakpoint)

  • 原理:利用 CPU 的调试寄存器 (DR0-DR3)。

  • 操作:在寄存器或内存地址上右键 -> 硬件断点 -> 选择 访问、写入 或 执行。

  • 优点:不修改内存代码,隐蔽性高,可监控内存读写(例如:监控 flag 变量何时被写入)。

  • 限制:最多只能设置 4 个。

3. 内存断点 (Memory Breakpoint)

  • 原理:修改内存页的权限(如设置为不可访问)。当程序尝试访问该内存页时触发异常。

  • 操作:在内存转储窗口选中区域 -> 右键 -> 断点 -> 内存访问/写入。

  • 场景:用于定位大块内存(如解压后的代码段、Shellcode)何时被执行或读取。


四、 逆向分析策略与技巧

在动态调试中,寻找“切入点”至关重要。

1. 字符串搜索法 (String References)

这是 CTF 和简单逆向中最快的切入点。

  • 操作:在反汇编窗口右键 -> 搜索 -> 当前模块 -> 字符串引用。

  • 逻辑:搜索 "Success", "Failed", "Wrong", "Correct" 等提示信息。双击跳转到代码处,向上回溯查找 CMP(比较)和 JNZ/JE(跳转)指令。

2. API 断点法 (Intermodular Calls)

当程序加壳或字符串被加密时,需拦截程序与操作系统的交互。

  • 操作:反汇编窗口右键 -> 搜索 -> 当前模块 -> 模块间调用。

  • 关键 API:

    • 输入/输出:GetWindowText, GetDlgItemText, MessageBox。

    • 文件操作:CreateFile, ReadFile, WriteFile。

    • 注册表:RegOpenKey, RegQueryValue。

  • 技巧:在输入 API(如 GetWindowText)下断点。程序中断后,使用 F8 单步跟踪,观察内存中何时出现输入的数据。

3. 智能补丁 (Patching)

直接修改程序逻辑以绕过验证。

  • 修改跳转:选中 JZ (74) 指令,按空格键,修改为 JNZ (75) 或 JMP (EB)。

  • NOP 填充:选中不需要的代码(如检测函数),右键 -> 二进制 -> 用 NOP 填充。

  • 保存更改:点击菜单栏 文件 -> 补丁 -> 修补文件,将修改保存为新的 EXE。

4. 栈回溯 (Stack Tracing)

当程序中断在系统 DLL(如 kernel32.dll)内部时,需要知道是谁调用了它。

  • 操作:查看栈窗口(Stack)的底部,寻找返回地址(Return to ...)。

  • 技巧:在栈窗口右键 -> 在反汇编中跟随。通常能直接跳回到用户代码中调用该 API 的位置。


五、 高级调试技巧

1. 修改寄存器与标志位 (The "Magic" Toggle)

在验证逻辑极其复杂(如高强度加密算法)难以逆向时,可直接修改结果。

  • 场景:遇到 test eax, eax 紧接着 je failure。

  • 操作:当程序停在跳转指令时,双击寄存器窗口中的 ZF (Zero Flag) 标志位(0 变 1,或 1 变 0)。

  • 效果:强制改变跳转路径,直接让程序走进“成功”分支。

2. 内存跟随 (Follow in Dump)

用于实时监控数据的变化。

  • 操作:在寄存器窗口(如 EAX 指向缓冲区)右键 -> 在内存窗口中跟随。

  • 作用:在单步调试解密循环时,内存窗口会实时刷新,能直观看到密文逐渐变成明文的过程。

3. 脚本自动化 (Scripting)

x64dbg 拥有强大的内置脚本引擎,可用于自动化解包或去混淆。

  • 示例指令:

    • bp 0x401000 (设置断点)

    • run (运行)

    • mov eax, 1 (修改寄存器)

    • log "EAX value: {eax}" (记录日志)

4. 插件扩展 (ScyllaHide & Scylla)

  • ScyllaHide:用于隐藏调试器。许多程序有反调试机制(检测 IsDebuggerPresent 等),ScyllaHide 可以 Hook 这些 API,欺骗程序“没有被调试”。

  • Scylla:用于导入表(IAT)修复和内存转储(Dump)。在手动脱壳时,用于将内存中解压好的程序保存到磁盘。


六、 总结:静态与动态的结合

  • IDA Pro (静态):用于宏观分析,构建代码逻辑图,识别算法结构,重命名函数。相当于“看地图”。

  • x64dbg (动态):用于微观验证,查看运行时数据,绕过检测,暴力破解。相当于“实地考察”。

最佳实践工作流:

  1. 用 IDA 打开程序,寻找关键字符串或函数。

  2. 记录关键地址(基址 + 偏移)。

  3. 用 x64dbg 打开程序,定位到该地址 (Ctrl + G)。

  4. 下断点,运行,输入测试数据。

  5. 观察寄存器和内存与输入的对比。

  6. 修改标志位或代码逻辑,验证假设。