动态调试

动态分析技术中最重要的工具是调试器,分为用户模式和内核模式两种类型。

用户模式调试器:Ollydbg、x64dbg、MDebug

内核模式调试器:Windbg

32位程序的调试:Ollydbg

64位程序的调试:IDA pro、x64dbg、Mdebug、Windbg

Ollydbg

Ollydbg (简称“OD”)是由Oleh Yuschuk编写的一款具有可视化界面的用户模式调试调试器,可以在当前各个版本的Windows上运行,但NT系统架构更能发挥Ollydbg的强大功能。Ollydbg结合了动态调试和静态分析,具有GUI界面,非常容易上手,对异常的跟踪处理相当灵活。

界面

默认当前窗口是CPU窗口

  1. 反汇编窗口

    反汇编窗口显示被调试程序的代码,有4列,分别是地址、十六进制的机器码、反汇编代码和注释。在最后一列注释中显示了相关API参数或运行简表,非常有用。

    在汇编面板窗口的列中,默认情况下,双击可以完成如下操作。

    • Address列:显示被双击行地址的相对地址,再次双击返回标准地址模式
    • Hex dump列:设置或取消无条件断点,对应的快捷键是“F2”键
    • Disassembly列:调用汇编器,可直接修改汇编代码,对应快捷键是空格键。
    • Comment列:允许增加或编辑注释,对应快捷键是“;”键
  2. 信息面板窗口

    在进行动态跟踪时,信息面板窗口将显示与指令相关的各寄存器的值、API函数调用提示和跳转提示等信息

  3. 数据面板窗口

    数据面板窗口以十六进制和字符方式显示文件在内存中的数据。要显示指定内存地址的数据,可单击右键快捷菜单中的“Go to expression” 命令或按“Ctrl+G“, 打开地址窗口,输入地址

  4. 寄存器面板窗口

    寄存器面板窗口显示CPU各寄存器的值,支持浮点、MMX和3DNow!寄存器。可以单击右键或窗口标题切换显示寄存器的方式

  5. 栈面板窗口

    栈面板窗口显示栈的内容,即ESP指向地址的内容。将数据放入栈的操作称为入栈(push),从栈中取出数据的操作称为出栈(pop)。栈窗口非常重要,各API函数和子程序都利用它传递参数和变量等。

基本操作

调试器的一个最基本的功能就是动态跟踪。

快捷键功能
F7单步步进,遇到call指令跟进
F8单步步过,遇到call指令路过,不跟进
Ctrl+F9直到出现ret指令时中断
Alt+F9若进入系统领空,此命令可瞬间回到应用程序领空
F9运行程序
F2设置断点

其他快捷键

快捷键功能
Ctrl+F2重新调试目标程序
F12暂停程序

断点

INT3

这是一个常用的断点。在Ollydbg中可以使用bp命令或者F2快捷键来设置/取消断点。

INT3指令,因其机器码是0xCC,也常被称为“CC指令”。当被调试进程执行INT3指令导致一个异常时,调试器就会捕捉这个异常,从而停在断点处,然后将断点处的指令恢复成原来的指令。

优点:可以设置无数个断点

缺点:改变了原程序机器码,容易被软件检测到

检测API的首地址是否为CC来检测断点

硬件断点

硬件断点和DRx调试寄存器有关。在Intel CPU体系架构手册中可以找到对DRx调试寄存器的介绍

DRx调试寄存器共有8个(DR0-DR7),每个寄存器的特性如下。

  • DR0~DR3:调试地址寄存器,用于保存需要监视的地址
  • DR4~DR5:保留
  • DR6:调试寄存器组状态寄存器
  • DR7:调试寄存器组控制寄存器

硬件断点的原理是使用DR0、DR1、DR2、DR3设定地址,并使用DR7设定状态,因此最多设置4个断点

优点:速度快

缺点:最多只能使用4个断点

内存断点

Ollydbg可以设置内存访问断点或内存写入断点,原理是对所设的地址赋予不可访问/不可写属性,这样当访问/写入的时候就会产生异常。Ollydbg截获异常后,比较异常地址是不是断点地址,如果是就中断,让用户继续操作。

因为每次出现异常时都要通过比较来确定是否应该中断,所以内存断点会降低Ollydbg的执行速度——也许Ollydbg考虑到执行速度才规定只能下1个内存断点吧。

程序运行时有三种状态,分别是读取、写入和执行。

内存断点不修改原始代码,不会像INT3断点那样因为修改代码被程序校验而导致失败。因此,在遇到代码校验且硬件断点失灵的情况下,可以使用内存断点

内存访问一次性断点

Windows对内存使用段页式的管理方式。在Ollydbg里按“Alt + M” 快捷键显示内存,可以看到许多个段,每个段都有不可访问、读、写、执行属性。

这类断点仅在NT架构下可用

消息断点

Windows本身是由消息驱动的,如果调试时没有合适的断点,可以尝试使用消息断点。当某个特定窗口函数接收到某个特定消息时,消息断点将使消息程序中断。

消息断点与INT3断点的区别在于:INT3断点可以在程序启动之前设置,消息断点只有在窗口被创建之后才能被设置并拦截消息

条件断点

在调试过程中,我们经常希望断点在满足一定条件时才会中断,这类断点称为条件断点。Ollydbg的条件断点可以按寄存器、存储器、消息等设断。条件断点是一个带有条件表达式的普通INT3断点。当调试器遇到这类断点时,断点会计算表达式的值,如果结果非零或者表达式有效,则断点生效。

shift+F2

条件记录断点

Run trace

Run trace(Run跟踪) 可以把被调试程序执行过的指令保存下来,以便了解以前发生的事件。

Hit trace

Hit trace能够让调试者辨别那一部分代码被执行,哪一部分没有。

调试符号

调试符号是被调试程序的二进制信息与源程序信息之间的桥梁,是在编译器将源文件编译为可执行程序的过程中为支持调试而摘录的调试信息。调试信息包括变量、类型、函数名、源代码行等。

符号格式

符号表(又称“调试符”)的作用是将十六进制数转换为源文件代码行、函数名及变量名。符号表中还包含程序使用的类型信息。调试器使用类型信息可以获取原始数据,并将原始数据显示为程序中所定义的结构或变量

  1. SYM
  2. COFF
  3. CodeView
  4. PDB
  5. DBG
  6. MAP

加载程序

Ollydbg可以用两种方式加载目标程序调试

  1. 通过CreateProcess创建进程
  2. 利用DebugActiveProcess函数将调试器捆绑到一个正在运行的进程上

x64dbg

x64dbg是一款开源的调试器,既支持32位和64位程序的调试,也支持插件的功能扩展,类似于C的表达式解析器,提供了图形模式代码流程、可调试的脚本支持等强大的功能。其界面及操作方法与Ollydbg相似,很容易上手。

Q.E.D.