x64dbg开源,一直在更新,支持64位程序,还多了一些功能,比Ollydbg好用,没学OD的可以不用学了(
以下内容分析目标是64位程序,使用的是x64dbg,部分功能具体可能不同(比如寄存器名称、硬件断点可用字节数)
CPU窗口
随便拖入一个可执行文件,会自动进入到CPU选项卡界面,可以看到四个窗口:
反汇编窗口
左上角的反汇编窗口,这里显示是我们要分析的程序的反汇编代码(注意是可以上下左右拖动的):
最左侧蓝色箭头显示的是EIP寄存器的指向,也就是运行到此处时下一条执行指令的位置,一般用于查看跳转,点击对应行,相应的箭头指示会变粗
黑灰色的一行表示程序的入口
拿出来一行看看:
00007FFA08B44402 | 48:C7C1 FEFFFFFF | mov rcx,FFFFFFFFFFFFFFFE | rcx:NtQueryInformationThread+14
-
第一列:
00007FFA08B44402表示的是当前这条汇编指令所在的地址
每一列的地址都是依次排序的,第二行的地址是第一行的地址再加上指令长度
在第一列双击可以看到一个箭头,你可以 以这个位置为起始地址,看到相对于这个地址的偏移:
-
第二列:
48:C7C1 FEFFFFFF是机器码/操作码opcode,是给计算机看的语言
在这个位置双击(或者选择该行点击F2),可以下一个断点,对应的地址列会变红:
-
第三列:
mov rcx,FFFFFFFFFFFFFFFE是汇编指令,也就是opcode指令翻译成的汇编语言
在这个位置按空格可以修改汇编代码(最好勾选上剩余字节以NOP填充):
-
第四列:
rcx:NtQueryInformationThread+14是注释
点击
;键可以添加/修改注释:
寄存器窗口
右上角的寄存器窗口显示调试程序的寄存器信息:
可以双击某一个寄存器对值进行修改:
或许你会看见不同的寄存器名称:
| 时代 | 位宽 | 寄存器命名特征 | 示例 |
|---|---|---|---|
| 8086(out) | 16 位 | AX、BX、CX、DX、SI、DI、BP、SP、IP | 如:AX 表示累加寄存器 |
| 80386 | 32 位 | 在 16 位基础上加前缀 E(Extended,扩展) | EAX、EBX、ECX、EDX、ESI、EDI、EBP、ESP、EIP |
| x86-64 | 64 位 | 在 16 位基础上加前缀 R(Register) | RAX、RBX、RCX、RDX、RSI、RDI、RBP、RSP、RIP |
内存窗口
左下角的数据窗口是内存地址的内容
最左边是内存地址,接着是对应地址的十六进制数据,最右侧是十六进制对应的ASCII码:
我们可以选中数据进行复制:
也可以双击某一个字节进行修改:
堆栈窗口
右下角是堆栈窗口,显示的是堆栈信息:
可以双击某一行对它进行修改:
快捷键
善用鼠标右键,很多功能都在里面,包括常用的查找搜索功能等等,快捷键只是更快使用它们而已
选项 -> 快捷键,可以查看和自定义快捷键:
下面是一些常用的快捷键:
| 快捷键 | 功能说明 |
|---|---|
| F2 | 设置 / 取消断点 |
| Ctrl + F2 | 重新启动调试(F2的断点还在) |
| Alt + F2 | 关闭当前程序 |
| F4 | 运行到选中行处 |
| F7 | 单步步入(进入函数,跟着call去函数内部) |
| F8 | 单步步过(不进入函数,跳过call,执行完当前函数) |
| Shift + F7 | 条件单步步入 |
| Shift + F8 | 条件单步步过 |
| Ctrl + F7 | 自动步入(重复单步进入) |
| Ctrl + F8 | 自动步过(重复单步步过) |
| F9 | 运行程序 / 继续执行 |
| Ctrl + F9 | 执行到返回,用于快速跳出当前函数 |
| Alt + F9 | 执行到用户代码,用于快速跳出系统函数 |
| F12 | 暂停程序 |
| Ctrl + G | 跳转到目标地址 / 表达式 |
| Ctrl + Shift + F | 在模块中搜索字符串 |
| Ctrl + F | 搜索指令或数据 |
| Ctrl + B | 搜索十六进制 |
| Ctrl + L | 搜索下一个 |
| Alt + Ins | 复制地址 |
| Shift + D | 在引用窗口全局搜索字符串 |
| Enter | 跟随跳转(如 call / jmp 目标) |
| Alt + M | 打开内存映射窗口 |
| Alt + K | 打开调用堆栈窗口 |
| Alt + B | 打开断点列表 |
| Space | 汇编 / 编辑当前指令 |
| ; | 添加注释 |
| Ctrl + P | 打开补丁窗口 |
断点
软件断点
在程序执行到特定指令时暂停程序执行
这种断点类型是由调试器模拟实现的,通常通过修改程序指令来实现
它是最常见的断点类型,因为可以在任何代码段中设置断点(但有些地方下断会导致系统崩溃,特别是内核)
快捷键下断点
通过F2 / 双击操作码可以在对应位置下断点,会以红色标注,而当前IP指针则会使灰色显示,如下图所示:
命令下断点
软件断点同样可以在最下方的命令输入窗口使用bp/bpx等命令下断,或通过bc来取消断点:
bp 00007FFA08B44425
跳转目标位置下断点
当需要在特定函数上下断点时,可通过Ctrl+G调出地址跳转表达窗口,输入目标函数,跳转后手动下断点:
当然也支持输入命令:
bp MessageBoxA
结合条件下断点
这个是对断点附加触发条件的方法
右键对应指令设置条件断点:
输入暂停条件,只有当满足特定条件表达式时,断点才会触发:
硬件断点
硬件断点是利用CPU的调试寄存器DR0–DR3来实现的,这些寄存器用于跟踪指令地址和数据访问地址
硬件断点不修改内存,通常比软件断点更快,但是受到硬件限制,每次能断的字节和总数量有限
在内存数据窗口选中某一块地址,之后右键即可选择要下的硬件断点:
硬件访问断点
当程序尝试从指定内存地址读取数据时触发
比较少使用,主要是监控敏感变量或内存内容被读取
硬件写入断点
当程序尝试向指定内存地址写入数据时触发
是常用的类型,比如跟踪变量、缓冲区、密钥、解密结果等数据什么时候被修改
硬件执行断点
当程序执行到指定地址时触发
相当于软件断点,但由CPU调试寄存器实现,不修改代码,无INT3中断指令
放在函数入口或特定指令上中断执行,能避免被反调试检测
内存断点
通过改变页表属性或分段保护实现,当程序在特定内存地址处读取、写入或执行时,暂停程序执行
内存断点是按照内存页(4KB)监控的,也就是一旦监控了一个地址,就等于监控该地址所在整个页面
它的范围广,但性能开销高,并且某些情况下是不够精确的,因为页的内存可能有很多指令在修改,会有干扰
内存断点分两种:
| 类型 | 触发次数 | 触发后行为 | 说明 | 常见用途 |
|---|---|---|---|---|
| 一次性断点 | 仅触发 一次 | 命中后自动删除 | 程序命中该断点暂停一次后,调试器会自动清除该断点 | 临时观察某处是否会被访问或执行,用于快速验证逻辑 |
| 重复断点 | 可触发 多次 | 命中后仍保留 | 程序每次命中都会暂停 | 长期监控某个内存或代码地址,例如循环中的多次写入或读取 |
内存访问断点
当程序试图访问特定内存地址时触发
最通用的类型,监控任意对敏感内存的操作,如全局变量或关键数据区
内存读取断点
当程序试图从特定内存地址读取数据时触发
用于分析某数据在何处被读取,例如密码、密钥或结构体成员
内存写入断点
当程序试图写入特定内存地址时触发
用于跟踪变量变化、解密过程、缓冲区写入等场景
内存执行断点
当程序试图执行特定内存地址处的指令时触发
类似软件断点,但不依靠INT3,而是靠修改页属性,用于检测动态代码执行、Shellcode或自修改代码
消息断点
这是一种特殊的断点,通过监控处理消息循环实现,当程序接收到指定类型的消息时,暂停程序执行
可以用于监视程序执行期间的Windows消息,包括键盘输入、鼠标操作、窗口消息等
消息断点在调试GUI程序时非常有用,可以帮助调试窗口消息的处理代码,定位程序中的错误或异常行为
例如,当你想要调试一个窗口消息处理函数时,可以在该函数上设置消息断点,当程序接收到对应的消息时,程序会暂停在该函数内部,方便进行调试
保存文件
如图,我们随便修改了这个程序的一些指令:
为了试运行而不影响源文件,就需要另存为新的文件
在反汇编窗口右键,选择补丁(patch),或者Ctrl+P:
接着点击修补文件即可另存:
基础使用就到这里,更多方法还要在实战里体会~