x64dbg是一款开源的动态调试工具,广泛应用于Windows平台的软件逆向工程中。
安装
x64dbg官网地址:x64dbg
区别
动态反汇编调试(Dynamic Disassembly Debugging)是指在程序运行时动态地反汇编机器码,从而获取指令级别的执行信息和内存访问情况,以辅助调试和分析程序。动态反汇编调试需要借助特殊的调试工具,如GDB、x64dbg、Ollydbg等,通常用于调试崩溃、死锁、内存泄漏等问题。
静态反汇编调试(Static Disassembly Debugging)是指对程序进行反汇编分析,不需要运行程序,只需要对程序进行静态分析就可以获得指令级别的执行信息和内存访问情况,以辅助调试和分析程序。静态反汇编调试需要使用特殊的工具,如IDA Pro、Binary Ninja等,通常用于逆向工程、恶意代码分析、漏洞挖掘等方面。
x64dbg使用技巧
认识x64dbg窗口
左上区域为反汇编窗口。当程序运行时,其源代码会被编译成机器码,这是计算机硬件直接执行的指令集。反汇编窗口允许用户查看这些机器码对应的汇编指令。
左下角区域为数据窗口,用于展示和编辑程序运行时的内存数据。
右上区域为寄存器窗口,该窗口用于显示和解释当前线程环境下CPU寄存器的各种状态值和内容。
右下角区域为堆栈窗口。堆栈窗口用于显示当前线程的栈,堆栈窗口会随着ESP(Extended Stack Pointer)寄存器的变化而变化,ESP指向当前栈顶元素的地址。
调试技巧
- 断点设置:
- 使用F2键可以快速在当前汇编指令处设置断点。
- 可以通过在断点界面右键点击“编辑”来设置断点条件,如寄存器值变化或特定内存地址访问等。
- 单步执行:
- F7键用于单步步入,即如果当前行是函数调用,则进入该函数内部。(遇到call指令,进入call函数的实现处继续执行汇编指令)
- F8键用于单步步过,即执行当前行,如果当前行是函数调用,则执行完该函数后继续执行下一行。(遇到call指令,执行call函数,之后接着执行call指令的下一条指令)
- 快速定位:
- Ctrl+G组合键可以快速定位到指定的内存地址或代码地址。
- 在汇编窗口或内存窗口中,输入地址后按下Enter键也可以实现快速跳转。
- 高亮显示:
- 按下H键后,双击要高亮的文本,可以实现高亮显示,便于跟踪和观察。
- 在寄存器窗口右键点击寄存器名称,选择“高亮”,可以高亮显示该寄存器在反汇编窗口中的引用。
- 数据查看:
- 使用Dump窗口查看内存中的数据,可以切换视图以不同格式(如十六进制、字符串、Unicode字符串、浮点等)展示数据。
- 在寄存器窗口查看当前寄存器的值,注意关注指令执行前后寄存器值的变化。
断点分类
-
代码断点:在程序的汇编代码上设置的断点。当程序执行到该断点时,会暂停执行。这是最基本的断点类型,用于控制程序的执行流程。
-
内存断点:在特定内存地址上设置的断点。当程序访问(读取或写入)该内存地址时,会触发断点。内存断点对于监测内存访问和修改非常有用。
-
硬件断点:利用CPU的硬件调试寄存器设置的断点。与软件断点相比,硬件断点不占用程序的内存空间,且通常具有更高的性能。但是,由于硬件断点的数量有限(通常只有几个),因此需要谨慎使用。
-
条件断点:在满足特定条件时触发的断点。用户可以在设置断点时指定一个条件表达式,只有当该表达式为真时,断点才会触发。条件断点对于过滤不必要的断点触发非常有用。
-
消息断点:在某些特定的Windows消息(如按键消息、鼠标消息等)发生时触发的断点。这对于分析GUI程序的交互行为非常有帮助。
寄存器
在x64dbg中,寄存器主要可以分为以下几类:
-
通用寄存器:这些寄存器是程序执行代码时最常用也最基础的寄存器。在x64架构中,这些寄存器包括rax、rbx、rcx、rdx、rsp、rbp、rsi、rdi等,它们分别用于存放各种数据和执行各种操作。例如,rax通常用于存放函数调用的返回值,rsp作为栈顶指针指向栈的顶部,rbp作为栈底指针或用于定位栈中的局部变量等。
-
标志寄存器:标志寄存器中包含了CPU执行指令过程中的一系列状态信息,如进位标志(CF)、奇偶标志(PF)、零标志(ZF)、符号标志(SF)和补码溢出标志(OF)等。在x64架构下,原来的eflags寄存器升级为64位的rflags寄存器,但高32位并未新增功能,保留为将来使用。
-
指令寄存器:在x64架构中,32位的eip指令寄存器升级为64位的rip寄存器。它指向下一条要执行的指令的地址,是CPU工作的核心。
-
其他专用寄存器:除了上述通用寄存器外,x64架构还引入了其他专用寄存器,如控制寄存器(cr0-cr4及cr8)、段寄存器、调试寄存器等,它们各自承担着不同的功能,共同支持CPU的正常运行。
upx手动脱壳
x64dbg学习的差不多啦 我们来试试手动脱壳吧!
什么是壳
专门负责对程序体积进行压缩,或者是保护一个程序不被非法修改、逆向分析的一类软件。
壳通过附加自身代码在保护对象(原始程序)上,在操作系统对原始程序代码进行执行只求按获得程序控制权,进而对原始程序进行解压或解密等还原操作,完成操作后控制权将还给原始程序,程序的原始代码才开始被执行。
壳主要有压缩壳和加密壳两种:加壳软件在运行时运行外壳代码,对程序进行解压操作或解密操作,所以对于比较简单的壳,一般思路就是在运行完外壳操作后,找到源程序入口(即OEP–original entry pointer)将源程序通过工具dump出来为一个exe文件,然后再进行一些修复操作。
ESP定律
ESP定律的原理就是“堆栈平衡”原理。栈是一种后进先出(LIFO)的数据结构,用于存储函数调用的上下文信息。栈平衡是计算机科学中的一个重要概念,它通过静态分析和动态检查等手段来确保程序中的堆栈操作是正确的,防止堆栈溢出和错误,从而保障程序的正常运行。
ESP定律是计算机用语,指的是在程序执行过程中,尤其是函数调用时,ESP(栈顶指针寄存器)的值会发生变化,以反映栈上新的栈帧的创建。当函数返回时,ESP的值会恢复到函数调用之前的值,以保持栈的平衡。
ESP是栈顶指针寄存器,保存了下次将要弹出的内容,其遵循堆栈平衡原理,在壳对程序进行操作加密或者压缩时,会把程序的 OEP 压入栈中,当壳执行完成后,进行解密或者解压缩,会把真正的 OEP 从栈中弹出,从而找到程序入口点。
例题
把exe文件拖入x64dbg
pushad意味着upx壳解压缩代码的入口。
PUSHAD是一个x86汇编指令,用于将当前程序的所有通用寄存器(EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI)的值依次入栈。PUSHAD指令压入32位寄存器,其堆栈指针SP将加32。
但是这个程序是一个64位的。64位程序中没有puahad,而是用几个push汇编代码替代
F9运行到程序的起点
按F9到达该断点,最好可以都按几次,可能有其他断点
F8单步执行,观察右上角RSP是否有变化
ESP定律指的是,当观察到ESP(或RSP)寄存器的值在调试过程中变红,意味着程序执行流程中有重要的栈操作发生。
为了定位程序后续执行的关键点,可以定位ESP(或RSP)当前指向的内存地址,并在此地址上设置一个硬件断点。打一个硬件断点后,按下F9运行到停下的位置,这个位置后面一般有一处跳转,完成跳转之后的地方就是OEP(程序真正的入口点)
![](https://i-blog.csdnimg.cn/direct/0a4030bc196f4f029961a00b0c72e847.png)
操作过程
点击RSP 从内存窗口中转到
右击栈顶,选中断点,选择硬件访问断点,选择4字节。
打好断点后 F9运行
这里发现下面有一个比较大幅度的jmp跳转,并且已经显示文件特征。到达jmp后必须跳过去,此时再次执行F8,因为接下来就有可能是程序的OEP领空。
“OEP领空”可以理解为程序内存中,包含原始入口点及其周围代码和数据的、相对安全或未受保护的区域。
并且通常E9表示入口,判断jmp指令会跳转到OEP。
选中jmp指令 按下F4 运行到此处 F4键的功能是“运行到光标处”
之后按下F8步过让程序强制转到跳转下面继续运行,成功跳转到OEP!
脱壳结束
这就正式进入了原程序,可以进行dump了
dump
在x64dbg中,dump(转储)是一个非常重要的功能,它指的是将数据以某种格式导出或转存到文件中的过程。这个过程可以应用于多种数据类型和场景,包括但不限于内存、变量、对象、数据结构以及网络通信数据等。
启动插件
先进行dump
但是dump后的文件是无法执行的,所以我们要修复文件
文件修复
先点击 IAT Autosearch
再点击 Get Imports ,在 Imports 列表中右键delete删掉带有红叉的。
最后再fix dump
得到最终的exe文件成功去壳 可以在ida里运行
得到最终的flag