第9章 OllyDbg

Author Avatar
kabeor 7月 20, 2018

OllyDbg

OllyDbg被普遍用来分析恶意代码之前,最初的用途是破解软件。 Immunity Security公司买下 OllyDbg1.1的基础代码,并将其更名为Immunity Debugger(ImmDbg)。在此之前, OllyDbg直都是恶意代码分析师和漏洞开发者们的首选调试器。Immunity的目的是使这个工具适合漏洞开发者们使用,并且修复了OllDbg中的一些Bug。
在完成 OllyDbg的外观GUI修改,提供带有完整功能的 Python解释器API后,一些用户开始用ImmDbg替代OllyDbg

9x1 加载恶意代码

1. 打开一个可执行文件

选择OllyDbg界面中的File->Open, 然后浏览到要加载的可执行文件。
如果要调试的程序需要参数,则在Open对话框的 Arguments输入框给出(只能在加载期间给OllyDgb传入命令行参数)

默认情况下,如果能够确定软件的入口点位置,即 WinMain, OllyDbg会在这个位置暂停程序的执行。否则OllyDbg会在软件PE头部提供的入口点处中断。另外,你也可以选择 OllyDbg的DebuggingOptions菜单(Options→Debugging Options)来修改这些启动选项。

2. 附加调试器到一个运行程序

为将OllyDbg附加到一个进程上,选择OllyDbg界面的File→ Attach。然后会弹出一个菜单,你可以在这个菜单中选择要附加的进程(如果有多个同名的进程,你需要知道调试进程的ID)。接下来选择要调试的进程,并从菜单中选择Attach。此刻OllyDbg会立即暂停这个程序以及它所有的线程。

OllyDbg附加上进程后,进程当前执行线程的代码会被暂停,并显示在OllyDbg的窗口中。然而,有可能在进程正在执行一个系统DLL中的指令时把它暂停了,当这种情况发生时,回到主代码最简单的办法就是在整个代码段中设置一个访问断点。这样就会让这个程序在下次访问代码段时中断执行。

9x2 OllyDbg的接口

反汇编面板窗口
这个窗口显示了被调试程序的代码一当前指令指针的前后一些指令。通常,下一条将要被执行的指令在这个窗口中高亮显示。如果想要修改指令或数据(或添加一些汇编指令),请在这个窗口中按空格键。

寄存器面板窗口
这个窗口用来显示被调试程序寄存器的当前状态,代码被调试时,如果一条指令运行过程中修改了寄存器的值,则寄存器窗口中的这个寄存器就会从黑色变为红色。

栈面板窗口
这个窗口用来显示被调试线程堆栈在内存中的当前状态。这个窗口总是显示给定线程的栈项。可以通过右击一个栈单元,选择Modify,来操作这个窗口中的栈。OllyDbg会在一些栈单元上显示一些有用的注释,这些注释描述了调用一个API之前栈中存放的参数。

内存转储面板窗口
这个窗口用来显示被调试进程的实时内存转储。在这个窗口中按CtrI+G组合键,并输入一个内存位置,可以跳转到任何内存地址(也可以单击一个内存地址,然后选择Follow in Dump,来转储那个内存地址)。如果想要编辑这个窗口中的内存,右击它并选择Binary->Edit。使用这种方式也可以修改恶意代码存储在RAM中的全局变量以及其他一些数据。

9x3 内存映射

内存映射窗口( View->Memory)显示了被调试程序分配的所有内存块。
内存映射是查看程序在内存中布局的一个好方式。你可以双击内存映射中的任意一行,显示那个段的内存转储。你也可以通过右击一段内存转储,然后选择View in Disassembler的方式,将其中的数据发送到反汇编窗口。

1. 基地址重定位

内存映射能够帮助你理解一个PE文件在运行时如何被重定位。基地址重定位是指Windows中的一个模块没有被加载到其预定基地址时发生的情况。

基地址
Windows中的所有PE文件都有一个预定的基地址,它在PE文件头中被称为映像基地址。

Windows允许映像基地址与要被加载到内存的实际地址不一致,虽然大部分情况下是一致的。大部分执行程序都被预定加载到0x00400000处,这个地址是Windows平台下大多数编译器使用的默认地址。不过,开发者可以选择将执行程序的基地址设置为一个与此不同的地址。支持地址空间布局随机化( ASLR)安全增强特性的可执行程序会经常被重定位。这就是说.DLL的重定位变得更加普遍。
因为一个应用程序可能导入许多DLL,而每个DLL都有一个希望被加载到内存中的预定基地址,所以重定位十分必要。假设有两个DLL被加载,并且它们拥有相同的预加载地址0x10000000,则它们不可能都加载到这个位置,Windows会将其中一个DLL加载到这个地址,另一个DLL重定位到另外某个地址。
Windows操作系统自带的大多数DLL有不同的预定基地址,而且它们之间不会产生冲突。然而第三方应用程序会经常出现使用同一个预定基地址的情况。

绝对地址与相对地址
重定位过程比简单将代码加载到另一个位置要复杂得多。虽然多数指令会引用内存中的相对地址,但是有些却引用内存的绝对地址。

9x4 查看线程和堆栈

恶意代码经常使用多线程。你可以通过选择View->Threads,调出线程面板窗口,查看一个程序的当前线程。这个窗口显示了线程的内存位置,以及它们当前的活动状态(活动、暂停,或者挂起)。
由OllyDbg是单线程的,可能需要你先暂停所有的线程,设置一个断点后,继续运行程序,这样可以确保在一个特定线程内调试。单击主工具栏中的暂停按钮,可以暂停所有活动的线程。

9x5 执行代码

im

9x6 断点

enter description here

1. 软件断点

调试字符串解码函数时,软件断点特别有用。

2. 条件断点

条件断点是软件断点的一种,只有某些条件得到满足时这个断点才能中断执行程序。OllyDbg调试器允许使用表达式,来设置断点,每当断点命中时,都会先计算表达式的值,如果其值不等于零,断点生效,程序运行中断。

对于调用频繁的API函数,仅当特定参数传给它时才中断程序执行,这种情况下,条件软件断点特别有用。

设置条件断点的步骤

  1. 右击反汇编面板窗口中函数的第一条指令,选择Breakpoint->Conditional。然后会弹出一个对话框,要求你输入条件表达式.
  2. 在步骤l弹出的对话框中输入表达式,然后单击OK按钮。
  3. 单击Play按钮,并等待条件断点命中。

3. 硬件断点

硬件断点非常强大,它可以在不改变你的代码、堆栈以及任何目标资源的前提下进行调试。

OllyDbg中,在某一指令上设置硬件断点的方法是:右击该指令选择Breakpoint->Hardware,on Execution。

通过使用Debugging Options菜单,你可以告诉OllyDbg默认使用硬件断点来代替软件断点。同时,使用硬件断点可以帮助你防御反调试技术,如软件断点扫描。

4. 内存断点

在一个内存块上设置内存断点,可以让被调试程序在访问这段内存时中断执行。OllyDbg支持软件内存断虑和硬件内存断点,此外还支持对内存进行读、写、执行或其他权限访问是否产生中断的设置。

为了设置一个基本的内存断点,在内存转储面板窗口中选择一部分内存,或者在内存映射面板窗口中选择一个内存段,然后右击它,选择Breakpoint->Memory,on Access。OllyDbg只允许你一次设置一个内存断点。如果你设置了一个新的内存断点,那么之前设置的内存断点会被移除。

在分析恶意代码时,如果想知道恶意代码何时使用了某个加载的DLL,这时内存断点将变得特别有用。可以设置这样一个内存断点,当DLL中的代码运行时程序被中断。下面是实现这种功能的步骤:

1.打开内存映射面板窗门,并右i键单击需要跟踪DLL的.text段(.text段包含DLL的可执行代码)。
2.选择Set Memory Breakpoint on Access.
3.按F9键或者单击Play按钮恢复程序运行。
当心用程序运行到DLL的.text段代码时.会中断执行。

9x7 加载DLL

除了可以调试加载的或者附加的可执行程序,OllyDbg还可以调试DLL。然而由于DLL不能直接运行.OllyDbg使用了一个名为loaddll. exe的虚拟程序来加载它。由于恶意代码经常打包成DLL.且其大部分代码都包含在DLL的DlIMain函数(DLL的初始化函数,当DLL被加载到进程时被调用)中,因此OllyDbg的这种技术非常有用。默认情况下,一旦DLL被加载,OllyDbg会在DLL的入口点(DllMain)处中断。

如果要用参数调用被调试DLL中的导出函数,首先用OllyDbg加载DLL.然后在其入口点处暂停DLL的执行,最后单击Play按钮,运行DllMain函数,以及其他一些DLL要求的初始化操作。

9x8 跟踪

跟踪是一种强大的调试技术,它可以记录程序详细的运行信息,供你查阅。OllyDbg支持多种跟踪功能,包括:标准回溯跟踪、堆栈调用跟踪和运行跟踪等。

1. 标准回溯跟踪

每次你在反汇编面板窗口上执行Step Into和Step Over操作时,OllyDbg都会记录下这种动作。你可以使用键盘上的减号键(一)。退回到上一步运行的指令:使用加号键(+).执行下一条指令。
如果使用Step Into,你可以跟踪每一步的执行。如果使用Step Over,只能单步跟踪step over之前区域,回溯之后再决定是否进入另一个区域。

2. 堆栈调用跟踪

在OllyDbg中,通过堆栈跟踪可以查看一个给定函数的执行路径。为了查看堆栈调用,在主菜单中选择View->Call Stack.会弹出一个窗口,窗口中显示了当前位置之前的调用序列。
为了跟踪堆栈调用,单击地址或者堆栈调用窗口中的某段。当你在那个堆栈位置时,寄存器和堆栈并不会显示什么,除非你执行运行跟踪操作。

3. 运行跟踪

运行跟踪是指在运行代码时,OllyDbg会保存所有运行过的指令,以及它们运行过程中对寄存器和标志所做的改变。

几种激活运行跟踪的方法
· 在反汇编面板窗口中高亮你要跟踪的代码。右键单击代码,选择Run Trace–Add Selection。代码运行后,选择View->Run Trace,查看运行过的指令。使用键盘上的一(减号键)和+(加号键),来上下浏览代码(与标准回溯跟踪小节讨论的一样)。使用这种方法,可以查看每条指令执行时所有寄存器发生的变化。
· 使用Trace Into与Trace Ovcr选项。这些选项比Add Selection更容易使用,因为它们不需要你选择需要跟踪的代码。Trace Into可以单步执行并且记录命中断点前所有的运行指令,但Trace Over仅记录当前正在运行函数的指令。
· 选择Select Debug->Set Condition。可以在命中条件使程序暂停之前,跟踪程序的运行。如果你想在条件断点命中时停止跟踪,并且从发生中断的位置,回溯跟踪查看如何或者为什么发生中断,这种跟踪方法将对你非常有帮助。

4. 跟踪Poison lvy

9x9 异常处理

默认情况下.OllyDbg被附加后会产生异常,附加程序也会停止运行,此时调试器开始接管控制权。调试器可以处理该异常,也可以将异常转到被调试的应用程序处理。当异常发生时.OllyDbg会暂停运行,然后你可以使用下列任一种方法,来决定是否将异常转到应用程序处理:

· Shift+F7将进入异常。
· Shift+F8将跳过异常。
· Shift+F9将运行异常处理。

OllyDbg提供异常处理的选项,这些选项可以告诉调试器忽略某些特定异常,并且将它们直接转到应用程序处理。
im

9x10 修补

OllyDbg可以很容易修改实时数据,如寄存器和标志。它也可以将汇编形式的修补代码直接插入到一个程序。你可以通过高亮选择某块区域来修改指令或内存,右击这块区域,选择Binary->Edit,会弹出让你添加操作码和数据的窗口(OllyDbg具有一些特殊功能,可以使用00项或NOP指令填充程序)。

9x11 分析shellcode

OllyDbg有一种分析shellcodc的简单方法。下面是使用这种方法的步骤:

1.将shellcode从一个十六进制编辑器复制到剪切板。
2.在内存映射面板窗口中,选择类型为Priv的内存区域(这是分配给进程的私有内存,与只读的可执行镜像不同,这些内存被多个进程共享)。
3.双击内存映射面板窗口的某行,会弹出一个十六进制转储窗口,你可以检查它的内容。该区域应该包含几百个连续为0的字节。
4.在内存映射面板窗口中,右击被选择的区域,选择Set Access—Full Access,赋予该区域读、写、运行的权限。
5.返回内存转储窗口。0字节填充的高亮区域足以容纳整个sheUcode,右键单击选择的内存区域,然后选择Binary一Binary Paste。这个操作将步骤l中复制的shellcode粘贴到选择的区域。
6.设置EIP寄存器,指向你修改的内存区域(右击反汇编面板窗口的一条指令,选择New Origin Here,你可以很容易设置EIP寄存器的值)。

上述步骤结束后,你就可以像对待正常应用程序一样运行、调试和单步整个shellcode了

9x12 协助功能

OllyDbg提供了多种机制来帮助分析,包括下面几种:

日志( Logging)
OllyDbg维护一个持续可用的事件日志。要访问这个日志,选择View->Log。此日志显示了加载的可执行模块、触发的断点,以及其他一些信息。另外,在分析过程中,日志还可以帮助你找出为到达某一特定状态而执行的那些操作。
监视(Watches)窗口
OllyDbg支持使用监视窗口,用它可以查看你生成表达式的值。程序运行时,这个表达式会不断更新。你可以通过View—Watches,来访问监视窗口,你也可以在监视窗口中按下空格键,来设置表达式。
帮助(Help) OllyDbg的Help->Contents选项为运算表达式的书写提供了详细说明。当你想监视一些特定数据或者复杂函数时,这个帮助非常有用。例如,如果想监控EAX+ESP+4处的内存,你只需要输入表达式[EAX+ESP+4]。
标注(Labeling) 如IDA Pro一样,你可以为OllyDbg中的子例程和循环添加标注。OllyDbg中的标注是为调试程序中某个地址设置的一个简单符号名称。为了在反汇编面板窗口设置标注,右击一个地址选择Label,此时会弹出提示输入标注的窗口。设置完标注以后,对这个地址的所有引用都会被该标注代替。

9x13 插件

OllyDbg拥有一些标准插件,其中一些可以免费下载到。在网站 http://www.openrce.org/downloads/browse/OllyDbg_Plugins 中,你可以找到一些对分析恶意代码有用的OllyDbg插件。
OllyDbg的插件以DLL形式存在,如果要安装某个插件,你将这个插件的DLL放到OllyDbg的安装根目录下即可。一旦将DLL放入OllyDbg的安装根目录,OllyDbg会自动识别这个插件,并将其添加到插件菜单。

1. OllyDump

OllyDump是OllyDbg最常使用的插件,它能够将一个被调试的进程转储成一个PE文件。当加载器加载一个可执行文件时,OllyDump会尝试逆向这个进程。然而,OllyDump利用的是进程内存中各段(代码段、数据段等)的状态。OllyDbg最典型的应用就是脱壳。

2. 调试器隐藏插件

调试器隐藏插件用多种方法对探测者隐藏调试器的存在。为了防止恶意代码使用反调试技术,恶意代码分析人员通常在分析恶意代码期间,一直运行调试器隐藏插件。这个插件主要针对IsDebuggerPresent检测、FindWindow检测、未处理异常欺骗以及用OutputDebugString反OllyDbg调试等反调试技术。

3. 命令行

要打开命令行窗口,选择Plugins->Command Line->Command Line。
im

4. 书签

OllyDbg默认情况下自带书签插件,书签插件可以将一个内存位置加到书签中,利用书签,下次不需要记住就可以轻松获取那个内存地址。右击反汇编面板窗口中的地址,选择Bookmark->Insert Bookmark.可以添加书签。选择Plugins->Bookmarks->Bookmarks,可以浏览书签,然后单击书签可以跳转到该书签代表的地址。

9x14 脚本调试

因为OllyDbg的插件被编译成DLL,创建或者修改一个插件往往是一个复杂的过程。因此,当需要扩展调试功能时,我们采用ImmDbg。它使用Python脚本来扩展功能,并且提供了易于使用的API接口。
ImmDbg的Python API包含很多实用工具和函数。例如,可以将你的脚本像本地代码一样集成到调试器中,创建自定义的表格、图形和各种接u。利用脚本分析恶意代码的原因有多种,典型的包括反调试器补丁、内联函数钩子( hook)以及函数参数日志等,其中许多代码可以在网上找到。
ImmDbg最常见的Python脚本类型是PyCommand.这个Python脚本位于ImmDbg安装目录下的PyCommands\目录中。编写好Python脚本后,必须将其放到这个目录下才能运行。这些脚本从命令栏运行,并且需要加上前缀“!”,如在命令行中输入!list命令,可以列出可用的PyCommand列表。
PyCommand类型脚本拥有如下结构:

. 一系列Import导入语句,用来导入Python的模块(同所有的Python脚本一样)。通过immlib或immutils模块访问ImmDbg的功能。
. 一个主函数,用来读取命令行参数(以Python列表传递)。
· PyCommand的代码实现部分。
· 返回包含字符串的值。一旦脚本运行结束,主调试器会用这个返回字符串更新状态栏。

From https://kabeor.github.io/第9章 OllyDbg/ bye

This blog is under a CC BY-NC-SA 4.0 Unported License
本文链接:https://kabeor.github.io/第9章 OllyDbg/