1、加载恶意代码

  • 直接加载 or 附加到进程
  • 命令选项运行恶意代码
  • 支持执行DLL中某个函数
  • 打开一个可执行文件
    • file->open:设置arguments可以在运行期间传入参数
    • 默认在WinMain(程序入口点)停止执行,可以使用Options->Debugging Options修改启动选项(例:选择System Breakpoint在代码执行前立刻中断)
  • 附加调试器到一个运行程序
    • file->attach
    • 进程当前执行线程的代码会被暂停

2、OllyDbg的接口

  • 反汇编面板窗口:显示被调试程序的代码,修改按空格键
  • 寄存器面板窗口:显示寄存器当前状态,修改处显示为红色
  • 栈面板窗口:显示被调试线程堆栈在内存中的当前状态,总是显示给定线程的栈顶,栈单元上会显示一些有用的注释
  • 内存转储面板窗口:显示被调试进程的实时内存转储,按Gtrl+G输入内存位置可以跳转到内存任意地址【也可以单击一个内存地址,选择Follow in Dump来转储那个内存地址】,想编辑这个窗口中的内存:右键Binary->Edit,也可以修改恶意代码存储在RAM中的全局变量及其他数据。

3、内存映射(View->Memory)

  • 显示被调试程序分配的所有内存块
  • 可以右击一段内存转储,选择View in Disassemble,将数据发送到反汇编窗口
  • 基地址重定位
    • 指Windows中一个模块没有被加载到其预定基地址时发生的情况
    • 基地址
      • 映像基地址,允许与被加载到内存中的实际地址不一致,大部分情况下是一致的,大部分执行程序都被预加载到0x00400000(windows平台下大多数编译器使用的默认地址)
      • 开发者可以更改基地址,支持地址空间布局随机化(ASLR)安全增强特性的可执行程序
    • 绝对地址与相对地址
      • 使用绝对地址访问内存容易出错,多数DLL会在PE头的.reloc节打包一个修订位置的列表
      • DLL在.exe载入后以任意顺序加载,基地址重定位后难以预测其在内存中定位的位置
      • 在所有DLL被编译时,编译器会为他们选择一个默认的基地址,一般都会重定向
      • 静态分析时不知道被重定向

4、查看线程和堆栈

  • View->Threads:显示线程内存位置以及它们当前的活动状态
  • 单击主工具栏的暂停按钮可以暂停所有活动的线程
  • 线程的重要数据都保存在栈上,可以使用内存映射查看内存中栈的内容

5、执行代码
27.jpg

  • Run&Pause:开始或暂停一个程序,但Pause很少用,因为可能会暂停到无用的位置,通常设断点暂停
  • Run to Selection:在到达选择的指令之前一直运行,如果选择的指令不被执行,则被调试程序会一直运行下去。
  • Execute till Return:在当前函数返回时暂停执行
    • 调试时如果恶意代码程序执行迷失在代码库中,使用Debug->Execute till User Code,使被调试程序返回到编译的恶意代码中
  • 单步跟踪
    • 单步进入:F7
    • 单步跳过:F8(要警惕函数没有ret的情况)

6、断点

  • 默认使用软件断点
  • 添加移除断点:F2
  • **View->BreakPoints:看到一个程序中活跃的断点
  • 软件断点:
    • 在调试字符串解码函数时非常有用(混淆字符串->解码),在解码结束的位置处下断点
  • 条件断点:
    • 使用表达式设置断点
    • 断点命中时,计算表达式的值,值不等于零断点生效程序运行中断
    • 具体应用:在函数受到特定参数时断下
    • 实例:探测Poison Ivy特定大小的内存分配情况,当接收shellcode时分配的内存大
      28.jpg
      • 分配内存大小为0x29,ESP寄存器存放栈顶指针,为了获取分配内存的大小,需要使用[ESP+8]引用内存(??)
      • 设置条件断点Breakpoint->Conditional
  • 硬件断点
    • OD提供利用专门硬件寄存器设置硬件断点
    • 硬件断点可以在不改变代码、堆栈以及任何目标资源的前提下进行调试(可以深究!!);但只能同时设置四个断点
    • 使用硬件断点可以防御反调试技术(软件断点扫描)
  • 内存断点
    • 在内存块上设置,可以让被调试程序在访问这段内存时中断执行,还可以判断此内存块的权限
    • 一次只能设置一个内存断点
    • 应用:判断恶意代码何时使用了某个加载的dll
      • 打开内存映射面板窗口,右键单击需要跟踪的dll的.text段
      • 选择Set Memory Breakpoint on Access
      • F9恢复运行

7、加载DLL

  • OD使用loaddll.exe加载dll运行,一旦被加载,在DllMain中断
  • 用参数调用被调试DLL中的导出函数:OD加载,运行到dll初始化完成,主菜单中选择Debug->Call Dll Export,使用参数调用dll导出的具体函数
  • Hide on call:函数调用后隐藏窗口
  • Follow in Disassembler:查看函数汇编代码
  • Pause after call:代替断点

8、跟踪

  • 标准回溯跟踪
    • Step into&Step over:-可以回退操作
  • 堆栈调用跟踪
    • 查看给定函数的执行路径
    • View->Call Stack:显示当前位置之前的调用序列
  • 运行跟踪
    • 在运行代码时,OD会保存所有运行过的指令以及运行过程中对寄存器和标志做的改变
    • 使用方法:
      • 反汇编窗口中高亮要跟踪的代码。右键单击选择Run Trace->Add Selection。代码运行后选择View->Run Trace查看运行过的指令,- +上下浏览
      • 使用Trace Into & Trace Over
        • Trace Into:单步执行并记录断点命中前所有指令
        • Trace Over:仅记录当前正在运行的函数指令
  • 例:跟踪Poison Ivy
    • 当EIP指向Poison Ivy为shellcode指向的堆时,可以使用跟踪来捕获shellcode的运行
    • 设置当EIP小于一个典型的映像位置时(0x400000,低于这个值是一些简单程序中的栈、堆和动态分配内存存放的位置),OD暂停。因为在正常程序运行中EIP不应该指向这些位置。
    • 选择Trace Into使在shellcode运行之前整个程序被跟踪

9、异常处理

  • 默认情况下产生异常时附加程序会停止运行,此时调试器开始接管控制权
  • 调试器可以处理该异常们也可以将异常转到被调试的应用程序处理
    • Shift+F7:进入异常
    • Shift+F8:跳过异常
    • Shift+F9:运行异常处理
  • Debugging Options:告诉调试器忽略某些特定异常,并且将它们直接转到应用程序处理

10、修补

  • 修改实时数据(如寄存器和标志),也可以将汇编形式的修补代码直接插入到一个程序,可以通过高亮选择某块区域来修改指令或内存
  • 右键选择区域:Binary->Edit(可以使用00或NOP填充,JNZ时可以避免跳转,改变执行流程)
  • 应用这种改变:右击反汇编面板窗口需要修补的代码,选择Copy to executable->All Modification->Save File保存

11、分析shellcode

  • 将shellcode从一个十六进制编辑器复制到剪切板
  • 在内存映射窗口中,选择类型为Priv的内存区域(分配给进程的私有内存,这个内存被多个进程共享)
  • 双击内存映射窗口的某行,会弹出一个十六进制转储窗口,可以检查它的内容。
  • 在内存映射面板窗口中右击被选择区域,选择Set Access->Full Access,赋予该区域读、写、运行的权限
  • 返回内存转储窗口。0字节填充的高亮区域足以容纳整个shellcode,右键单击选择的内存区域,选择Binary->Binary Paste将复制的shellcode粘贴到选择的区域。
  • 设置EIP寄存器,指向你修改的内存区域。(右键反汇编面板窗口的一条指令,选择New Origin Here设置EIP寄存器的值)
  • 运行,调试和单步整个shellcode

12、协助功能

  • 日志(Logging):View->Log 显示了加载的可执行模块、触发的断点等,状态记录
  • 监视(Watches)窗口:查看生成表达式的值(??),按空格可以设置表达式
  • 标注(Labeling):右键->Lable

13、插件

  • 将插件dll放在安装根目录,OD自动识别
  • OllyDump
    • 将一个被调试的进程转储为一个PE文件
    • 加载可执行文件时会尝试逆向这个进程(脱壳应用)
  • 调试器隐藏插件
    • 对探测者隐藏调试器的存在
    • 防止恶意代码使用反调试技术
  • 命令行
    • Plugins->Command Line->Command Line
      29.jpg
  • 书签
    • 将一个内存位置加到书签中
    • 添加书签:Bookmark->Insert Bookmark
    • 浏览书签:Plugins->Bookmarks->Bookmarks

14、脚本调试

  • 需要扩展调试功能时,采用ImmDbg,使用Python脚本来扩展功能,有易于使用的API接口
  • PyCommand:ImmDbg最常见的脚本类型,编写好脚本后放在ImmDbg安装目录下的PyCommands\目录,脚本从命令行运行,并且需要加上前缀!(例:!list:列出可用的PyCommand列表)
  • 导入模块:通过immlib或immutils模块访问ImmDbg的功能
  • 主函数:用来读取命令行参数(Python列表传递)
  • PyCommand代码实现
  • 返回包含字符串的值,脚本运行结束,主调试器会用这个返回字符串更新状态栏