首页 >> 常用名词解答
OLLYDBG
发布时间:2012-6-2 10:25:33 被阅览数:22494次 来源:OLLYDBG
OLLYDBG是一个新的动态追踪工具,将IDA与SoftICE结合起来的思想,Ring 3级调试器,非常容易上手,己代替SoftICE成为当今最为流行的调试解密工具了.同时还支持插件扩展功能,是目前最强大的调试工具.
编辑摘要
目录
1 主要介绍
2 相关条目
OLLYDBG - 主要介绍
软件
OLLYDBG
名称,一个新的动态追踪工具,将IDA与SoftICE结合起来的思想,Ring 3级调试器,非常容易上手,己代替SoftICE成为当今最为流行的调试解密工具了.同时还支持插件扩展功能,是目前最强大的调试工具.
OLLYDBG - 相关条目
追踪 调试器 流行 工具 插件
一,什么是 OllyDbg?
OllyDbg 是一种具有可视化界面的 32 位汇编-分析调试器。它的特别之处在于可以在没有源代码时解决问题,并且可以处理其它编译器无法解决的难题。
Version 1.10 是最终的发布版本。 这个工程已经停止,我不再继续支持这个软件了。但不用担心:全新打造的 OllyDbg 2.00 不久就会面世!
运行环境: OllyDbg 可以以在任何采用奔腾处理器的 Windows 95、98、ME、NT 或是 XP(未经完全测试)操作系统中工作,但我们强烈建议您采用300-MHz以上的奔腾处理器以达到最佳效果。还有,OllyDbg 是极占内存的,因此如果您需要使用诸如追踪调试[Trace]之类的扩展功能话,建议您最好使用128MB以上的内存。
支持的处理器: OllyDbg 支持所有 80x86、奔腾、MMX、3DNOW!、Athlon 扩展指令集、SSE指令集以及相关的数据格式,但是不支持SSE2指令集。
配置: 有多达百余个选项用来设置 OllyDbg 的外观和运行。
数据格式: OllyDbg 的数据窗口能够显示的所有数据格式:HEX、ASCII、UNICODE、 16/32位有/无符号/HEX整数、32/64/80位浮点数、地址、反汇编(MASM、IDEAL或是HLA)、PE文件头或线程数据块。
帮助: 此文件中包含了关于理解和使用 OllyDbg 的必要的信息。如果您还有 Windows API 帮助文件的话(由于版权的问题 win32.hlp 没有包括在内),您可以将它挂在 OllyDbg 中,这样就可以快速获得系统函数的相关帮助。
启动: 您可以采用命令行的形式指定可执行文件、也可以从菜单中选择,或直接拖放到OllyDbg中,或者重新启动上一个被调试程序,或是挂接[Attach]一个正在运行的程序。OllyDbg支持即时调试。OllyDbg根本不需要安装,可直接在软盘中运行!
调试DLLs: 您可以利用OllyDbg调试标准动态链接库 (DLLs)。OllyDbg 会自动运行一个可执行程序。这个程序会加载链接库,并允许您调用链接库的输出函数。
源码级调试: OllyDbg 可以识别所有 Borland 和 Microsoft 格式的调试信息。这些信息包括源代码、函数名、标签、全局变量、静态变量。有限度的支持动态(栈)变量和结构。
代码高亮: OllyDbg 的反汇编器可以高亮不同类型的指令(如:跳转、条件跳转、入栈、出栈、调用、返回、特殊的或是无效的指令)和不同的操作数(常规[general]、
FPU/SSE、段/系统寄存器、在栈或内存中的操作数,常量)。您可以定制个性化高亮方案。
线程: OllyDbg 可以调试多线程程序。因此您可以在多个线程之间转换,挂起、恢复、终止线程或是改变线程优先级。并且线程窗口将会显示每个线程的错误(就像调用 GETLASTERROR 返回一样)。
分析:OllyDbg 的最大特点之一就是分析。它会分析函数过程、循环语句、选择语句、表[tables]、常量、代码中的字符串、欺骗性指令[tricky constructs]、API调用、函数中参数的数目,import表等等。. 这些分析增加了二进制代码的可读性,减少了出错的可能性,使得我们的调试工作更加容易。
Object扫描。 OllyDbg 可以扫描Object文件/库(包括 OMF 和 COFF 格式),解压代码段[code segments]并且对其位置进行定向。
Implib扫描。 由于一些DLL文件的输出函数使用的索引号,对于人来说,这些索引号没有实际含义。如果您有与DLL相应的输入库[import library],OllyDbg 就可以将序号转换成符号名称。
完全支持Unicode: 几乎所有支持 ASCII 的操作同时也支持 UNICODE,反之亦然。
名称: OllyDbg 可以根据 Borland 和 Microsoft 格式的调试信息,显示输入/输出符号及名称。Object 扫描器可以识别库函数。其中的名称和注释您可任意添加。如果DLL中的某些函数是通过索引号输出的,则您可通过挂接输入库[import library]来恢复原来的函数名称。不仅如此,OllyDbg还能识别大量的常量符号名(如:窗口消息、错误代码、位域[bit fields]…)并能够解码为已知的函数调用。
已知函数:OllyDbg 可以识别 2300 多个 C 和 Windows API 中的常用函数及其使用的参数。您可以添加描述信息、预定义解码。您还可以在已知函数设定 Log 断点并可以对参数进行记录。
函数调用: OllyDbg 可以在没有调试信息或函数过程使用非标准的开始部分[prolog]和结尾部分[epilog]的情况下,对递归调用进行回溯。
译者注:
004010D0 push ebp \
004010D1 mov ebp,esp |
004010D3 sub esp,10h |prolog
004010D6 push ebx |
004010D7 push esi |
004010D8 push edi /
……
004010C5 pop edi \
004010C6 pop esi |
004010C7 pop ebx |epilog
004010C8 mov esp,ebp |
004010CA pop ebp |
004010CB ret /
栈:在栈窗口中,OllyDbg 能智能识别返回地址和栈框架[Stack Frames]。并会留下一些先前的调用。如果程序停在已知函数上,堆栈窗口将会对其参数进行分析解码。
译者注:栈框架[Stack Frames]是指一个内存区域,用于存放函数参数和局部变量。
SEH 链: 跟踪栈并显示结构化异常句柄链。全部链会显示在一个单独的窗口中。
搜索:方法真是太多了!可精确、模糊搜索命令或命令序列,搜索常数,搜索二进制、文本字符串,搜索全部命令地址,搜索全部常量或地址域[address range],搜索所有能跳到选定地址的跳转,搜索所有调用和被调用的函数,搜索所有参考字符串,在不同模块中搜索所有调用、搜索函数名称,在全部已分配的内存中搜索二进制序列。如果搜索到多个结果,您可以对其进行快速操作。
窗口:OllyDbg 能够列出关于调试程序中的各种窗口,并且可以在窗口、类甚至选定的消息上设置断点。
资源:如果 Windows API 函数使用了参考资源串,OllyDbg 可以显示它。其支持显示的类型仅限于附带资源[attached resources]的列表、数据显示及二进制编辑、。
断点: OllyDbg 支持各种断点:一般断点、条件断点、记录断点(比如记录函数参数到记录窗口)、内存读写断点、硬件断点(只适用于ME/NT/2000)等。在Hit跟踪情况下,可以在模块的每条命令上都设置INT3断点。在使用500-MHZ处理器的 Windows NT 中,OllyDbg 每秒可以处理高达 5000 个中断。
监视与监察器:每个监视都是一个表达式并能实时显示表达式的值。您可以使用寄存器、常数、地址表达式、布尔值以及任何复杂代数运算,您还可以比较ASCII和UNICODE
字符串。监察器[inspectors]是一种包含了两个的索引序列的监视[Watches],它以二维表的形式呈现,可以对数组和结构进行解码分析。
Heap walk.:在基于Win95的系统中,OllyDbg 可以列出所有的已分配的堆。
句柄:在基于NT的系统中,OllyDbg 可列出被调试程序的所有系统句柄。
执行:.您可以单步执行、步入子程序或者步过子程序。您也可以执行程序直到函数返回时、执行到指定地址处,还可以自动执行。当程序运行时,您仍然可以操纵程序并能够查看内存、设置断点甚至修改代码。您也可以任意的暂停或重启被调试的程序。
Hit跟踪:.Hit跟踪可以显示出目前已执行的指令或函数过程,帮助您检验代码的各个分支。Hit跟踪会在指定指令到达之前设置断点,而在这个指令执行后,会把这个断点清除掉。
译者注:Hit在英文中是“击中”的意思,指令如果运行了就表示这个指令被“击中”了,没有执行的指令就是“未击中”,这样我们就很容易看出被调试程序哪些部分运行了,而哪些没有运行。
Run跟踪: Run跟踪可以单步执行程序,它会在一个很大的循环缓冲区中模拟运行程序。这个模拟器包含了除了SSE指令集以外的所以寄存器、标志、线程错误、消息、已经函数的参数。您可以保存命令,这样可以非常方便地调试自修改代码(译者注:比如加壳程序)。您可以设置条件中断,条件包括地址范围、表达式、命令。您可以将Run
跟踪信息保存到一个文件中,这样就可以对比两次运行的差别。Run跟踪可以回溯分析已执行过的上百万条命令的各种细节。
统计: 统计[Profiler]可以在跟踪时计算某些指令出现的次数。因此您就能了解代码的哪一部分被频繁执行。
补丁: 内置汇编器能够自动找到修改过的代码段。二进制编辑器则会以ASCII、UNICODE或者十六进制的形式同步显示修改后的数据。修改后的数据同其它数据一样,能够进行复制-粘贴操作。原来的数据会自动备份,以便数据恢复时使用。您可以把修改的部分直接复制到执行文件中,OllyDbg会自动修正。OllyDbg还会记录以前调试过程中使用的所有补丁。您可以通过空格键实现补丁的激活或者禁止。
自解压文件: 当调试自解压文件时,您往往希望跳过解压部分,直接停在程序的原始入口点。OllyDbg的自解压跟踪将会使您实现这一目的。如果是加保护的自解压段,自解压跟踪往往会失败。而一旦OllyDbg找到了入口点,它将会跳过解压部分,并准确的到达入口点。
插件:您可以把自己的插件添加到 OllyDbg 中,以增加新的功能。OllyDbg 的插件能够访问几乎所有重要的数据的结构、能够在 OllyDbg 的窗口中添加菜单和快捷键,能够使用100个以上的插件API函数。插件API函数有详细的说明文档。默认安装已经包含了两个插件:命令行插件和书签插件。
UDD:OllyDbg 把所有程序或模块相关的信息保存至单独的文件中,并在模块重新加载时继续使用。这些信息包括了标签、注释、断点、监视、分析数据、条件等等
更多:这里介绍的功能,仅仅是 OllyDbg 的部分功能。因为其具有如此丰富的功能,以至于 OllyDbg 能成为非常方便的调试器!
2005-9-6 15:25 乾龙二,一般原理[General principles]
我希望您能对80x86系列处理器的内部结构有所了解,同时具有一定的编写汇编程序的能力。对于Microsoft Windows方面的知识,您也要熟悉。
OllyDbg是运行在Windows 95、Windows 98、Windows ME、Windows NT 和 Windows 2000系统下的一个单进程、多线程的分析代码级调试工具。它可以调试PE格式的执行文件及动态链接库,并可以对其打补丁。“代码级”意味着您可以直接与比特、字节或处理器指令打交道。OllyDbg 仅使用已公开的 Win32 API 函数,因此它可以在所有 Windows 操作系统及后继版本中使用。但是由于我没有对 XP 系统进行彻底测试,因此不能保证 OllyDbg 功能的充分发挥。注意:OllyDbg 不支持对 .NET 程序的调试。
OllyDbg不是面向编译器的。它没有特别的规则规定必须是哪一个编译器产生的代码。因此,OllyDbg可以非常好的处理通过编译器生成的代码,或是直接用汇编写入的代码。
OllyDbg可以并行调试程序。您无须暂停执行程序,就可以浏览代码和数据,设置断点、停止或恢复线程,甚至直接修改内存。(这可以视为一种软件调试的模式,与之相对的硬件模式则是当进程在运行时调试器被阻滞,反之亦然)。假使所需的操作比较复杂,OllyDbg会让进程终止一小段时间,但是这种暂停对于用户来说是透明的。
有时进程会发生非法操作。您可以把OllyDbg设置成即时[just-in-time]调试器,它会挂接出错程序,并停在程序产生异常的地方。
通过OllyDbg,您可以调试单独的DLL[standalone DLLs]文件。操作系统不能直接运行 DLL 文件,因此 OllyDbg 将一个可以加载 DLL 的小程序压缩到资源里,这个程序允许您调用最多10个参数的输出函数。
OllyDbg是完全面向模块[module-oriented]的。模块[Module]包括可执行文件(扩展名通常为.EXE)和在启动时加载或需要时动态加载的动态链接库(扩展名通常为.DLL
)。在调试期间,您可以设置断点[breakpoints]、定义新的标签[labels]、注释[comment]汇编指令,当某个模块从内存中卸载[unload]时,调试器会把这些信息保存在文件中,文件名就是模块的名称,扩展名为.UDD(表示 用户自定义文件[User-Defined Data])当OllyDbg下一次加载该模块时,它会自动恢复所有的调试信息,而不管是哪一个程序使用这个模块。假设您正在调试程序Myprog1,这个程序使用了Mydll。您在 Mydll 中设置了一些断点,然后您开始调试Myprog2,这个程序同样使用了Mydll。这时您会发现,所有 Mydll 中的断点依然存在,即使 Mydll 加载到不同的位置!
一些调试器把被调试进程的内存当作一个单一的(并且大部分是空的)大小为2 ^32字节的区域。OllyDbg采用了与之不同的技术:在这里,内存由许多独立的块组成,任何对内存内容的操作都被限制在各自的块内。在大多数情况下,这种方式工作得很好并且方便了调试。但是,如果模块包含好几个可执行段[executable sections],您将不能一次看到全部代码,然而这种情况是非常少见的。
OllyDbg 是一个很占用内存的程序[memory-hungry application]。它在启动时就需要 3 MB,并且当您第一次装载被调试的程序时还需要一到两兆的内存。每一次的分析、备份、跟踪或者文件数据显示都需要占用一定的内存。因此当您调试一个很大的项目,发现程序管理器显示有 40 或 60 兆内存被占用时,请不要惊慌。
为了有效地调试一些不带源码的程序,您必须首先理解它是如何工作的。OllyDbg 包含的大量特性可以使这种理解变得非常容易。
首先,OllyDbg包含一个内置的代码分析器。分析器遍历整个代码,分出指令和数据,识别出不同的数据类型和过程,分析出标准API函数(最常用的大约有1900个)的参数并且试着猜出未知函数的参数数目。您也可以加入自己的函数说明[your own function descriptions]。它标记出程序入口点和跳转目的地,识别出跳转表[table-driven switches]和指向字符串的指针,加入一些注释,甚至标示出跳转的方向等等。在分析结果的基础上,调用树[call tree]显示哪些函数被指定过程调用(直接或间接)并且识别出递归调用、系统调用和叶子过程[leaf procedures]。如果需要的话,您可以设置解码提示[decoding hints]来帮助分析器解析那些不明确的代码或数据。
OllyDbg还包含Object扫描器[Object Scanner]。如果您有库文件[libraries]或目标文件[object files],扫描器会在被调试的程序中定位这些库函数。在全部函数调用中,对标准函数的调用占很重要的一部分(据我估计可达70%)。如果您知道正要被调用的函数的功能,您就不必把注意力集中在这个函数上,可以简单地单步步过[
step over]这个call。分析器知道400多个标准C函数,比如fopen和memcpy。然而我必须承认当前版本的OllyDbg不能定位很短的函数(比一个return命令多不了多少的)或相似的函数(只在重定位上有不同)。
Object扫描器[Object scanner]也能够识别输入库[import libraries]。如果某个DLL是按序号输出的,您不会看到函数名,只会发现一堆无意义的神秘数字。这种DLL的开发者通常会提供一个输入库来实现函数符号名与序号间的对应。让OllyDbg使用这个输入库,它就会恢复原始的函数符号名。
面向对象的语言(如C++),使用了一种叫做名称修饰[name mangling]的技术,把函数类型和参数都加入函数名中。OllyDbg 可以解码[demangle]这种函数名,使程序更易读。
译者注:C++的名称修饰是编译器将函数的名称转变成为一个唯一的字符串的过程,这个字符串会对函数的类、其命名空间、其参数表,以及其他等等进行编码。C++的名称修饰适用于静态成员函数,也适用于非静态成员函数。静态函数的名称修饰的一个好处之一,是能够在不同的类里使用同一个名称来声明两个或者更多的静态成员函数----而不会发生名称上的冲突。
OllyDbg完全支持 UNICODE,几乎所有对 ASCII 字符串的操作都可以同样应用于 UNICODE。
汇编指令都是很相似的。您经常会搞不清自己是不是已经跟踪过某一段代码。在 OllyDbg 中您可以加入自己的标签[labels]和注释[comments]。这些极大地方便了调试。注意一旦您注释了某个DLL,以后每次加载这个DLL时,注释和标签都有效----尽管您在调试不同的程序。
OllyDbg可以跟踪标准的栈帧[stack frames](由PUSH EBP; MOV EBP,ESP所创建的)。现代编译器有禁止产生标准栈框架的选项,在这种情况下分配栈[stack walk
]是不可能的。当程序运行到已知的函数时,栈窗口[stack window]解析它的参数,调用栈[Call stack]窗口显示到达当前位置所调用函数的序列。
现代的面向对象应用程序广泛地使用了一种叫做结构化异常处理[Structured Exception Handling,SHE]的技术。SHE窗口[SEH window] 可以显示异常处理链。
多种不同的搜索[search]选项可以让您找到二进制代码或数据、命令或命令序列、常量或字符串、符号名或在 Run跟踪中的一条记录。
对于任何地址或常量,OllyDbg 可以找出参考[referencing]到该地址或常量的全部命令的列表。然后您可以在这个列表里找出对您来说是重要的参考。举例来说,某个函数可能被直接调用,或者经过编译器优化后把地址放入寄存器间接调用,或者把地址压入堆栈作为一个参数----没问题,OllyDbg 会找出所有这样的地方。它甚至能找到并列出所有和某个指定的位置有关的跳转。(真的?哦,天哪!……)
OllyDbg 支持所有标准类型的断点[breakpoints]----非条件和条件断点、内存断点(写入或访问)、硬件断点或在整个内存块上下断点(后两项功能只在Window ME,NT,2000,XP中有效)。条件表达式可以非常复杂(“当 [ESP+8] 的第 2 位被设置,并且 123456 位置处的字[word]小于10,或者 EAX 指向一个以“ABC”开头的 UNICODE 字串,但跳过前10次断点而在第11次中断”)。您可以设定一条或多条指令,当程序暂停时由OllyDbg传递给插件插件[plugins]。除了暂停,您还可以记录某个表达式的值(可以带有简短的说明),或者记录 OllyDbg 已知的函数的参数。在Athlon 2600+、Windows2000 环境下,OllyDbg 可以每秒处理多达 25000 个条件断点。
另一个有用的特性是跟踪。OllyDbg 支持两种方式的跟踪:hit和run。在第一种情况下,它对指定范围内的每条指令上设置断点(比如在全部可执行代码中)。当到达设断的指令后,OllyDbg 清除断点并且把该指令标记为hit。这种方法可以用来检测某段代码是否被执行。Hit跟踪速度惊人的快,在一个很短时间的启动后程序几乎达到了全速(译者注:这应该是与不进行调试时速度相比而言)。因为INT3断点可能对数据有灾难性的影响,所以我建议不要使用模糊识别过程。当代码没有被分析时Hit跟踪是不可以使用的。
Run跟踪[Run trace] 是一步一步地执行程序,同时记录精确的运行历史和所有寄存器的内容、已知的参数和可选的指令(当代码是自修改时会有帮助)。当然,这需要大量的内存(每个指令需要15至50个字节,取决于调试的模式)但是可以精确地回溯和分析。您可以只在选定的一段代码甚至是一条指令中进行Run跟踪,或者您可以跳过无关紧要的代码。对于每个地址,OllyDbg能够计算这个地址在Run跟踪日志中出现的次数,虽然会导致执行缓慢但是可以得到代码执行的统计。比如说,某命令让您在每个已识别的过程入口处进行Run跟踪,那么统计[profile]就会给您每个过程被调用的次数。在到达某条指令、某个地址范围或指令计数器达到某一数值时Run跟踪可以自动地暂停[pause]。
在多线程程序里OllyDbg可以自动管理线程[threads],如果您单步调试或跟踪程序,它会自动恢复当前线程而挂起其它线程。如果您运行程序,OllyDbg 会恢复先前的线程状态。
您可以为内存块建立快照(叫做备份)。OllyDbg会高亮显示所有的改动。您可以把备份保存到文件或从文件中读取出来,从而发现两次运行的不同之处。您可以查看备份,搜索下一处改动,恢复全部或选定的改动。补丁管理器[Patch manager]记录了上次应用到程序中的所有补丁,在下次调试时可以再次应用它们。
您可以很容易地把您的补丁加在可执行文件上。OllyDbg 会自动进行修正。
您不能在带有 Win32 的16位 Windows 下使用 OllyDbg。这种32位扩展操作系统无法实现某些必需的调试功能。
您既不能调试 DOS 程序也不能调试16位 NE(New Executable)格式文件,我也没有打算在未来的版本中支持这些。安息吧,古老而美好的命令提示符!
三,反汇编器[Disassembler]
反汇编器识别所有的标准80x86、保护、FPU、MMX和3DNow!指令集(包括Athlon扩展的MMX指令集)。但它不识别ISSI命令,尽管计划要在下个版本中支持这种命令。某些过时或者未公开的命令,像LOADALL,也不支持。
反汇编器可以正确解码16位地址。但它假设所有的段都是32位的(段属性使用32位)。这对于PE[Portable Executable]格式文件总是真的。OllyDbg不支持16位的NE
[New Executables]格式。
如果您熟悉MASM或者TASM,那么反汇编的代码对于您没有任何问题。但是,一些特例也是存在的。以下命令的解码与Intel的标准不同:
AAD (ASCII Adjust AX Before Division) -
该命令的解码后的一般形式为:AAD imm8
AAM (ASCII Adjust AX After Multiply) -
该命令(非十进制数)的一般解码形式为:AAM imm8
SLDT (Store Local Descriptor Table register) -
操作数总被解码为16位。这个命令的32位形式会在目的操作数的低16位中存储段选择器,并保留高16位不变。
SALC (Sign-extend Carry bit to AL, undocumented) -
OllyDbg 支持这个未公开指令。
PINSRW (Insert Word From Integer Register, Athlon extension to MMX) -
在AMD的官方文档中,这个命令的内存形式使用了16位内存操作数;然而寄存器形式需要32位寄存器,但只使用了低16位。为了方便处理,反汇编器解码寄存器为16
位形式。而汇编器两种形式都支持。
CVTPS2PI and CVTTPS2PI (Convert Packed Single-Precision Floating to Packed Doubleword, Convert with Truncation Packed Single-Precision Floating to Packed Doubleword) -
在这些命令中,第一个操作数是MMX寄存器,第二个或者是128位XMM寄存器或者是64位内存区域。为了方便处理,内存操作数也被解码为128位。
有些指令的助记符要依赖操作数的大小:
不分大小的形式 明确的16位形式 明确的32位形式
PUSHA PUSHAW PUSHAD
POPA POPAW POPAD
LOOP LOOPW LOOPD
LOOPE LOOPWE LOOPDE
LOOPNE LOOPWNE LOOPDNE
PUSHF PUSHFW PUSHFD
POPF POPFW POPFD
IRET IRETW IRETD
您可以改变解码大小敏感助记符[decoding of size-sensitive mnemonics].。根据选项,反汇编器从三种可能中选择之一进行解码。这个选项也会影响汇编器的默认处理方式。
解码MMX和3DNow!指令总是开启的,尽管您的处理器并不支持这些指令。四,分析器[Analysis]
OllyDbg 整合了一个快速而强大的代码分析器。您可以从快捷菜单,或者在CPU窗口的反汇编面板中按 Ctrl+A ,或者在可执行模块中选择“分析全部模块[Analyze all modules]”,来使用它。
分析器有很高的启发性。它能区分代码和数据,标记入口和跳转目的地址,识别转换表[switch tables],ASCII 和 UNICODE 串,定位函数过程,循环,高阶转换[
high-level switches]并且能解码标准API函数的参数(示例[example])。OllyDbg 的其他部分也广泛的使用了分析后的数据。
这是如何实现的?我将为您揭开这一神秘面纱。第一遍,OllyDbg反汇编代码段中所有可能的地址,并计算调用的每个目的地址的个数。当然,很多调用是假的,但不可能两个错误的调用都指向了相同的命令,当然如果有三个的话,就更不可能了。因此如果有三个或者更多的调用指向了相同的地址,我可以肯定的说这个地址是某个频繁使用的子程序的入口。从定位的入口出发,我继续跟踪所有的跳转和函数调用,等等。按这种方法,我可能准确定位99.9% 的命令。但是,某些字节并不在这个链条上。我再用20多种高效的启发方法(最简单的方法,比如“直接访问前64K内存是不允许的,像在MOV [0],EAX中”)来探测他们
有时,分析器在您感兴趣的地方分析错误。有两种解决方法:或者从选中的部分移除分析(快捷键退格键),这样 OllyDbg 将使用默认的解码(反汇编)方式;或者设置
解码提示[decoding hints]并重新分析。注意:在某些情况下,当分析器认为您的提示是不合适的,或者有冲突,则可能忽略您的设置。
探测程序的函数过程也很简单。在分析器眼中看来,程序只是一个连绵不断的代码,从一个入口开始,可能达到(至少从理论上)所有的命令(除了NOP以及类似的用于填充间隙的命令)。您可能指定三个识别级别。严格的函数过程要求有准确的一个入口,并且至少有一个返回。在启发级别下,分析器只要求过程有一个入口。而如果您选择模糊模式,差不多连贯的代码都会被识别为单独的过程。现代编译器进行全局代码优化,有可能把一个过程分成几个部份。在这种情况下,模糊模式非常有用。但是也会误识别的机率也就更高。
同样地,循环是一个封闭的连续的命令序列,并有一个到开始处的跳转作为一个入口,还有若干个出口。循环与高级操作命令 do, while 和 for 相对应。OllyDbg 能够识别任何复杂的嵌套循环。他们会在反汇编栏[Disassembly]中用长而粗括号标记。如果入口不是循环的第一个命令,OllyDbg会用一个小三角进行标记。
为了实现一个转换[switch], 许多编译器,读取转换变量[switch variable]到寄存器中,然后减它,像如下的代码序列:
MOV EDX,
SUB EDX,100
JB DEFAULTCASE
JE CASE100 ; Case 100
DEC EDX
JNE DEFAULTCASE
... ; Case 101
这个序列可能还包含一到两阶的转换表、直接比较、优化和其他元素。如果在比较或跳转的很深处,这就很难知道哪是一个分支[Case]。OllyDbg 会帮助您,它会标记所有的分支,包括默认的,甚至尝试分析每个分支的含义,如'A'、WM_PAINT 或者 EXCEPTION_ACCESS_VIOLATION。如果命令序列没有修改寄存器(也就是仅仅由比较组成),那么这可能不是转换,而很有可能是选择嵌套:
if (i==0) {...}
else if (i==5) {...}
else if (i==10) {...}
如果需要OllyDbg将选择嵌套解码成选择语句,请在分析1[Analysis1]中设置相关选项。
OllyDbg包含多达1900条常用API函数,这些都作为内部预处理资源。这个列表包含了KERNEL32, GDI32, USER32, ADVAPI32, COMDLG32, SHELL32, VERSION, SHLWAPI, COMCTL32, WINSOCK, WS2_32 和 MSVCRT。您可以添加自己的函数描述[add your own descriptions]。如果分析器遇到的调用,使用了已知的函数名(或者跳转到这样的函数),它将在调用之前立即解码PUSH命令。因此,您只需略微一看就能明白函数调用的含义。OllyDbg还包含了大约400多种的标准C函数。如果您有原始的库文件,我推荐您在分析前扫描目标文件。这样OllyDbg将能解码这些C函数的参数。
如果选项“猜测未知函数的参数个数”开启,分析器将会决定这个调用函数过程使用的长度为双字的参数个数。并且标记他们为参数1[Arg1],参数2[ Arg2],等等。注意:无论如何,寄存器参数是无法识别的,所以不会增加参数的数目。分析器使用了一种比较安全的方法。例如,它不能识别的没有参数的函数过程,或者该过程POP
命令直接做返回前的寄存器恢复,而不销毁参数。然而,识别出来的函数参数数目通常非常高,这大大加大了代码的可读性。
分析器能够跟踪整型寄存器的内容。现代优化编译器,特别是奔腾系列,频繁地使用寄存器读取常量和地址,或使用尽量少的使用内存。如果某个常量读取到寄存器中,分析器会注意它,并尝试解码函数和其参数。分析器还能完成简单的算术计算,甚至可以跟踪压栈和出栈。
分析器不能区分不同类的名称[different kinds of names]. 。如果您将某些函数指定为已知的名称,OllyDbg将会解码所有到该地址的调用。这是几个预定义的特殊名称
WinMain, DllEntryPoint and WinProc。您可能使用这些标签标记主程序、DLL的的入口以及窗口过程(注意:OllyDbg不检查用户自定义的标签是否唯一)。另外,假定预定义参数assume predefined arguments是一种更好的方法
不幸的是,没有一般规则能够做到100%的准确分析。在某些情况下,例如当模块包含了P-Code或代码段中包换了大量的数据,分析器可能将一些数据解释成代码。如果统计分析显示代码部分很可能是压缩包或者经过加密了,分析器会发出警告。如果您想使用Hit跟踪[Hit trace],我建议您不要使用模糊分析[fuzzy analysis],因为设置断点的地方可能正是数据部分。
自解压文件[Self-extractable files] 通常有一个自提取器,在“正式”代码段之外。如果您选择自解压选项[SFX option]中的“扩展代码段,包含提取器[Extend code section to include self-extractor]”,OllyDbg将会扩展代码段,形式上允许分析它,并可以使用Hit跟踪[Hit] trace和Run跟踪[Run trace]。
2005-9-6 15:27 乾龙五,Object扫描器[Object scanner]
扫描器将特定的目标文件或者目标库(包括OMF和COFF两种格式),提取出代码段,然后将这些段定位在当前模块的代码节[Code section]中.如果段定位好了,扫描器将从目标文件中的调试信息提取名称(也就是所谓的库标签[library labels])。这极大的增加了代码与数据的可读性.
扫描器并不会对已识别的目标文件进行标签匹配,所以它不能识别非常小或相似的函数(比如:两个函数只是在重定位有区别)。因此要经常检查扫描器发送到登陆窗口的警告列表!六,Implib扫描器 [Implib scanner]
某些DLL的输出符号仅仅是一个序号。许多符号都是井号加数字(比如:MFC42.#1003),这非常不便于理解。幸运的是,软件零售商提供了输入连接库(implibs),它与序号符号名相关。
使用implib扫描器的方法:从主菜单中选择调试[Debug]|选择输入链接库[Select import libraries]。当您加载应用程序时,OllyDbg会读取链接库并从内置表格[
internal tables]中提取符号名。每次遇到序号符号,而对应的链接库已经注册到OllyDbg中时,这个序号符号会被替换。七,如何开始调试[How to start debugging session]
最简单的方法是:运行 OllyDbg,点击菜单上的文件[File]|打开[Open],选择您想调试的程序。如果程序需要命令行参数,您可以在对话框底部的输入栏中,输入参数或者选择以前调试时输入过的一条参数。
OllyDbg 能够调试独立的DLL[stand-alone DLLs]。在这种情况下,OllyDbg 会创建并运行一个小的应用程序来加载链接库并根据您的需要调用输出函数。
如果您想重新启动上一次调试的程序,只要按一下 Ctrl+F2(这是重启程序的快捷键),这样 OllyDbg 会以同样的参数运行这个程序。另一种做法是在菜单中选择文件[File],从历史列表中选择程序。您也可以在 Windows 资源管理器中将可执行文件或 DLL 文件拖拽到 OllyDbg 中。
当然,您可以在 OllyDbg 启动时,运行指定带有运行参数的被调试程序。例如:您可以在桌面创建一个 OllyDbg 的快捷方式,右击并选择“属性”,在“快捷方式”中的“目标”中添加调试的程序的全路径。这样,您每次双击快捷方式时,OllyDbg 将自动运行被调试程序。注意:DLL文件不支持这种方式。
您可以把正在运行的进程挂接到 OllyDbg 中。在菜单中打开 文件[File]|挂接[Attach],从进程列表中选择要挂接的进程。注意:在您关闭 OllyDbg 的同时,这个进程也会被关闭。不要挂接系统进程,否则可能会导致整个操作系统的崩溃。(事实上在大多数情况下,操作系统禁止您挂接敏感进程)。
OllyDbg 可以作为即时[just-in-time]调试器。这需要在系统注册表中注册。在菜单中选择选项[Options]|即时调试[Just-in-time debugging] 并在弹出的对话框中单击按钮“设置OllyDbg为即时调试器”[Make OllyDbg just-in-time debugger]。今后,如果某个应用程序发生了非法操作,系统将提示您是否用 OllyDbg 调试这个程序。操作系统会启动 OllyDbg 并直接停在发生异常的地方。如果您选择了“挂接时不询问”[attaching without confirmation],则在即时调试时OllyDbg不会弹出询问对话框。如果想恢复成以前的即时调试器[Restore old just-in-time debuger],按相应的按钮即可。
另一种方法是把 OllyDbg 添加到与可执行文件关联的快捷菜单中(这个想法是 Jochen Gerster 提出的)。在主菜单中,选择选项[Options]|添加到资源管理器中[Add to Explorer]。以后您可以在所有的文件列表中,右击可执行文件或DLL,在快捷菜单中选择OllyDbg。这个功能会创建四个注册表键值:
HKEY_CLASSES_ROOT\exefile\shell\Open with OllyDbg
HKEY_CLASSES_ROOT\exefile\shell\Open with OllyDbg\command
HKEY_CLASSES_ROOT\dllfile\shell\Open with OllyDbg
HKEY_CLASSES_ROOT\dllfile\shell\Open with OllyDbg\command
OllyDbg能够调试控制台程序(基于文字的)。
OllyDbg不能调试.NET应用程序。.NET程序是由微软的中间语言这种伪指令组成的,或是on-the-fly to native ?6 commands编译的。
注意:如果您运行的是Windows NT、2000 或XP操作系统,您应该拥有管理员权限以
八,CPU 窗口[CPU window]
对于用户来说,CPU窗口在OllyDbg中是最重要的窗口。您调试自己程序的绝大部分操作都要在这个窗口中进行。它包括以下五个面板(这五个面板的大小都是可以调节的):
反汇编[Disassembler]
信息[Information]
数据[Dump]
寄存器[Registers]
栈[Stack]
按TAB键,可以切换到下一个CPU面板中(顺时针方向)。
按Shift+TAB,可以切换到前一个CPU面板(逆时针方向)。九,断点[Breakpoints]
OllyDbg支持数种不同类型的断点:
- 一般断点[Ordinary breakpoint], 将您想中断的命令的第一个字节,用一个特殊命令INT3(调试器陷阱)来替代。您可以在反汇编窗口中选中要设断点的指令行并按下 F2 键就可以设定一个此类型的断点。也可以在快捷菜单中设置。再次按下 F2 键时,断点将被删除。注意,程序将在设断指令被执行之前中断下来。
INT3断点的设置数量是没有限制的。当您关闭被调试程序或者调试器的时候,OllyDbg将自动把这些断点保存到硬盘中,永远不要试图在数据段或者指令的中间设置这种断点,如果您试图在代码段以外设置断点,OllyDbg将会警告。您可以在安全选项[Security options]中永远关闭这个提示,在某些情况下调试器会插入自带的临时INT3
断点。
- 条件断点[Conditional breakpoint] (快捷键 Shift+F2) 是一个带有条件表达式的普通INT3断点。当调试器遇到这类断点时,它将计算表达式的值,如果结果非零或者表达式无效,将暂停被调试程序,当然,由条件为假的断点引起的开销是非常高的(主要归因于操作系统的反应时间)。在Windows NT、奔腾Ⅱ/450处理器环境下
OllyDbg每秒最多处理2500个条件为假的断点。条件断点的一个典型使用情况就是在Windows消息上设置断点(比如 WM_PAINT)。为此,您可以将伪变量 MSG 同适当的参数说明联合使用。如果窗口被激活,参考一下后面的消息断点描述。
- 条件记录断点 [Conditional logging breakpoint] (Shift+F4)是一种条件断点,每当遇到此类断点或者满足条件时,它将记录已知函数表达式或参数的值。例如,您可以在一些窗口过程函数上设置记录断点并列出对该函数的所有调用。或者只对接收到的WM_COMMAND消息标识符设断,或者对创建文件的函数(CreateFile)设断,并且记录以只读方式打开的文件名等,记录断点和条件断点速度相当,并且从记录窗口中浏览上百条消息要比按上百次F9轻松的多,您可以为表达式选择一个预先定义好的解释说明。
您可以设置通过的次数 - 每次符合暂停条件时,计数器就会减一。如果通过计数在减一前,不等于零,OllyDbg就会继续执行。如果一个循环执行100次(十进制),在循环体内设置一个断点,并设置通过次数为99(十进制)。OllyDbg将会在最后一次执行循环体时暂停。
另外,条件记录断点允许您传递一个或多个命令给插件[plugins]。例如,您需要使用命令行插件改变一个寄存器的内容,然后继续执行程序。
- 消息断点[Message breakpoint]和条件记录断点基本相同,除了OllyDbg会自动产生一个条件,这个条件允许在窗口过程的入口处设置某些消息(比如WM_PSINT)断点,您可以在窗口[Windows]中设置它。
- 跟踪断点[Trace breakpoint] 是在每个选中命令上设置的一种特殊的INT3断点。如果您设置了Hit跟踪[hit trace] ,断点会在命令执行后移除,并在该地址处做一个标记。如果您使用的是Run跟踪[run trace] ,OllyDbg会添加跟踪数据记录并且断点仍然是保持激活状态。
- 内存断点[Memory breakpoint] OllyDbg每一时刻只允许有一个内存断点。您可以在反汇编窗口、CPU窗口、数据窗口中选择一部分内存,然后使用快捷菜单设置内存断点。如果有以前的内存断点,将被自动删除。您有两个选择:在内存访问(读,写,执行)时中断,或内存写入时中断。设置此类断点时,OllyDbg将会改变所选部分的内存块的属性。在与80x86兼容的处理器上将会有4096字节的内存被分配并保护起来。即使您仅仅选择了一个字节,OllyDbg 也会将整个内存块都保护起来。这将会引起大量的错误警告,请小心使用此类断点。某些系统函数(特别是在Windows95/98下)在访问受保护的内存时不但不会产生调试事件反而会造成被调试程序的崩溃。
- 硬断点[Hardware breakpoint](仅在Windows ME,NT或2000下可用)在80x86兼容的处理器上,允许您设置4个硬件断点。和内存断点不同,硬件断点并不会降低执行速度,但是最多只能覆盖四个字节。在单步执行或者跟踪代码时,OllyDbg能够使用硬断点代替INT3断点。
- 内存访问一次性断点[Single-shot break on memory access] (仅在Windows NT或2000下可用)。您可以通过内存窗口的快捷菜单(或按F2),对整个内存块设置该类断点。当您想捕捉调用或返回到某个模块时,该类断点就显得特别有用。中断发生以后,断点将被删除。
- 暂停Run跟踪[Run trace pause] (快捷键:Ctrl+T)是在每一步Run跟踪[run trace] 时都要检查的一个条件集.您可以在EIP进入某个范围或超出某个范围时暂停,某个条件为真时暂停,或者命令与指定的模式匹配时暂停,或者当命令可疑的时候暂停。注意,这一选择会极大的(高达20%)降低Run跟踪的速度。
OllyDbg也可以在一些调试事件[debugging events]上暂停程序执行。比如加载或卸载DLL,启动或终止线程,或者程序发出调试字符串的时候。
10,数据窗口[Dump]
数据窗口用于显示内存或文件的内容。您可以从以下预处理格式[predefined formats]中选择一种显示方式:字节[byte]、文本[text]、整数[integer]、浮点数[float
]、地址[address],反汇编[disassembly]、 PE头[PE Header]。
所有的dump窗口支持备份[backup]、搜索和编辑操作。CPU 窗口[CPU window]的Dump面板允许您对可执行代码的数据和可执行文件(.exe,或.dll)的内存映射做如下操作:定义标签[labels]、设置 内存断点[memory breakpoints], 查找参考[references]。数据菜单[Dump menu]只显示与选中部分相关的命令。
如果 备份[backup]可用,则单击第一个列标题栏,会在地址[Address]/备份[Backup] 两种显示模式之间切换。点击其他列标题栏,会改变Dump模式。
像反汇编窗口一样,数据窗口也保存了大量查看内存地址的历史记录。您可以通过“+”和“-”键来访问您过去查看过的数据地址空间。
要翻动一字节的数据,可以按住Ctrl l键并按上/下方向键。
可执行模块窗口[Executable modules window]
可执行模块窗口(快捷键:Alt+E)列出了当前被调试进程加载的所有可执行模块。它也显示了很多有用的信息,比如模块大小、入口地址、模块版本、以及可执行文件路径等。一些信息,如以十进制显示的模块大小、入口地址的符号名、是否为系统模块等,通常是被隐藏的。如果想看,可以增加相应栏的宽度。快捷菜单支持以下操作:
刷新[Actualize] - 重新扫描模块并去除对新加载模块的高亮显示。在大多数情况下,OllyDbg会自动完成该操作。
查看内存[View memory] - 打开内存窗口,并定位到属于该模块镜像的第一个内存块处。
在CPU窗口中查看代码[View code in CPU] (快捷键:回车键) - 在反汇编窗口中显示模块的可执行代码。
跟进到入口[Follow entry] - 在反汇编窗口中跟进到模块的入口处。
在CPU窗口中查看数据[Dump data in CPU] -在CPU窗口的数据面板中显示模块的数据段。块代码段。
显示名称[View names] (快捷键:Ctrl+N) -显示当前模块定义或使用的全部名称[names](包括输出表、引入表、链接库、用户自定义)。
标记为系统DLL[Mark as system DLL],
标记为非系统DLL[Mark as non-system DLL] - 将选中模块标记为系统或非系统属性。如果设置为系统属性,则在Run跟踪[Run trace] 时会直接执行(不进行跟踪)这个模块,从而大大加快跟踪速度。默认情况下,所有驻留在系统目录(通常在Windows 95/98下为c:\windows\system ,在WinNT/2000/XP下为c:\winnt\system32)的模块都认为是系统模块。
立即更新.udd文件[Update .udd file now] -向文件“.udd”写入模块相关的全部数据,udd文件保存了在调试期间设置的断点、标签、注释、监视、分析等信息。当模块卸载时OllyDbg会自动创建.udd文件。
查看可执行文件[View executable file] - 显示可执行文件的全部内容。
查看全部资源[View all resources] - 以列表形式显示模块定义的全部资源,并带有一个简短信息。OllyDbg并不把资源当作单独实体来支持。您可以提取[Dump]并以二进制的形式进行编辑。
查看资源字符串[View resource strings] -以列表形式显示资源字符串及其标识符。
查看Run跟踪的统计[View run trace profile] - 在此模块中计算统计[profile] 。相关信息:Run跟踪[Run trace].
分析全部模块[Analyze all modules] -允许同时分析全部模块。分析将从代码中提取大量的有用信息;代码经过分析后再进行调试,通常会非常快并且可靠。
鼠标双击某一行,将会在反汇编窗口中显示模块的执行代码。十,内存映射窗口[Memory map window]
内存映射窗口显示了被调试程序分配的所有内存块。因为没有标准的方法来完成这项任务,所以OllyDbg可能会把一个大的内存块分成几个部分。然而,在大多数情况下,并非一定要精确处理。如果想查看由应用程序通过调用GlobalAlloc()和LocalAlloc()等申请的内存块列表,请使用堆列表[Heap list]。
如果内存块是可执行模块的一个节,OllyDbg则会报告这个内存块所包含的数据类型:代码、数据、资源等。
Windows95/98是和WindowsNT/2000是有一些区别的。在Windows95/98下,OllyDbg是不能显示被映射文件的名称的。另外,Windows95/98不允许的访存类型为读和写,然而,在WindowsNT/2000下,OllyDbg却有拥有更多功能,包括执行访问,写复制[copy-on-write]以及监视标志位。OllyDbg忽略写复制[copy-on-write]属性。
如果OllyDbg发现程序分配了新内存或者重新分配了已经存在的内存块,它将在内存映射窗口中高亮显示相应的记录,去掉高亮度显示,可以选择快捷菜单中的刷新[
Actualize]项。
您可以按Alt+M来调用内存窗口。
以下是快捷菜单中可以选择的菜单项:
刷新[Actualize] - 更新已分配内存的列表并去除对新内存块的高亮显示。
在反汇编窗口中查看[View in Disassembler] -在反汇编窗口中查看:在反汇编窗口中打开内存块,这一选项仅在某些模块的内存块中包含可执行代码或者自解压器时可用。
在CPU数据窗口中查看[Dump in CPU] - 在CPU的数据窗口中显示内存块的内容。
数据窗口[Dump] - 在单独窗口中显示内存块内容。如果内存块的类型已知,则OllyDbg会自动选择显示格式。
查看全部资源[View all resources] - 如果内存块包含资源数据,则列出所有资源及相关数据。OllyDbg并不把资源当作单独实体来支持。您可以显示其数据并以二进制的形式进行编辑。
查看资源字符串[View resource strings] - 如果内存块包含资源数据,则列出全部资源字符串及其标识符。
搜索[Search] - 允许搜索所有的内存块,从选择处开始,搜索匹配的二进制串。如果找到,则OllyDbg将显示该内存块。内存映像窗口和数据窗口共享同一种搜索模式,所以您可以在弹出的数据窗口中立即继续搜索该二进制串出现的下一位置。按Esc键可以关闭数据窗口。
搜索下一个[Search next](快捷键:Ctrl+L) - 继续上次搜索。
设置访问中断[Set break-on-access] (快捷键:F2,仅在WindowsNT/2000下可用) - 保护整个内存块。当中断发生后OllyDbg暂停被调试程序并清除断点。这类断点在您想捕捉调用或返回到某个模块的时候特别有用。
清除访问中断[Remove break-on-access] (快捷键:F2) - 从内存块中清除访问中断保护。
设置内存访问断点[Set memory breakpoint on access] - 在整个内存块上设置断点,每当该内存块被访问时程序都将中断。OllyDbg只支持一个内存访问断点。在
Windows95/98下,当系统程序访问含有内存断点的内存块时,可能会导致所被调试程序崩溃,因此,不到万不得已,请不要设置这种断点。
设置内存写入断点[Set memory breakpoint on write] - 在整个内存块上设置断点,每当该内存块被写入数据时程序都将中断。在Windows95/98下,当系统程序访问含有内存断点的内存块时,可能会导致所被调试程序崩溃,因此,不到万不得已,请不要设置这种断点。
清除内存断点[Remove memory breakpoint] - 清除内存断点。
清除自解压内存断点[Remove SFX memory breakpoint] - 停止搜索自解压程序[self-extractable (SFX) program]的真实入口。这个搜索使用了特殊类型的内存断点。
访问设置[Set access] -设置整个内存块的保护属性,可选择的有:
禁止访问[No access]
只读[Read only]
读/写[Read/write]
执行[Execute]
执行/读[Execute/read]
完全访问[Full access]
复制到剪切板[Copy to clipboard]
整行[Whole line] -以多行文本(包括解释)的方式把所选记录复制到剪切板,如果复制时想排除某些列,可将该列的宽度置为最小(该栏剩余的边框将变灰)。
整个表格[Whole table] -以多行文本的方式将整个内存映像信息复制到剪切板,该文本的第一行为窗口标题("内存映射[Memory map]"), 第二行为列标题栏,后面几行的内容为内存数据记录。复制将保持列的宽度。如果复制时想排除某些列,可将该列的宽度置为最小(该栏剩余的边框将变灰)。十一,监视与监察器[Watches and inspectors]
监视[Watch] 窗口包含若干个表达式[expressions]。它在第二列里显示这些表达式的值。OllyDbg 会把这些表达式保存到主模块的.UDD文件中,因此它们在下一次调试时同样有效。
监察器[inspector]是显示若干变量、1/2维数组或是选定项目结构数组[selected items of array of structures]的独立窗口。它的表达式与监视窗口中的基本相同,只是多包含了两个参数:%A和%B。您可以指定这两个参数的界限,OllyDbg 将会用所有可能的组合代替表达式中的%A和%B。从0开始一直到界限(不包含界限),并在表格中显示结果。参数%B(列数)的界限不能超过16。
例如,如果您指定了表达式%A+%B,并且限定%A和%B的上限为3,您将获得如下的表格:
十三,线程[Threads]
OllyDbg 以简单而有效的线程管理为特色。如果您单步调试、跟踪、执行到返回或者执行到所选,则线程管理器将停止除当前线程以外的所有线程。即使当前线程被挂起,它也会将其恢复。在这种情况下,如果您手动挂起或者恢复线程,动作将被延期。如果您运行被调试的应用程序,OllyDbg将恢复最初的线程状态。(从调试器的角度来看,Hit跟踪[hit trace]和自由运行是等效的)。
依据这种方案,线程窗口可能会有如下五种线程状态:
激活[Active] - 线程运行中,或被调试信息暂停t
挂起[Suspended] - 线程被挂起
跟踪[Traced] - 线程被挂起,但OllyDbg正在单步跟踪此线程
暂停[Paused] - 线程是活动的,但OllyDbg临时将其挂起,并在跟踪其它的线程
结束[Finished] - 线程结束
.
线程窗口同时也显示了最后的线程错误(GetlastError函数的返回值)并计算该线程以用户模式和系统模式(仅NT/2000/XP)运行的时间。线程窗口还会高亮主线程的标识符。
以下在快捷菜单中可用:
刷新[Actualize] - 标记所有线程为旧的。
挂起[Suspend] - 挂起线程。
恢复[Resume] - 恢复先前挂起的线程。
设置优先级[Set priority] - 调整进程中线程的优先级。以下选项可用:
空闲[Idle] - 进程中线程的最低优先级
最低[Lowest]
低[Low]
标准[Normal]
高[High]
最高[Highest]
时间临界[Time critical] - 最高优先级
在CPU窗口打开[Open in CPU](双击)- 在CPU窗口中显示所选线程的当前状态。十四,复制到剪切板[Copy to clipboard]
整行[Whole line] -全部行--以多行文本的形式并带注释将所选记录复制到剪切板。如果在复制时想排除某个栏目,可以将该栏的宽度置为最小(栏目的残留部分将变灰)。
整个表格[Whole table] - 整个表格--以多行文本的形式将整个内存映象复制到剪切板,该文本的第一行包含窗口标题(“内存映射[Memory map]”),第二行是栏目标题,所有后继行是内存数据记录。复制将保持栏目的宽度。如果在复制时想排除某些栏目,可以将该栏的宽度置为最小(栏目的残留部分将变灰)。十五,调用栈[Call stack]
调用栈窗口(快捷键:Alt+K)根据选定线程的栈,尝试反向跟踪函数调用顺序并将其显示出来,同时包含被调用函数的已知的或隐含的参数。如果调用函数创建了标准的堆栈框架(PUSH EBP; MOV EBP,ESP),则这个任务非常容易完成。现代的优化编译器并不会为栈框架而操心,所以OllyDbg另辟蹊径,采用了一个变通的办法。例如,跟踪代码到下一个返回处,并计算其中全部的入栈、出栈,及 ESP 的修改。如果不成功,则尝试另外一种办法,这个办法风险更大,速度也更慢:移动栈,搜索所有可能的返回地址,并检查这个地址是否被先前的已分析的命令调用。如果还不行,则会采用启发式搜索。栈移动[Stack Walk]可能会非常慢。OllyDbg 仅在调用栈窗口打开时才会使用。
调用栈窗口包含5个栏目:地址[Address]、栈[Stack]、过程[Procedure],调用来自[Called from],框架[Frame]。地址[Adress]栏包含栈地址,栈[Stack]
栏显示了相应的返回地址或参数值。
函数[Procedure](或 函数/参数[Procedure / arguments])显示了被调用函数的地址,在某些情况下,OllyDbg并不能保证该地址是正确的并会添加如下标记之一:
? 找到的入口点不可靠
可能[Maybe] OllyDbg无法找到精确的入口点,报告的地址是用启发式算法猜测的。
包含[Includes] OllyDbg无法找到入口点,仅知道该函数包含显示的地址
通过按例标题栏上的按钮或从菜单中选择“隐藏/显示参数[Hide/Show arguments]”,可以在显示或隐藏函数的参数之间切换。
调用来自[Called from]用于显示调用该函数的命令地址。最后一栏是框架[Frame]这一栏默认是隐藏的,如果框架指针的值(寄存器EBP)已知的话,则该栏用于显示这个值。
当调用函数经过分析[analyzed].后,栈移动会更可靠并且迅速。十六,调用树[Call tree]
调用树(快捷键:在反汇编窗口中Ctrl+K)利用分析[Analysis]的结果来找出指定函数过程直接或间接调用的函数列表,同时列出指定函数过程被调用的地址。为了避免由此可能造成的副作用。调用树会判断选定函数是否明确地是递归的。“明确地”意味着它不会跟踪目标未知的调用,比如CALL EAX。如果函数过程中有未知调用,调用树将会添加标记“未知目标”。
某些函数调用将会添加如下注释之一:
叶子[Leaf] 不调用其他函数
纯函数[Pure] 不调用函数,不会产生副作用
单返回[RETN] 只有一个RETN 命令
系统[Sys] 系统动态链接库中的函数。系统动态链接库定义为保存在系统目录下的动态链接库。
如果想在调用树上移动,可以双击“被调用[Called from]”或“调用/直接调用[Calls/Calls directly]”两栏中的地址。调用树窗口保存了移动记录(快捷键“-”和“+”)。
如果被调试的程序包含几个模块,推荐您分析所有模块。Call tree 不会试图处理系统函数。十七,选项[Options]
外观选项[Appearance options]
常规[General]
默认[Defaults]
对话框[Dialogs]
目录[Directories]
字体[Fonts]
颜色[Colours]
代码高亮[Code highlighting]
调试选项[Debugging options] (Alt+O)
安全[Security]
调试[Debug]
事件[Events]
异常[Exceptions]
跟踪[Trace]
自解压[SFX]
字符串[Strings]
地址[Addresses]
命令[Commands]
反汇编[Disasm]
CPU
寄存器[Registers]
栈[Stack]
分析1[Analysis 1]
分析2[Analysis 2]
分析3[Analysis 3]
即时调试[Just-in-time debugging]
添加到资源管理器[Add to Explorer]十八,搜索[Search]
OllyDbg 允许您使用以下的搜索方式:
符号名(标签)[Symbolic name (label)]
二进制串[binary string]
常量[constant]
命令[command]
命令序列[sequence of commands]
模块间调用[intermodular calls]
修改过的命令或数据[modified command or data]
自定义标签[user-defined label]
自定义注释[user-defined comment
文本字符串[text string]
Run跟踪的记录[record in run trace]
参考命令[referencing commands]
十九,自解压文件[Self-extracting (SFX) files]
自解压文件由提取程序和压缩的原程序两部分组成。当遇到自解压文件(SFX)文件时,我们通常希望跳过解压部分,而直接跳到原始程序的入口(真正的入口)。
OllyDbg 包含了几个便于完成这一任务的功能。
通常提取程序的加载地址都在执行代码之外。在这种情况下,OllyDbg 将这类文件均视作为自解压文件(SFX)。
当自解压选项[SFX options]要求跟踪真正入口时,OllyDbg 在整个代码节[Code section]设置内存断点,最初这里是空的,或者只包含压缩数据。当程序试图执行某个在这个保护区域的命令,而这些命令不是 RET 和 JMP 时,OllyDbg 会报告真正的入口。这就是提取工作的原理。
上面的方法非常慢。有另外一种比较快的方法。每次读取数据发生异常时,OllyDbg 使这个4K内存区域变为可读,而使原先可读的区域变为无效。而每次发生写数据异常时,
OllyDbg 使这个区域变为可写,而使原先可写的区域变为无效。当程序执行在保留的保护区域中的指令时,OllyDbg 报告真正的入口。但是,当真正的入口点在可读或可写区域内部时,报告的地址就可能有误。
您可以纠正入口位置,选择新的入口,从反汇编窗口的快捷菜单中选择“断点[Breakpoint]|设置真正的自解压入口[Set real SFX entry here]”。如果相应的SFX选项是开启的,OllyDbg下次可以迅速而可靠的跳过自提取程序。
注意:OllyDbg 在跟踪采取了保护或者反调试技术的解压程序时通常会失败。 二十,单步执行与自动执行[Step-by-step execution and animation]
您可以通过按 F7(单步步入)或 F8(单步步过),对程序进行单步调试。这两个单步执行操作的主要区别在于:如果当前的命令是一个子函数,按F7,将会进入子函数,并停在子函数的第一条命令上;而按 F8,将会一次运行完这个子函数。如果您单步步过的子函数中含有断点或其他调试事件,执行将会被暂停,但 OllyDbg 会在子函数的后一条命令上,自动下一个断点,而这个断点您迟早会碰到。
如果被调试程序停在异常上,您可以跳过它,并转到被调试程序建立的句柄处。只需简单的 Shift 键和任何一个单步命令。
如果需要连续按F7、F8键上百次,您可以使用自动执行(Ctrl+F7或者Ctrl+F8)功能。在这种情况下,OllyDbg 将自动重复F7或者F8操作,并且实时更新所有的窗口。这个过程会在下面情况停止:
- 按 Esc 键或发出任何单步命令
- OllyDbg 遇到断点
- 被调试程序发生异常
使用“+”和“-”按键,可以回朔以前的执行历史[execution history].
注意:当执行停止时 OllyDbg 将会刷新大部分窗口。如果动态执行过程非常慢,可以尝试关掉或最小化没有用的窗口。
另外,更快捷的找到以前执行指令的办法是Run跟踪[run trace]。它将创建一个执行协议并告知您指定指令的执行时间和次数二一,Hit跟踪[Hit trace] portant; FLOAT: none; WORD-SPACING: 0px; FONT: 14px/25px verdana, SimSun, Arial, Helvetica, sans-serif; TEXT-TRANSFORM: none; COLOR: rgb(0,0,0); TEXT-INDENT: 0px; WHITE-SPACE: normal; LETTER-SPACING: normal; BACKGROUND-COLOR: rgb(204,232,204); TEXT-ALIGN: left; orphans: 2; widows: 2; webkit-text-size-adjust: auto; webkit-text-stroke-width: 0px">资源:如果 Windows API 函数使用了参考资源串,OllyDbg 可以显示它。其支持显示的类型仅限于附带资源[attached resources]的列表、数据显示及二进制编辑、。
断点: OllyDbg 支持各种断点:一般断点、条件断点、记录断点(比如记录函数参数到记录窗口)、内存读写断点、硬件断点(只适用于ME/NT/2000)等。在Hit跟踪情况下,可以在模块的每条命令上都设置INT3断点。在使用500-MHZ处理器的 Windows NT 中,OllyDbg 每秒可以处理高达 5000 个中断。
监视与监察器:每个监视都是一个表达式并能实时显示表达式的值。您可以使用寄存器、常数、地址表达式、布尔值以及任何复杂代数运算,您还可以比较ASCII和UNICODE
字符串。监察器[inspectors]是一种包含了两个的索引序列的监视[Watches],它以二维表的形式呈现,可以对数组和结构进行解码分析。
Heap walk.:在基于Win95的系统中,OllyDbg 可以列出所有的已分配的堆。
句柄:在基于NT的系统中,OllyDbg 可列出被调试程序的所有系统句柄。
执行:.您可以单步执行、步入子程序或者步过子程序。您也可以执行程序直到函数返回时、执行到指定地址处,还可以自动执行。当程序运行时,您仍然可以操纵程序并能够查看内存、设置断点甚至修改代码。您也可以任意的暂停或重启被调试的程序。
Hit跟踪:.Hit跟踪可以显示出目前已执行的指令或函数过程,帮助您检验代码的各个分支。Hit跟踪会在指定指令到达之前设置断点,而在这个指令执行后,会把这个断点清除掉。
译者注:Hit在英文中是“击中”的意思,指令如果运行了就表示这个指令被“击中”了,没有执行的指令就是“未击中”,这样我们就很容易看出被调试程序哪些部分运行了,而哪些没有运行。
Run跟踪: Run跟踪可以单步执行程序,它会在一个很大的循环缓冲区中模拟运行程序。这个模拟器包含了除了SSE指令集以外的所以寄存器、标志、线程错误、消息、已经函数的参数。您可以保存命令,这样可以非常方便地调试自修改代码(译者注:比如加壳程序)。您可以设置条件中断,条件包括地址范围、表达式、命令。您可以将Run
跟踪信息保存到一个文件中,这样就可以对比两次运行的差别。Run跟踪可以回溯分析已执行过的上百万条命令的各种细节。
统计: 统计[Profiler]可以在跟踪时计算某些指令出现的次数。因此您就能了解代码的哪一部分被频繁执行。
补丁: 内置汇编器能够自动找到修改过的代码段。二进制编辑器则会以ASCII、UNICODE或者十六进制的形式同步显示修改后的数据。修改后的数据同其它数据一样,能够进行复制-粘贴操作。原来的数据会自动备份,以便数据恢复时使用。您可以把修改的部分直接复制到执行文件中,OllyDbg会自动修正。OllyDbg还会记录以前调试过程中使用的所有补丁。您可以通过空格键实现补丁的激活或者禁止。
自解压文件: 当调试自解压文件时,您往往希望跳过解压部分,直接停在程序的原始入口点。OllyDbg的自解压跟踪将会使您实现这一目的。如果是加保护的自解压段,自解压跟踪往往会失败。而一旦OllyDbg找到了入口点,它将会跳过解压部分,并准确的到达入口点。
插件:您可以把自己的插件添加到 OllyDbg 中,以增加新的功能。OllyDbg 的插件能够访问几乎所有重要的数据的结构、能够在 OllyDbg 的窗口中添加菜单和快捷键,能够使用100个以上的插件API函数。插件API函数有详细的说明文档。默认安装已经包含了两个插件:命令行插件和书签插件。
UDD:OllyDbg 把所有程序或模块相关的信息保存至单独的文件中,并在模块重新加载时继续使用。这些信息包括了标签、注释、断点、监视、分析数据、条件等等
更多:这里介绍的功能,仅仅是 OllyDbg 的部分功能。因为其具有如此丰富的功能,以至于 OllyDbg 能成为非常方便的调试器!
2005-9-6 15:25 乾龙二,一般原理[General principles]
我希望您能对80x86系列处理器的内部结构有所了解,同时具有一定的编写汇编程序的能力。对于Microsoft Windows方面的知识,您也要熟悉。
OllyDbg是运行在Windows 95、Windows 98、Windows ME、Windows NT 和 Windows 2000系统下的一个单进程、多线程的分析代码级调试工具。它可以调试PE格式的执行文件及动态链接库,并可以对其打补丁。“代码级”意味着您可以直接与比特、字节或处理器指令打交道。OllyDbg 仅使用已公开的 Win32 API 函数,因此它可以在所有 Windows 操作系统及后继版本中使用。但是由于我没有对 XP 系统进行彻底测试,因此不能保证 OllyDbg 功能的充分发挥。注意:OllyDbg 不支持对 .NET 程序的调试。
OllyDbg不是面向编译器的。它没有特别的规则规定必须是哪一个编译器产生的代码。因此,OllyDbg可以非常好的处理通过编译器生成的代码,或是直接用汇编写入的代码。
OllyDbg可以并行调试程序。您无须暂停执行程序,就可以浏览代码和数据,设置断点、停止或恢复线程,甚至直接修改内存。(这可以视为一种软件调试的模式,与之相对的硬件模式则是当进程在运行时调试器被阻滞,反之亦然)。假使所需的操作比较复杂,OllyDbg会让进程终止一小段时间,但是这种暂停对于用户来说是透明的。
有时进程会发生非法操作。您可以把OllyDbg设置成即时[just-in-time]调试器,它会挂接出错程序,并停在程序产生异常的地方。
通过OllyDbg,您可以调试单独的DLL[standalone DLLs]文件。操作系统不能直接运行 DLL 文件,因此 OllyDbg 将一个可以加载 DLL 的小程序压缩到资源里,这个程序允许您调用最多10个参数的输出函数。
OllyDbg是完全面向模块[module-oriented]的。模块[Module]包括可执行文件(扩展名通常为.EXE)和在启动时加载或需要时动态加载的动态链接库(扩展名通常为.DLL
)。在调试期间,您可以设置断点[breakpoints]、定义新的标签[labels]、注释[comment]汇编指令,当某个模块从内存中卸载[unload]时,调试器会把这些信息保存在文件中,文件名就是模块的名称,扩展名为.UDD(表示 用户自定义文件[User-Defined Data])当OllyDbg下一次加载该模块时,它会自动恢复所有的调试信息,而不管是哪一个程序使用这个模块。假设您正在调试程序Myprog1,这个程序使用了Mydll。您在 Mydll 中设置了一些断点,然后您开始调试Myprog2,这个程序同样使用了Mydll。这时您会发现,所有 Mydll 中的断点依然存在,即使 Mydll 加载到不同的位置!
一些调试器把被调试进程的内存当作一个单一的(并且大部分是空的)大小为2 ^32字节的区域。OllyDbg采用了与之不同的技术:在这里,内存由许多独立的块组成,任何对内存内容的操作都被限制在各自的块内。在大多数情况下,这种方式工作得很好并且方便了调试。但是,如果模块包含好几个可执行段[executable sections],您将不能一次看到全部代码,然而这种情况是非常少见的。
OllyDbg 是一个很占用内存的程序[memory-hungry application]。它在启动时就需要 3 MB,并且当您第一次装载被调试的程序时还需要一到两兆的内存。每一次的分析、备份、跟踪或者文件数据显示都需要占用一定的内存。因此当您调试一个很大的项目,发现程序管理器显示有 40 或 60 兆内存被占用时,请不要惊慌。
为了有效地调试一些不带源码的程序,您必须首先理解它是如何工作的。OllyDbg 包含的大量特性可以使这种理解变得非常容易。
首先,OllyDbg包含一个内置的代码分析器。分析器遍历整个代码,分出指令和数据,识别出不同的数据类型和过程,分析出标准API函数(最常用的大约有1900个)的参数并且试着猜出未知函数的参数数目。您也可以加入自己的函数说明[your own function descriptions]。它标记出程序入口点和跳转目的地,识别出跳转表[table-driven switches]和指向字符串的指针,加入一些注释,甚至标示出跳转的方向等等。在分析结果的基础上,调用树[call tree]显示哪些函数被指定过程调用(直接或间接)并且识别出递归调用、系统调用和叶子过程[leaf procedures]。如果需要的话,您可以设置解码提示[decoding hints]来帮助分析器解析那些不明确的代码或数据。
OllyDbg还包含Object扫描器[Object Scanner]。如果您有库文件[libraries]或目标文件[object files],扫描器会在被调试的程序中定位这些库函数。在全部函数调用中,对标准函数的调用占很重要的一部分(据我估计可达70%)。如果您知道正要被调用的函数的功能,您就不必把注意力集中在这个函数上,可以简单地单步步过[
step over]这个call。分析器知道400多个标准C函数,比如fopen和memcpy。然而我必须承认当前版本的OllyDbg不能定位很短的函数(比一个return命令多不了多少的)或相似的函数(只在重定位上有不同)。
Object扫描器[Object scanner]也能够识别输入库[import libraries]。如果某个DLL是按序号输出的,您不会看到函数名,只会发现一堆无意义的神秘数字。这种DLL的开发者通常会提供一个输入库来实现函数符号名与序号间的对应。让OllyDbg使用这个输入库,它就会恢复原始的函数符号名。
面向对象的语言(如C++),使用了一种叫做名称修饰[name mangling]的技术,把函数类型和参数都加入函数名中。OllyDbg 可以解码[demangle]这种函数名,使程序更易读。
译者注:C++的名称修饰是编译器将函数的名称转变成为一个唯一的字符串的过程,这个字符串会对函数的类、其命名空间、其参数表,以及其他等等进行编码。C++的名称修饰适用于静态成员函数,也适用于非静态成员函数。静态函数的名称修饰的一个好处之一,是能够在不同的类里使用同一个名称来声明两个或者更多的静态成员函数----而不会发生名称上的冲突。
OllyDbg完全支持 UNICODE,几乎所有对 ASCII 字符串的操作都可以同样应用于 UNICODE。
汇编指令都是很相似的。您经常会搞不清自己是不是已经跟踪过某一段代码。在 OllyDbg 中您可以加入自己的标签[labels]和注释[comments]。这些极大地方便了调试。注意一旦您注释了某个DLL,以后每次加载这个DLL时,注释和标签都有效----尽管您在调试不同的程序。
OllyDbg可以跟踪标准的栈帧[stack frames](由PUSH EBP; MOV EBP,ESP所创建的)。现代编译器有禁止产生标准栈框架的选项,在这种情况下分配栈[stack walk
]是不可能的。当程序运行到已知的函数时,栈窗口[stack window]解析它的参数,调用栈[Call stack]窗口显示到达当前位置所调用函数的序列。
现代的面向对象应用程序广泛地使用了一种叫做结构化异常处理[Structured Exception Handling,SHE]的技术。SHE窗口[SEH window] 可以显示异常处理链。
多种不同的搜索[search]选项可以让您找到二进制代码或数据、命令或命令序列、常量或字符串、符号名或在 Run跟踪中的一条记录。
对于任何地址或常量,OllyDbg 可以找出参考[referencing]到该地址或常量的全部命令的列表。然后您可以在这个列表里找出对您来说是重要的参考。举例来说,某个函数可能被直接调用,或者经过编译器优化后把地址放入寄存器间接调用,或者把地址压入堆栈作为一个参数----没问题,OllyDbg 会找出所有这样的地方。它甚至能找到并列出所有和某个指定的位置有关的跳转。(真的?哦,天哪!……)
OllyDbg 支持所有标准类型的断点[breakpoints]----非条件和条件断点、内存断点(写入或访问)、硬件断点或在整个内存块上下断点(后两项功能只在Window ME,NT,2000,XP中有效)。条件表达式可以非常复杂(“当 [ESP+8] 的第 2 位被设置,并且 123456 位置处的字[word]小于10,或者 EAX 指向一个以“ABC”开头的 UNICODE 字串,但跳过前10次断点而在第11次中断”)。您可以设定一条或多条指令,当程序暂停时由OllyDbg传递给插件插件[plugins]。除了暂停,您还可以记录某个表达式的值(可以带有简短的说明),或者记录 OllyDbg 已知的函数的参数。在Athlon 2600+、Windows2000 环境下,OllyDbg 可以每秒处理多达 25000 个条件断点。
另一个有用的特性是跟踪。OllyDbg 支持两种方式的跟踪:hit和run。在第一种情况下,它对指定范围内的每条指令上设置断点(比如在全部可执行代码中)。当到达设断的指令后,OllyDbg 清除断点并且把该指令标记为hit。这种方法可以用来检测某段代码是否被执行。Hit跟踪速度惊人的快,在一个很短时间的启动后程序几乎达到了全速(译者注:这应该是与不进行调试时速度相比而言)。因为INT3断点可能对数据有灾难性的影响,所以我建议不要使用模糊识别过程。当代码没有被分析时Hit跟踪是不可以使用的。
Run跟踪[Run trace] 是一步一步地执行程序,同时记录精确的运行历史和所有寄存器的内容、已知的参数和可选的指令(当代码是自修改时会有帮助)。当然,这需要大量的内存(每个指令需要15至50个字节,取决于调试的模式)但是可以精确地回溯和分析。您可以只在选定的一段代码甚至是一条指令中进行Run跟踪,或者您可以跳过无关紧要的代码。对于每个地址,OllyDbg能够计算这个地址在Run跟踪日志中出现的次数,虽然会导致执行缓慢但是可以得到代码执行的统计。比如说,某命令让您在每个已识别的过程入口处进行Run跟踪,那么统计[profile]就会给您每个过程被调用的次数。在到达某条指令、某个地址范围或指令计数器达到某一数值时Run跟踪可以自动地暂停[pause]。
在多线程程序里OllyDbg可以自动管理线程[threads],如果您单步调试或跟踪程序,它会自动恢复当前线程而挂起其它线程。如果您运行程序,OllyDbg 会恢复先前的线程状态。
您可以为内存块建立快照(叫做备份)。OllyDbg会高亮显示所有的改动。您可以把备份保存到文件或从文件中读取出来,从而发现两次运行的不同之处。您可以查看备份,搜索下一处改动,恢复全部或选定的改动。补丁管理器[Patch manager]记录了上次应用到程序中的所有补丁,在下次调试时可以再次应用它们。
您可以很容易地把您的补丁加在可执行文件上。OllyDbg 会自动进行修正。
您不能在带有 Win32 的16位 Windows 下使用 OllyDbg。这种32位扩展操作系统无法实现某些必需的调试功能。
您既不能调试 DOS 程序也不能调试16位 NE(New Executable)格式文件,我也没有打算在未来的版本中支持这些。安息吧,古老而美好的命令提示符!
三,反汇编器[Disassembler]
反汇编器识别所有的标准80x86、保护、FPU、MMX和3DNow!指令集(包括Athlon扩展的MMX指令集)。但它不识别ISSI命令,尽管计划要在下个版本中支持这种命令。某些过时或者未公开的命令,像LOADALL,也不支持。
反汇编器可以正确解码16位地址。但它假设所有的段都是32位的(段属性使用32位)。这对于PE[Portable Executable]格式文件总是真的。OllyDbg不支持16位的NE
[New Executables]格式。
如果您熟悉MASM或者TASM,那么反汇编的代码对于您没有任何问题。但是,一些特例也是存在的。以下命令的解码与Intel的标准不同:
AAD (ASCII Adjust AX Before Division) -
该命令的解码后的一般形式为:AAD imm8
AAM (ASCII Adjust AX After Multiply) -
该命令(非十进制数)的一般解码形式为:AAM imm8
SLDT (Store Local Descriptor Table register) -
操作数总被解码为16位。这个命令的32位形式会在目的操作数的低16位中存储段选择器,并保留高16位不变。
SALC (Sign-extend Carry bit to AL, undocumented) -
OllyDbg 支持这个未公开指令。
PINSRW (Insert Word From Integer Register, Athlon extension to MMX) -
在AMD的官方文档中,这个命令的内存形式使用了16位内存操作数;然而寄存器形式需要32位寄存器,但只使用了低16位。为了方便处理,反汇编器解码寄存器为16
位形式。而汇编器两种形式都支持。
CVTPS2PI and CVTTPS2PI (Convert Packed Single-Precision Floating to Packed Doubleword, Convert with Truncation Packed Single-Precision Floating to Packed Doubleword) -
在这些命令中,第一个操作数是MMX寄存器,第二个或者是128位XMM寄存器或者是64位内存区域。为了方便处理,内存操作数也被解码为128位。
有些指令的助记符要依赖操作数的大小:
不分大小的形式 明确的16位形式 明确的32位形式
PUSHA PUSHAW PUSHAD
POPA POPAW POPAD
LOOP LOOPW LOOPD
LOOPE LOOPWE LOOPDE
LOOPNE LOOPWNE LOOPDNE
PUSHF PUSHFW PUSHFD
POPF POPFW POPFD
IRET IRETW IRETD
您可以改变解码大小敏感助记符[decoding of size-sensitive mnemonics].。根据选项,反汇编器从三种可能中选择之一进行解码。这个选项也会影响汇编器的默认处理方式。
解码MMX和3DNow!指令总是开启的,尽管您的处理器并不支持这些指令。四,分析器[Analysis]
OllyDbg 整合了一个快速而强大的代码分析器。您可以从快捷菜单,或者在CPU窗口的反汇编面板中按 Ctrl+A ,或者在可执行模块中选择“分析全部模块[Analyze all modules]”,来使用它。
分析器有很高的启发性。它能区分代码和数据,标记入口和跳转目的地址,识别转换表[switch tables],ASCII 和 UNICODE 串,定位函数过程,循环,高阶转换[
high-level switches]并且能解码标准API函数的参数(示例[example])。OllyDbg 的其他部分也广泛的使用了分析后的数据。
这是如何实现的?我将为您揭开这一神秘面纱。第一遍,OllyDbg反汇编代码段中所有可能的地址,并计算调用的每个目的地址的个数。当然,很多调用是假的,但不可能两个错误的调用都指向了相同的命令,当然如果有三个的话,就更不可能了。因此如果有三个或者更多的调用指向了相同的地址,我可以肯定的说这个地址是某个频繁使用的子程序的入口。从定位的入口出发,我继续跟踪所有的跳转和函数调用,等等。按这种方法,我可能准确定位99.9% 的命令。但是,某些字节并不在这个链条上。我再用20多种高效的启发方法(最简单的方法,比如“直接访问前64K内存是不允许的,像在MOV [0],EAX中”)来探测他们
有时,分析器在您感兴趣的地方分析错误。有两种解决方法:或者从选中的部分移除分析(快捷键退格键),这样 OllyDbg 将使用默认的解码(反汇编)方式;或者设置
解码提示[decoding hints]并重新分析。注意:在某些情况下,当分析器认为您的提示是不合适的,或者有冲突,则可能忽略您的设置。
探测程序的函数过程也很简单。在分析器眼中看来,程序只是一个连绵不断的代码,从一个入口开始,可能达到(至少从理论上)所有的命令(除了NOP以及类似的用于填充间隙的命令)。您可能指定三个识别级别。严格的函数过程要求有准确的一个入口,并且至少有一个返回。在启发级别下,分析器只要求过程有一个入口。而如果您选择模糊模式,差不多连贯的代码都会被识别为单独的过程。现代编译器进行全局代码优化,有可能把一个过程分成几个部份。在这种情况下,模糊模式非常有用。但是也会误识别的机率也就更高。
同样地,循环是一个封闭的连续的命令序列,并有一个到开始处的跳转作为一个入口,还有若干个出口。循环与高级操作命令 do, while 和 for 相对应。OllyDbg 能够识别任何复杂的嵌套循环。他们会在反汇编栏[Disassembly]中用长而粗括号标记。如果入口不是循环的第一个命令,OllyDbg会用一个小三角进行标记。
为了实现一个转换[switch], 许多编译器,读取转换变量[switch variable]到寄存器中,然后减它,像如下的代码序列:
MOV EDX,
SUB EDX,100
JB DEFAULTCASE
JE CASE100 ; Case 100
DEC EDX
JNE DEFAULTCASE
... ; Case 101
这个序列可能还包含一到两阶的转换表、直接比较、优化和其他元素。如果在比较或跳转的很深处,这就很难知道哪是一个分支[Case]。OllyDbg 会帮助您,它会标记所有的分支,包括默认的,甚至尝试分析每个分支的含义,如'A'、WM_PAINT 或者 EXCEPTION_ACCESS_VIOLATION。如果命令序列没有修改寄存器(也就是仅仅由比较组成),那么这可能不是转换,而很有可能是选择嵌套:
if (i==0) {...}
else if (i==5) {...}
else if (i==10) {...}
如果需要OllyDbg将选择嵌套解码成选择语句,请在分析1[Analysis1]中设置相关选项。
OllyDbg包含多达1900条常用API函数,这些都作为内部预处理资源。这个列表包含了KERNEL32, GDI32, USER32, ADVAPI32, COMDLG32, SHELL32, VERSION, SHLWAPI, COMCTL32, WINSOCK, WS2_32 和 MSVCRT。您可以添加自己的函数描述[add your own descriptions]。如果分析器遇到的调用,使用了已知的函数名(或者跳转到这样的函数),它将在调用之前立即解码PUSH命令。因此,您只需略微一看就能明白函数调用的含义。OllyDbg还包含了大约400多种的标准C函数。如果您有原始的库文件,我推荐您在分析前扫描目标文件。这样OllyDbg将能解码这些C函数的参数。
如果选项“猜测未知函数的参数个数”开启,分析器将会决定这个调用函数过程使用的长度为双字的参数个数。并且标记他们为参数1[Arg1],参数2[ Arg2],等等。注意:无论如何,寄存器参数是无法识别的,所以不会增加参数的数目。分析器使用了一种比较安全的方法。例如,它不能识别的没有参数的函数过程,或者该过程POP
命令直接做返回前的寄存器恢复,而不销毁参数。然而,识别出来的函数参数数目通常非常高,这大大加大了代码的可读性。
分析器能够跟踪整型寄存器的内容。现代优化编译器,特别是奔腾系列,频繁地使用寄存器读取常量和地址,或使用尽量少的使用内存。如果某个常量读取到寄存器中,分析器会注意它,并尝试解码函数和其参数。分析器还能完成简单的算术计算,甚至可以跟踪压栈和出栈。
分析器不能区分不同类的名称[different kinds of names]. 。如果您将某些函数指定为已知的名称,OllyDbg将会解码所有到该地址的调用。这是几个预定义的特殊名称
WinMain, DllEntryPoint and WinProc。您可能使用这些标签标记主程序、DLL的的入口以及窗口过程(注意:OllyDbg不检查用户自定义的标签是否唯一)。另外,假定预定义参数assume predefined arguments是一种更好的方法
不幸的是,没有一般规则能够做到100%的准确分析。在某些情况下,例如当模块包含了P-Code或代码段中包换了大量的数据,分析器可能将一些数据解释成代码。如果统计分析显示代码部分很可能是压缩包或者经过加密了,分析器会发出警告。如果您想使用Hit跟踪[Hit trace],我建议您不要使用模糊分析[fuzzy analysis],因为设置断点的地方可能正是数据部分。
自解压文件[Self-extractable files] 通常有一个自提取器,在“正式”代码段之外。如果您选择自解压选项[SFX option]中的“扩展代码段,包含提取器[Extend code section to include self-extractor]”,OllyDbg将会扩展代码段,形式上允许分析它,并可以使用Hit跟踪[Hit] trace和Run跟踪[Run trace]。
2005-9-6 15:27 乾龙五,Object扫描器[Object scanner]
扫描器将特定的目标文件或者目标库(包括OMF和COFF两种格式),提取出代码段,然后将这些段定位在当前模块的代码节[Code section]中.如果段定位好了,扫描器将从目标文件中的调试信息提取名称(也就是所谓的库标签[library labels])。这极大的增加了代码与数据的可读性.
扫描器并不会对已识别的目标文件进行标签匹配,所以它不能识别非常小或相似的函数(比如:两个函数只是在重定位有区别)。因此要经常检查扫描器发送到登陆窗口的警告列表!六,Implib扫描器 [Implib scanner]
某些DLL的输出符号仅仅是一个序号。许多符号都是井号加数字(比如:MFC42.#1003),这非常不便于理解。幸运的是,软件零售商提供了输入连接库(implibs),它与序号符号名相关。
使用implib扫描器的方法:从主菜单中选择调试[Debug]|选择输入链接库[Select import libraries]。当您加载应用程序时,OllyDbg会读取链接库并从内置表格[
internal tables]中提取符号名。每次遇到序号符号,而对应的链接库已经注册到OllyDbg中时,这个序号符号会被替换。七,如何开始调试[How to start debugging session]
最简单的方法是:运行 OllyDbg,点击菜单上的文件[File]|打开[Open],选择您想调试的程序。如果程序需要命令行参数,您可以在对话框底部的输入栏中,输入参数或者选择以前调试时输入过的一条参数。
OllyDbg 能够调试独立的DLL[stand-alone DLLs]。在这种情况下,OllyDbg 会创建并运行一个小的应用程序来加载链接库并根据您的需要调用输出函数。
如果您想重新启动上一次调试的程序,只要按一下 Ctrl+F2(这是重启程序的快捷键),这样 OllyDbg 会以同样的参数运行这个程序。另一种做法是在菜单中选择文件[File],从历史列表中选择程序。您也可以在 Windows 资源管理器中将可执行文件或 DLL 文件拖拽到 OllyDbg 中。
当然,您可以在 OllyDbg 启动时,运行指定带有运行参数的被调试程序。例如:您可以在桌面创建一个 OllyDbg 的快捷方式,右击并选择“属性”,在“快捷方式”中的“目标”中添加调试的程序的全路径。这样,您每次双击快捷方式时,OllyDbg 将自动运行被调试程序。注意:DLL文件不支持这种方式。
您可以把正在运行的进程挂接到 OllyDbg 中。在菜单中打开 文件[File]|挂接[Attach],从进程列表中选择要挂接的进程。注意:在您关闭 OllyDbg 的同时,这个进程也会被关闭。不要挂接系统进程,否则可能会导致整个操作系统的崩溃。(事实上在大多数情况下,操作系统禁止您挂接敏感进程)。
OllyDbg 可以作为即时[just-in-time]调试器。这需要在系统注册表中注册。在菜单中选择选项[Options]|即时调试[Just-in-time debugging] 并在弹出的对话框中单击按钮“设置OllyDbg为即时调试器”[Make OllyDbg just-in-time debugger]。今后,如果某个应用程序发生了非法操作,系统将提示您是否用 OllyDbg 调试这个程序。操作系统会启动 OllyDbg 并直接停在发生异常的地方。如果您选择了“挂接时不询问”[attaching without confirmation],则在即时调试时OllyDbg不会弹出询问对话框。如果想恢复成以前的即时调试器[Restore old just-in-time debuger],按相应的按钮即可。
另一种方法是把 OllyDbg 添加到与可执行文件关联的快捷菜单中(这个想法是 Jochen Gerster 提出的)。在主菜单中,选择选项[Options]|添加到资源管理器中[Add to Explorer]。以后您可以在所有的文件列表中,右击可执行文件或DLL,在快捷菜单中选择OllyDbg。这个功能会创建四个注册表键值:
HKEY_CLASSES_ROOT\exefile\shell\Open with OllyDbg
HKEY_CLASSES_ROOT\exefile\shell\Open with OllyDbg\command
HKEY_CLASSES_ROOT\dllfile\shell\Open with OllyDbg
HKEY_CLASSES_ROOT\dllfile\shell\Open with OllyDbg\command
OllyDbg能够调试控制台程序(基于文字的)。
OllyDbg不能调试.NET应用程序。.NET程序是由微软的中间语言这种伪指令组成的,或是on-the-fly to native ?6 commands编译的。
注意:如果您运行的是Windows NT、2000 或XP操作系统,您应该拥有管理员权限以
八,CPU 窗口[CPU window]
对于用户来说,CPU窗口在OllyDbg中是最重要的窗口。您调试自己程序的绝大部分操作都要在这个窗口中进行。它包括以下五个面板(这五个面板的大小都是可以调节的):
反汇编[Disassembler]
信息[Information]
数据[Dump]
寄存器[Registers]
栈[Stack]
按TAB键,可以切换到下一个CPU面板中(顺时针方向)。
按Shift+TAB,可以切换到前一个CPU面板(逆时针方向)。九,断点[Breakpoints]
OllyDbg支持数种不同类型的断点:
- 一般断点[Ordinary breakpoint], 将您想中断的命令的第一个字节,用一个特殊命令INT3(调试器陷阱)来替代。您可以在反汇编窗口中选中要设断点的指令行并按下 F2 键就可以设定一个此类型的断点。也可以在快捷菜单中设置。再次按下 F2 键时,断点将被删除。注意,程序将在设断指令被执行之前中断下来。
INT3断点的设置数量是没有限制的。当您关闭被调试程序或者调试器的时候,OllyDbg将自动把这些断点保存到硬盘中,永远不要试图在数据段或者指令的中间设置这种断点,如果您试图在代码段以外设置断点,OllyDbg将会警告。您可以在安全选项[Security options]中永远关闭这个提示,在某些情况下调试器会插入自带的临时INT3
断点。
- 条件断点[Conditional breakpoint] (快捷键 Shift+F2) 是一个带有条件表达式的普通INT3断点。当调试器遇到这类断点时,它将计算表达式的值,如果结果非零或者表达式无效,将暂停被调试程序,当然,由条件为假的断点引起的开销是非常高的(主要归因于操作系统的反应时间)。在Windows NT、奔腾Ⅱ/450处理器环境下
OllyDbg每秒最多处理2500个条件为假的断点。条件断点的一个典型使用情况就是在Windows消息上设置断点(比如 WM_PAINT)。为此,您可以将伪变量 MSG 同适当的参数说明联合使用。如果窗口被激活,参考一下后面的消息断点描述。
- 条件记录断点 [Conditional logging breakpoint] (Shift+F4)是一种条件断点,每当遇到此类断点或者满足条件时,它将记录已知函数表达式或参数的值。例如,您可以在一些窗口过程函数上设置记录断点并列出对该函数的所有调用。或者只对接收到的WM_COMMAND消息标识符设断,或者对创建文件的函数(CreateFile)设断,并且记录以只读方式打开的文件名等,记录断点和条件断点速度相当,并且从记录窗口中浏览上百条消息要比按上百次F9轻松的多,您可以为表达式选择一个预先定义好的解释说明。
您可以设置通过的次数 - 每次符合暂停条件时,计数器就会减一。如果通过计数在减一前,不等于零,OllyDbg就会继续执行。如果一个循环执行100次(十进制),在循环体内设置一个断点,并设置通过次数为99(十进制)。OllyDbg将会在最后一次执行循环体时暂停。
另外,条件记录断点允许您传递一个或多个命令给插件[plugins]。例如,您需要使用命令行插件改变一个寄存器的内容,然后继续执行程序。
- 消息断点[Message breakpoint]和条件记录断点基本相同,除了OllyDbg会自动产生一个条件,这个条件允许在窗口过程的入口处设置某些消息(比如WM_PSINT)断点,您可以在窗口[Windows]中设置它。
- 跟踪断点[Trace breakpoint] 是在每个选中命令上设置的一种特殊的INT3断点。如果您设置了Hit跟踪[hit trace] ,断点会在命令执行后移除,并在该地址处做一个标记。如果您使用的是Run跟踪[run trace] ,OllyDbg会添加跟踪数据记录并且断点仍然是保持激活状态。
- 内存断点[Memory breakpoint] OllyDbg每一时刻只允许有一个内存断点。您可以在反汇编窗口、CPU窗口、数据窗口中选择一部分内存,然后使用快捷菜单设置内存断点。如果有以前的内存断点,将被自动删除。您有两个选择:在内存访问(读,写,执行)时中断,或内存写入时中断。设置此类断点时,OllyDbg将会改变所选部分的内存块的属性。在与80x86兼容的处理器上将会有4096字节的内存被分配并保护起来。即使您仅仅选择了一个字节,OllyDbg 也会将整个内存块都保护起来。这将会引起大量的错误警告,请小心使用此类断点。某些系统函数(特别是在Windows95/98下)在访问受保护的内存时不但不会产生调试事件反而会造成被调试程序的崩溃。
- 硬断点[Hardware breakpoint](仅在Windows ME,NT或2000下可用)在80x86兼容的处理器上,允许您设置4个硬件断点。和内存断点不同,硬件断点并不会降低执行速度,但是最多只能覆盖四个字节。在单步执行或者跟踪代码时,OllyDbg能够使用硬断点代替INT3断点。
- 内存访问一次性断点[Single-shot break on memory access] (仅在Windows NT或2000下可用)。您可以通过内存窗口的快捷菜单(或按F2),对整个内存块设置该类断点。当您想捕捉调用或返回到某个模块时,该类断点就显得特别有用。中断发生以后,断点将被删除。
- 暂停Run跟踪[Run trace pause] (快捷键:Ctrl+T)是在每一步Run跟踪[run trace] 时都要检查的一个条件集.您可以在EIP进入某个范围或超出某个范围时暂停,某个条件为真时暂停,或者命令与指定的模式匹配时暂停,或者当命令可疑的时候暂停。注意,这一选择会极大的(高达20%)降低Run跟踪的速度。
OllyDbg也可以在一些调试事件[debugging events]上暂停程序执行。比如加载或卸载DLL,启动或终止线程,或者程序发出调试字符串的时候。
10,数据窗口[Dump]
数据窗口用于显示内存或文件的内容。您可以从以下预处理格式[predefined formats]中选择一种显示方式:字节[byte]、文本[text]、整数[integer]、浮点数[float
]、地址[address],反汇编[disassembly]、 PE头[PE Header]。
所有的dump窗口支持备份[backup]、搜索和编辑操作。CPU 窗口[CPU window]的Dump面板允许您对可执行代码的数据和可执行文件(.exe,或.dll)的内存映射做如下操作:定义标签[labels]、设置 内存断点[memory breakpoints], 查找参考[references]。数据菜单[Dump menu]只显示与选中部分相关的命令。
如果 备份[backup]可用,则单击第一个列标题栏,会在地址[Address]/备份[Backup] 两种显示模式之间切换。点击其他列标题栏,会改变Dump模式。
像反汇编窗口一样,数据窗口也保存了大量查看内存地址的历史记录。您可以通过“+”和“-”键来访问您过去查看过的数据地址空间。
要翻动一字节的数据,可以按住Ctrl l键并按上/下方向键。
可执行模块窗口[Executable modules window]
可执行模块窗口(快捷键:Alt+E)列出了当前被调试进程加载的所有可执行模块。它也显示了很多有用的信息,比如模块大小、入口地址、模块版本、以及可执行文件路径等。一些信息,如以十进制显示的模块大小、入口地址的符号名、是否为系统模块等,通常是被隐藏的。如果想看,可以增加相应栏的宽度。快捷菜单支持以下操作:
刷新[Actualize] - 重新扫描模块并去除对新加载模块的高亮显示。在大多数情况下,OllyDbg会自动完成该操作。
查看内存[View memory] - 打开内存窗口,并定位到属于该模块镜像的第一个内存块处。
在CPU窗口中查看代码[View code in CPU] (快捷键:回车键) - 在反汇编窗口中显示模块的可执行代码。
跟进到入口[Follow entry] - 在反汇编窗口中跟进到模块的入口处。
在CPU窗口中查看数据[Dump data in CPU] -在CPU窗口的数据面板中显示模块的数据段。块代码段。
显示名称[View names] (快捷键:Ctrl+N) -显示当前模块定义或使用的全部名称[names](包括输出表、引入表、链接库、用户自定义)。
标记为系统DLL[Mark as system DLL],
标记为非系统DLL[Mark as non-system DLL] - 将选中模块标记为系统或非系统属性。如果设置为系统属性,则在Run跟踪[Run trace] 时会直接执行(不进行跟踪)这个模块,从而大大加快跟踪速度。默认情况下,所有驻留在系统目录(通常在Windows 95/98下为c:\windows\system ,在WinNT/2000/XP下为c:\winnt\system32)的模块都认为是系统模块。
立即更新.udd文件[Update .udd file now] -向文件“.udd”写入模块相关的全部数据,udd文件保存了在调试期间设置的断点、标签、注释、监视、分析等信息。当模块卸载时OllyDbg会自动创建.udd文件。
查看可执行文件[View executable file] - 显示可执行文件的全部内容。
查看全部资源[View all resources] - 以列表形式显示模块定义的全部资源,并带有一个简短信息。OllyDbg并不把资源当作单独实体来支持。您可以提取[Dump]并以二进制的形式进行编辑。
查看资源字符串[View resource strings] -以列表形式显示资源字符串及其标识符。
查看Run跟踪的统计[View run trace profile] - 在此模块中计算统计[profile] 。相关信息:Run跟踪[Run trace].
分析全部模块[Analyze all modules] -允许同时分析全部模块。分析将从代码中提取大量的有用信息;代码经过分析后再进行调试,通常会非常快并且可靠。
鼠标双击某一行,将会在反汇编窗口中显示模块的执行代码。十,内存映射窗口[Memory map window]
内存映射窗口显示了被调试程序分配的所有内存块。因为没有标准的方法来完成这项任务,所以OllyDbg可能会把一个大的内存块分成几个部分。然而,在大多数情况下,并非一定要精确处理。如果想查看由应用程序通过调用GlobalAlloc()和LocalAlloc()等申请的内存块列表,请使用堆列表[Heap list]。
如果内存块是可执行模块的一个节,OllyDbg则会报告这个内存块所包含的数据类型:代码、数据、资源等。
Windows95/98是和WindowsNT/2000是有一些区别的。在Windows95/98下,OllyDbg是不能显示被映射文件的名称的。另外,Windows95/98不允许的访存类型为读和写,然而,在WindowsNT/2000下,OllyDbg却有拥有更多功能,包括执行访问,写复制[copy-on-write]以及监视标志位。OllyDbg忽略写复制[copy-on-write]属性。
如果OllyDbg发现程序分配了新内存或者重新分配了已经存在的内存块,它将在内存映射窗口中高亮显示相应的记录,去掉高亮度显示,可以选择快捷菜单中的刷新[
Actualize]项。
您可以按Alt+M来调用内存窗口。
以下是快捷菜单中可以选择的菜单项:
刷新[Actualize] - 更新已分配内存的列表并去除对新内存块的高亮显示。
在反汇编窗口中查看[View in Disassembler] -在反汇编窗口中查看:在反汇编窗口中打开内存块,这一选项仅在某些模块的内存块中包含可执行代码或者自解压器时可用。
在CPU数据窗口中查看[Dump in CPU] - 在CPU的数据窗口中显示内存块的内容。
数据窗口[Dump] - 在单独窗口中显示内存块内容。如果内存块的类型已知,则OllyDbg会自动选择显示格式。
查看全部资源[View all resources] - 如果内存块包含资源数据,则列出所有资源及相关数据。OllyDbg并不把资源当作单独实体来支持。您可以显示其数据并以二进制的形式进行编辑。
查看资源字符串[View resource strings] - 如果内存块包含资源数据,则列出全部资源字符串及其标识符。
搜索[Search] - 允许搜索所有的内存块,从选择处开始,搜索匹配的二进制串。如果找到,则OllyDbg将显示该内存块。内存映像窗口和数据窗口共享同一种搜索模式,所以您可以在弹出的数据窗口中立即继续搜索该二进制串出现的下一位置。按Esc键可以关闭数据窗口。
搜索下一个[Search next](快捷键:Ctrl+L) - 继续上次搜索。
设置访问中断[Set break-on-access] (快捷键:F2,仅在WindowsNT/2000下可用) - 保护整个内存块。当中断发生后OllyDbg暂停被调试程序并清除断点。这类断点在您想捕捉调用或返回到某个模块的时候特别有用。
清除访问中断[Remove break-on-access] (快捷键:F2) - 从内存块中清除访问中断保护。
设置内存访问断点[Set memory breakpoint on access] - 在整个内存块上设置断点,每当该内存块被访问时程序都将中断。OllyDbg只支持一个内存访问断点。在
Windows95/98下,当系统程序访问含有内存断点的内存块时,可能会导致所被调试程序崩溃,因此,不到万不得已,请不要设置这种断点。
设置内存写入断点[Set memory breakpoint on write] - 在整个内存块上设置断点,每当该内存块被写入数据时程序都将中断。在Windows95/98下,当系统程序访问含有内存断点的内存块时,可能会导致所被调试程序崩溃,因此,不到万不得已,请不要设置这种断点。
清除内存断点[Remove memory breakpoint] - 清除内存断点。
清除自解压内存断点[Remove SFX memory breakpoint] - 停止搜索自解压程序[self-extractable (SFX) program]的真实入口。这个搜索使用了特殊类型的内存断点。
访问设置[Set access] -设置整个内存块的保护属性,可选择的有:
禁止访问[No access]
只读[Read only]
读/写[Read/write]
执行[Execute]
执行/读[Execute/read]
完全访问[Full access]
复制到剪切板[Copy to clipboard]
整行[Whole line] -以多行文本(包括解释)的方式把所选记录复制到剪切板,如果复制时想排除某些列,可将该列的宽度置为最小(该栏剩余的边框将变灰)。
整个表格[Whole table] -以多行文本的方式将整个内存映像信息复制到剪切板,该文本的第一行为窗口标题("内存映射[Memory map]"), 第二行为列标题栏,后面几行的内容为内存数据记录。复制将保持列的宽度。如果复制时想排除某些列,可将该列的宽度置为最小(该栏剩余的边框将变灰)。十一,监视与监察器[Watches and inspectors]
监视[Watch] 窗口包含若干个表达式[expressions]。它在第二列里显示这些表达式的值。OllyDbg 会把这些表达式保存到主模块的.UDD文件中,因此它们在下一次调试时同样有效。
监察器[inspector]是显示若干变量、1/2维数组或是选定项目结构数组[selected items of array of structures]的独立窗口。它的表达式与监视窗口中的基本相同,只是多包含了两个参数:%A和%B。您可以指定这两个参数的界限,OllyDbg 将会用所有可能的组合代替表达式中的%A和%B。从0开始一直到界限(不包含界限),并在表格中显示结果。参数%B(列数)的界限不能超过16。
例如,如果您指定了表达式%A+%B,并且限定%A和%B的上限为3,您将获得如下的表格:
十三,线程[Threads]
OllyDbg 以简单而有效的线程管理为特色。如果您单步调试、跟踪、执行到返回或者执行到所选,则线程管理器将停止除当前线程以外的所有线程。即使当前线程被挂起,它也会将其恢复。在这种情况下,如果您手动挂起或者恢复线程,动作将被延期。如果您运行被调试的应用程序,OllyDbg将恢复最初的线程状态。(从调试器的角度来看,Hit跟踪[hit trace]和自由运行是等效的)。
依据这种方案,线程窗口可能会有如下五种线程状态:
激活[Active] - 线程运行中,或被调试信息暂停t
挂起[Suspended] - 线程被挂起
跟踪[Traced] - 线程被挂起,但OllyDbg正在单步跟踪此线程
暂停[Paused] - 线程是活动的,但OllyDbg临时将其挂起,并在跟踪其它的线程
结束[Finished] - 线程结束
.
线程窗口同时也显示了最后的线程错误(GetlastError函数的返回值)并计算该线程以用户模式和系统模式(仅NT/2000/XP)运行的时间。线程窗口还会高亮主线程的标识符。
以下在快捷菜单中可用:
刷新[Actualize] - 标记所有线程为旧的。
挂起[Suspend] - 挂起线程。
恢复[Resume] - 恢复先前挂起的线程。
设置优先级[Set priority] - 调整进程中线程的优先级。以下选项可用:
空闲[Idle] - 进程中线程的最低优先级
最低[Lowest]
低[Low]
标准[Normal]
高[High]
最高[Highest]
时间临界[Time critical] - 最高优先级
在CPU窗口打开[Open in CPU](双击)- 在CPU窗口中显示所选线程的当前状态。十四,复制到剪切板[Copy to clipboard]
整行[Whole line] -全部行--以多行文本的形式并带注释将所选记录复制到剪切板。如果在复制时想排除某个栏目,可以将该栏的宽度置为最小(栏目的残留部分将变灰)。
整个表格[Whole table] - 整个表格--以多行文本的形式将整个内存映象复制到剪切板,该文本的第一行包含窗口标题(“内存映射[Memory map]”),第二行是栏目标题,所有后继行是内存数据记录。复制将保持栏目的宽度。如果在复制时想排除某些栏目,可以将该栏的宽度置为最小(栏目的残留部分将变灰)。十五,调用栈[Call stack]
调用栈窗口(快捷键:Alt+K)根据选定线程的栈,尝试反向跟踪函数调用顺序并将其显示出来,同时包含被调用函数的已知的或隐含的参数。如果调用函数创建了标准的堆栈框架(PUSH EBP; MOV EBP,ESP),则这个任务非常容易完成。现代的优化编译器并不会为栈框架而操心,所以OllyDbg另辟蹊径,采用了一个变通的办法。例如,跟踪代码到下一个返回处,并计算其中全部的入栈、出栈,及 ESP 的修改。如果不成功,则尝试另外一种办法,这个办法风险更大,速度也更慢:移动栈,搜索所有可能的返回地址,并检查这个地址是否被先前的已分析的命令调用。如果还不行,则会采用启发式搜索。栈移动[Stack Walk]可能会非常慢。OllyDbg 仅在调用栈窗口打开时才会使用。
调用栈窗口包含5个栏目:地址[Address]、栈[Stack]、过程[Procedure],调用来自[Called from],框架[Frame]。地址[Adress]栏包含栈地址,栈[Stack]
栏显示了相应的返回地址或参数值。
函数[Procedure](或 函数/参数[Procedure / arguments])显示了被调用函数的地址,在某些情况下,OllyDbg并不能保证该地址是正确的并会添加如下标记之一:
? 找到的入口点不可靠
可能[Maybe] OllyDbg无法找到精确的入口点,报告的地址是用启发式算法猜测的。
包含[Includes] OllyDbg无法找到入口点,仅知道该函数包含显示的地址
通过按例标题栏上的按钮或从菜单中选择“隐藏/显示参数[Hide/Show arguments]”,可以在显示或隐藏函数的参数之间切换。
调用来自[Called from]用于显示调用该函数的命令地址。最后一栏是框架[Frame]这一栏默认是隐藏的,如果框架指针的值(寄存器EBP)已知的话,则该栏用于显示这个值。
当调用函数经过分析[analyzed].后,栈移动会更可靠并且迅速。十六,调用树[Call tree]
调用树(快捷键:在反汇编窗口中Ctrl+K)利用分析[Analysis]的结果来找出指定函数过程直接或间接调用的函数列表,同时列出指定函数过程被调用的地址。为了避免由此可能造成的副作用。调用树会判断选定函数是否明确地是递归的。“明确地”意味着它不会跟踪目标未知的调用,比如CALL EAX。如果函数过程中有未知调用,调用树将会添加标记“未知目标”。
某些函数调用将会添加如下注释之一:
叶子[Leaf] 不调用其他函数
纯函数[Pure] 不调用函数,不会产生副作用
单返回[RETN] 只有一个RETN 命令
系统[Sys] 系统动态链接库中的函数。系统动态链接库定义为保存在系统目录下的动态链接库。
如果想在调用树上移动,可以双击“被调用[Called from]”或“调用/直接调用[Calls/Calls directly]”两栏中的地址。调用树窗口保存了移动记录(快捷键“-”和“+”)。
如果被调试的程序包含几个模块,推荐您分析所有模块。Call tree 不会试图处理系统函数。十七,选项[Options]
外观选项[Appearance options]
常规[General]
默认[Defaults]
对话框[Dialogs]
目录[Directories]
字体[Fonts]
颜色[Colours]
代码高亮[Code highlighting]
调试选项[Debugging options] (Alt+O)
安全[Security]
调试[Debug]
事件[Events]
异常[Exceptions]
跟踪[Trace]
自解压[SFX]
字符串[Strings]
地址[Addresses]
命令[Commands]
反汇编[Disasm]
CPU
寄存器[Registers]
栈[Stack]
分析1[Analysis 1]
分析2[Analysis 2]
分析3[Analysis 3]
即时调试[Just-in-time debugging]
添加到资源管理器[Add to Explorer]十八,搜索[Search]
OllyDbg 允许您使用以下的搜索方式:
符号名(标签)[Symbolic name (label)]
二进制串[binary string]
常量[constant]
命令[command]
命令序列[sequence of commands]
模块间调用[intermodular calls]
修改过的命令或数据[modified command or data]
自定义标签[user-defined label]
自定义注释[user-defined comment
文本字符串[text string]
Run跟踪的记录[record in run trace]
参考命令[referencing commands]
十九,自解压文件[Self-extracting (SFX) files]
自解压文件由提取程序和压缩的原程序两部分组成。当遇到自解压文件(SFX)文件时,我们通常希望跳过解压部分,而直接跳到原始程序的入口(真正的入口)。
OllyDbg 包含了几个便于完成这一任务的功能。
通常提取程序的加载地址都在执行代码之外。在这种情况下,OllyDbg 将这类文件均视作为自解压文件(SFX)。
当自解压选项[SFX options]要求跟踪真正入口时,OllyDbg 在整个代码节[Code section]设置内存断点,最初这里是空的,或者只包含压缩数据。当程序试图执行某个在这个保护区域的命令,而这些命令不是 RET 和 JMP 时,OllyDbg 会报告真正的入口。这就是提取工作的原理。
上面的方法非常慢。有另外一种比较快的方法。每次读取数据发生异常时,OllyDbg 使这个4K内存区域变为可读,而使原先可读的区域变为无效。而每次发生写数据异常时,
OllyDbg 使这个区域变为可写,而使原先可写的区域变为无效。当程序执行在保留的保护区域中的指令时,OllyDbg 报告真正的入口。但是,当真正的入口点在可读或可写区域内部时,报告的地址就可能有误。
您可以纠正入口位置,选择新的入口,从反汇编窗口的快捷菜单中选择“断点[Breakpoint]|设置真正的自解压入口[Set real SFX entry here]”。如果相应的SFX选项是开启的,OllyDbg下次可以迅速而可靠的跳过自提取程序。
注意:OllyDbg 在跟踪采取了保护或者反调试技术的解压程序时通常会失败。 二十,单步执行与自动执行[Step-by-step execution and animation]
您可以通过按 F7(单步步入)或 F8(单步步过),对程序进行单步调试。这两个单步执行操作的主要区别在于:如果当前的命令是一个子函数,按F7,将会进入子函数,并停在子函数的第一条命令上;而按 F8,将会一次运行完这个子函数。如果您单步步过的子函数中含有断点或其他调试事件,执行将会被暂停,但 OllyDbg 会在子函数的后一条命令上,自动下一个断点,而这个断点您迟早会碰到。
如果被调试程序停在异常上,您可以跳过它,并转到被调试程序建立的句柄处。只需简单的 Shift 键和任何一个单步命令。
如果需要连续按F7、F8键上百次,您可以使用自动执行(Ctrl+F7或者Ctrl+F8)功能。在这种情况下,OllyDbg 将自动重复F7或者F8操作,并且实时更新所有的窗口。这个过程会在下面情况停止:
- 按 Esc 键或发出任何单步命令
- OllyDbg 遇到断点
- 被调试程序发生异常
使用“+”和“-”按键,可以回朔以前的执行历史[execution history].
注意:当执行停止时 OllyDbg 将会刷新大部分窗口。如果动态执行过程非常慢,可以尝试关掉或最小化没有用的窗口。
另外,更快捷的找到以前执行指令的办法是Run跟踪[run trace]。它将创建一个执行协议并告知您指定指令的执行时间和次数二一,Hit跟踪[Hit trace]
编辑摘要
目录
1 主要介绍
2 相关条目
OLLYDBG - 主要介绍
软件
OLLYDBG
名称,一个新的动态追踪工具,将IDA与SoftICE结合起来的思想,Ring 3级调试器,非常容易上手,己代替SoftICE成为当今最为流行的调试解密工具了.同时还支持插件扩展功能,是目前最强大的调试工具.
OLLYDBG - 相关条目
追踪 调试器 流行 工具 插件
一,什么是 OllyDbg?
OllyDbg 是一种具有可视化界面的 32 位汇编-分析调试器。它的特别之处在于可以在没有源代码时解决问题,并且可以处理其它编译器无法解决的难题。
Version 1.10 是最终的发布版本。 这个工程已经停止,我不再继续支持这个软件了。但不用担心:全新打造的 OllyDbg 2.00 不久就会面世!
运行环境: OllyDbg 可以以在任何采用奔腾处理器的 Windows 95、98、ME、NT 或是 XP(未经完全测试)操作系统中工作,但我们强烈建议您采用300-MHz以上的奔腾处理器以达到最佳效果。还有,OllyDbg 是极占内存的,因此如果您需要使用诸如追踪调试[Trace]之类的扩展功能话,建议您最好使用128MB以上的内存。
支持的处理器: OllyDbg 支持所有 80x86、奔腾、MMX、3DNOW!、Athlon 扩展指令集、SSE指令集以及相关的数据格式,但是不支持SSE2指令集。
配置: 有多达百余个选项用来设置 OllyDbg 的外观和运行。
数据格式: OllyDbg 的数据窗口能够显示的所有数据格式:HEX、ASCII、UNICODE、 16/32位有/无符号/HEX整数、32/64/80位浮点数、地址、反汇编(MASM、IDEAL或是HLA)、PE文件头或线程数据块。
帮助: 此文件中包含了关于理解和使用 OllyDbg 的必要的信息。如果您还有 Windows API 帮助文件的话(由于版权的问题 win32.hlp 没有包括在内),您可以将它挂在 OllyDbg 中,这样就可以快速获得系统函数的相关帮助。
启动: 您可以采用命令行的形式指定可执行文件、也可以从菜单中选择,或直接拖放到OllyDbg中,或者重新启动上一个被调试程序,或是挂接[Attach]一个正在运行的程序。OllyDbg支持即时调试。OllyDbg根本不需要安装,可直接在软盘中运行!
调试DLLs: 您可以利用OllyDbg调试标准动态链接库 (DLLs)。OllyDbg 会自动运行一个可执行程序。这个程序会加载链接库,并允许您调用链接库的输出函数。
源码级调试: OllyDbg 可以识别所有 Borland 和 Microsoft 格式的调试信息。这些信息包括源代码、函数名、标签、全局变量、静态变量。有限度的支持动态(栈)变量和结构。
代码高亮: OllyDbg 的反汇编器可以高亮不同类型的指令(如:跳转、条件跳转、入栈、出栈、调用、返回、特殊的或是无效的指令)和不同的操作数(常规[general]、
FPU/SSE、段/系统寄存器、在栈或内存中的操作数,常量)。您可以定制个性化高亮方案。
线程: OllyDbg 可以调试多线程程序。因此您可以在多个线程之间转换,挂起、恢复、终止线程或是改变线程优先级。并且线程窗口将会显示每个线程的错误(就像调用 GETLASTERROR 返回一样)。
分析:OllyDbg 的最大特点之一就是分析。它会分析函数过程、循环语句、选择语句、表[tables]、常量、代码中的字符串、欺骗性指令[tricky constructs]、API调用、函数中参数的数目,import表等等。. 这些分析增加了二进制代码的可读性,减少了出错的可能性,使得我们的调试工作更加容易。
Object扫描。 OllyDbg 可以扫描Object文件/库(包括 OMF 和 COFF 格式),解压代码段[code segments]并且对其位置进行定向。
Implib扫描。 由于一些DLL文件的输出函数使用的索引号,对于人来说,这些索引号没有实际含义。如果您有与DLL相应的输入库[import library],OllyDbg 就可以将序号转换成符号名称。
完全支持Unicode: 几乎所有支持 ASCII 的操作同时也支持 UNICODE,反之亦然。
名称: OllyDbg 可以根据 Borland 和 Microsoft 格式的调试信息,显示输入/输出符号及名称。Object 扫描器可以识别库函数。其中的名称和注释您可任意添加。如果DLL中的某些函数是通过索引号输出的,则您可通过挂接输入库[import library]来恢复原来的函数名称。不仅如此,OllyDbg还能识别大量的常量符号名(如:窗口消息、错误代码、位域[bit fields]…)并能够解码为已知的函数调用。
已知函数:OllyDbg 可以识别 2300 多个 C 和 Windows API 中的常用函数及其使用的参数。您可以添加描述信息、预定义解码。您还可以在已知函数设定 Log 断点并可以对参数进行记录。
函数调用: OllyDbg 可以在没有调试信息或函数过程使用非标准的开始部分[prolog]和结尾部分[epilog]的情况下,对递归调用进行回溯。
译者注:
004010D0 push ebp \
004010D1 mov ebp,esp |
004010D3 sub esp,10h |prolog
004010D6 push ebx |
004010D7 push esi |
004010D8 push edi /
……
004010C5 pop edi \
004010C6 pop esi |
004010C7 pop ebx |epilog
004010C8 mov esp,ebp |
004010CA pop ebp |
004010CB ret /
栈:在栈窗口中,OllyDbg 能智能识别返回地址和栈框架[Stack Frames]。并会留下一些先前的调用。如果程序停在已知函数上,堆栈窗口将会对其参数进行分析解码。
译者注:栈框架[Stack Frames]是指一个内存区域,用于存放函数参数和局部变量。
SEH 链: 跟踪栈并显示结构化异常句柄链。全部链会显示在一个单独的窗口中。
搜索:方法真是太多了!可精确、模糊搜索命令或命令序列,搜索常数,搜索二进制、文本字符串,搜索全部命令地址,搜索全部常量或地址域[address range],搜索所有能跳到选定地址的跳转,搜索所有调用和被调用的函数,搜索所有参考字符串,在不同模块中搜索所有调用、搜索函数名称,在全部已分配的内存中搜索二进制序列。如果搜索到多个结果,您可以对其进行快速操作。
窗口:OllyDbg 能够列出关于调试程序中的各种窗口,并且可以在窗口、类甚至选定的消息上设置断点。
资源:如果 Windows API 函数使用了参考资源串,OllyDbg 可以显示它。其支持显示的类型仅限于附带资源[attached resources]的列表、数据显示及二进制编辑、。
断点: OllyDbg 支持各种断点:一般断点、条件断点、记录断点(比如记录函数参数到记录窗口)、内存读写断点、硬件断点(只适用于ME/NT/2000)等。在Hit跟踪情况下,可以在模块的每条命令上都设置INT3断点。在使用500-MHZ处理器的 Windows NT 中,OllyDbg 每秒可以处理高达 5000 个中断。
监视与监察器:每个监视都是一个表达式并能实时显示表达式的值。您可以使用寄存器、常数、地址表达式、布尔值以及任何复杂代数运算,您还可以比较ASCII和UNICODE
字符串。监察器[inspectors]是一种包含了两个的索引序列的监视[Watches],它以二维表的形式呈现,可以对数组和结构进行解码分析。
Heap walk.:在基于Win95的系统中,OllyDbg 可以列出所有的已分配的堆。
句柄:在基于NT的系统中,OllyDbg 可列出被调试程序的所有系统句柄。
执行:.您可以单步执行、步入子程序或者步过子程序。您也可以执行程序直到函数返回时、执行到指定地址处,还可以自动执行。当程序运行时,您仍然可以操纵程序并能够查看内存、设置断点甚至修改代码。您也可以任意的暂停或重启被调试的程序。
Hit跟踪:.Hit跟踪可以显示出目前已执行的指令或函数过程,帮助您检验代码的各个分支。Hit跟踪会在指定指令到达之前设置断点,而在这个指令执行后,会把这个断点清除掉。
译者注:Hit在英文中是“击中”的意思,指令如果运行了就表示这个指令被“击中”了,没有执行的指令就是“未击中”,这样我们就很容易看出被调试程序哪些部分运行了,而哪些没有运行。
Run跟踪: Run跟踪可以单步执行程序,它会在一个很大的循环缓冲区中模拟运行程序。这个模拟器包含了除了SSE指令集以外的所以寄存器、标志、线程错误、消息、已经函数的参数。您可以保存命令,这样可以非常方便地调试自修改代码(译者注:比如加壳程序)。您可以设置条件中断,条件包括地址范围、表达式、命令。您可以将Run
跟踪信息保存到一个文件中,这样就可以对比两次运行的差别。Run跟踪可以回溯分析已执行过的上百万条命令的各种细节。
统计: 统计[Profiler]可以在跟踪时计算某些指令出现的次数。因此您就能了解代码的哪一部分被频繁执行。
补丁: 内置汇编器能够自动找到修改过的代码段。二进制编辑器则会以ASCII、UNICODE或者十六进制的形式同步显示修改后的数据。修改后的数据同其它数据一样,能够进行复制-粘贴操作。原来的数据会自动备份,以便数据恢复时使用。您可以把修改的部分直接复制到执行文件中,OllyDbg会自动修正。OllyDbg还会记录以前调试过程中使用的所有补丁。您可以通过空格键实现补丁的激活或者禁止。
自解压文件: 当调试自解压文件时,您往往希望跳过解压部分,直接停在程序的原始入口点。OllyDbg的自解压跟踪将会使您实现这一目的。如果是加保护的自解压段,自解压跟踪往往会失败。而一旦OllyDbg找到了入口点,它将会跳过解压部分,并准确的到达入口点。
插件:您可以把自己的插件添加到 OllyDbg 中,以增加新的功能。OllyDbg 的插件能够访问几乎所有重要的数据的结构、能够在 OllyDbg 的窗口中添加菜单和快捷键,能够使用100个以上的插件API函数。插件API函数有详细的说明文档。默认安装已经包含了两个插件:命令行插件和书签插件。
UDD:OllyDbg 把所有程序或模块相关的信息保存至单独的文件中,并在模块重新加载时继续使用。这些信息包括了标签、注释、断点、监视、分析数据、条件等等
更多:这里介绍的功能,仅仅是 OllyDbg 的部分功能。因为其具有如此丰富的功能,以至于 OllyDbg 能成为非常方便的调试器!
2005-9-6 15:25 乾龙二,一般原理[General principles]
我希望您能对80x86系列处理器的内部结构有所了解,同时具有一定的编写汇编程序的能力。对于Microsoft Windows方面的知识,您也要熟悉。
OllyDbg是运行在Windows 95、Windows 98、Windows ME、Windows NT 和 Windows 2000系统下的一个单进程、多线程的分析代码级调试工具。它可以调试PE格式的执行文件及动态链接库,并可以对其打补丁。“代码级”意味着您可以直接与比特、字节或处理器指令打交道。OllyDbg 仅使用已公开的 Win32 API 函数,因此它可以在所有 Windows 操作系统及后继版本中使用。但是由于我没有对 XP 系统进行彻底测试,因此不能保证 OllyDbg 功能的充分发挥。注意:OllyDbg 不支持对 .NET 程序的调试。
OllyDbg不是面向编译器的。它没有特别的规则规定必须是哪一个编译器产生的代码。因此,OllyDbg可以非常好的处理通过编译器生成的代码,或是直接用汇编写入的代码。
OllyDbg可以并行调试程序。您无须暂停执行程序,就可以浏览代码和数据,设置断点、停止或恢复线程,甚至直接修改内存。(这可以视为一种软件调试的模式,与之相对的硬件模式则是当进程在运行时调试器被阻滞,反之亦然)。假使所需的操作比较复杂,OllyDbg会让进程终止一小段时间,但是这种暂停对于用户来说是透明的。
有时进程会发生非法操作。您可以把OllyDbg设置成即时[just-in-time]调试器,它会挂接出错程序,并停在程序产生异常的地方。
通过OllyDbg,您可以调试单独的DLL[standalone DLLs]文件。操作系统不能直接运行 DLL 文件,因此 OllyDbg 将一个可以加载 DLL 的小程序压缩到资源里,这个程序允许您调用最多10个参数的输出函数。
OllyDbg是完全面向模块[module-oriented]的。模块[Module]包括可执行文件(扩展名通常为.EXE)和在启动时加载或需要时动态加载的动态链接库(扩展名通常为.DLL
)。在调试期间,您可以设置断点[breakpoints]、定义新的标签[labels]、注释[comment]汇编指令,当某个模块从内存中卸载[unload]时,调试器会把这些信息保存在文件中,文件名就是模块的名称,扩展名为.UDD(表示 用户自定义文件[User-Defined Data])当OllyDbg下一次加载该模块时,它会自动恢复所有的调试信息,而不管是哪一个程序使用这个模块。假设您正在调试程序Myprog1,这个程序使用了Mydll。您在 Mydll 中设置了一些断点,然后您开始调试Myprog2,这个程序同样使用了Mydll。这时您会发现,所有 Mydll 中的断点依然存在,即使 Mydll 加载到不同的位置!
一些调试器把被调试进程的内存当作一个单一的(并且大部分是空的)大小为2 ^32字节的区域。OllyDbg采用了与之不同的技术:在这里,内存由许多独立的块组成,任何对内存内容的操作都被限制在各自的块内。在大多数情况下,这种方式工作得很好并且方便了调试。但是,如果模块包含好几个可执行段[executable sections],您将不能一次看到全部代码,然而这种情况是非常少见的。
OllyDbg 是一个很占用内存的程序[memory-hungry application]。它在启动时就需要 3 MB,并且当您第一次装载被调试的程序时还需要一到两兆的内存。每一次的分析、备份、跟踪或者文件数据显示都需要占用一定的内存。因此当您调试一个很大的项目,发现程序管理器显示有 40 或 60 兆内存被占用时,请不要惊慌。
为了有效地调试一些不带源码的程序,您必须首先理解它是如何工作的。OllyDbg 包含的大量特性可以使这种理解变得非常容易。
首先,OllyDbg包含一个内置的代码分析器。分析器遍历整个代码,分出指令和数据,识别出不同的数据类型和过程,分析出标准API函数(最常用的大约有1900个)的参数并且试着猜出未知函数的参数数目。您也可以加入自己的函数说明[your own function descriptions]。它标记出程序入口点和跳转目的地,识别出跳转表[table-driven switches]和指向字符串的指针,加入一些注释,甚至标示出跳转的方向等等。在分析结果的基础上,调用树[call tree]显示哪些函数被指定过程调用(直接或间接)并且识别出递归调用、系统调用和叶子过程[leaf procedures]。如果需要的话,您可以设置解码提示[decoding hints]来帮助分析器解析那些不明确的代码或数据。
OllyDbg还包含Object扫描器[Object Scanner]。如果您有库文件[libraries]或目标文件[object files],扫描器会在被调试的程序中定位这些库函数。在全部函数调用中,对标准函数的调用占很重要的一部分(据我估计可达70%)。如果您知道正要被调用的函数的功能,您就不必把注意力集中在这个函数上,可以简单地单步步过[
step over]这个call。分析器知道400多个标准C函数,比如fopen和memcpy。然而我必须承认当前版本的OllyDbg不能定位很短的函数(比一个return命令多不了多少的)或相似的函数(只在重定位上有不同)。
Object扫描器[Object scanner]也能够识别输入库[import libraries]。如果某个DLL是按序号输出的,您不会看到函数名,只会发现一堆无意义的神秘数字。这种DLL的开发者通常会提供一个输入库来实现函数符号名与序号间的对应。让OllyDbg使用这个输入库,它就会恢复原始的函数符号名。
面向对象的语言(如C++),使用了一种叫做名称修饰[name mangling]的技术,把函数类型和参数都加入函数名中。OllyDbg 可以解码[demangle]这种函数名,使程序更易读。
译者注:C++的名称修饰是编译器将函数的名称转变成为一个唯一的字符串的过程,这个字符串会对函数的类、其命名空间、其参数表,以及其他等等进行编码。C++的名称修饰适用于静态成员函数,也适用于非静态成员函数。静态函数的名称修饰的一个好处之一,是能够在不同的类里使用同一个名称来声明两个或者更多的静态成员函数----而不会发生名称上的冲突。
OllyDbg完全支持 UNICODE,几乎所有对 ASCII 字符串的操作都可以同样应用于 UNICODE。
汇编指令都是很相似的。您经常会搞不清自己是不是已经跟踪过某一段代码。在 OllyDbg 中您可以加入自己的标签[labels]和注释[comments]。这些极大地方便了调试。注意一旦您注释了某个DLL,以后每次加载这个DLL时,注释和标签都有效----尽管您在调试不同的程序。
OllyDbg可以跟踪标准的栈帧[stack frames](由PUSH EBP; MOV EBP,ESP所创建的)。现代编译器有禁止产生标准栈框架的选项,在这种情况下分配栈[stack walk
]是不可能的。当程序运行到已知的函数时,栈窗口[stack window]解析它的参数,调用栈[Call stack]窗口显示到达当前位置所调用函数的序列。
现代的面向对象应用程序广泛地使用了一种叫做结构化异常处理[Structured Exception Handling,SHE]的技术。SHE窗口[SEH window] 可以显示异常处理链。
多种不同的搜索[search]选项可以让您找到二进制代码或数据、命令或命令序列、常量或字符串、符号名或在 Run跟踪中的一条记录。
对于任何地址或常量,OllyDbg 可以找出参考[referencing]到该地址或常量的全部命令的列表。然后您可以在这个列表里找出对您来说是重要的参考。举例来说,某个函数可能被直接调用,或者经过编译器优化后把地址放入寄存器间接调用,或者把地址压入堆栈作为一个参数----没问题,OllyDbg 会找出所有这样的地方。它甚至能找到并列出所有和某个指定的位置有关的跳转。(真的?哦,天哪!……)
OllyDbg 支持所有标准类型的断点[breakpoints]----非条件和条件断点、内存断点(写入或访问)、硬件断点或在整个内存块上下断点(后两项功能只在Window ME,NT,2000,XP中有效)。条件表达式可以非常复杂(“当 [ESP+8] 的第 2 位被设置,并且 123456 位置处的字[word]小于10,或者 EAX 指向一个以“ABC”开头的 UNICODE 字串,但跳过前10次断点而在第11次中断”)。您可以设定一条或多条指令,当程序暂停时由OllyDbg传递给插件插件[plugins]。除了暂停,您还可以记录某个表达式的值(可以带有简短的说明),或者记录 OllyDbg 已知的函数的参数。在Athlon 2600+、Windows2000 环境下,OllyDbg 可以每秒处理多达 25000 个条件断点。
另一个有用的特性是跟踪。OllyDbg 支持两种方式的跟踪:hit和run。在第一种情况下,它对指定范围内的每条指令上设置断点(比如在全部可执行代码中)。当到达设断的指令后,OllyDbg 清除断点并且把该指令标记为hit。这种方法可以用来检测某段代码是否被执行。Hit跟踪速度惊人的快,在一个很短时间的启动后程序几乎达到了全速(译者注:这应该是与不进行调试时速度相比而言)。因为INT3断点可能对数据有灾难性的影响,所以我建议不要使用模糊识别过程。当代码没有被分析时Hit跟踪是不可以使用的。
Run跟踪[Run trace] 是一步一步地执行程序,同时记录精确的运行历史和所有寄存器的内容、已知的参数和可选的指令(当代码是自修改时会有帮助)。当然,这需要大量的内存(每个指令需要15至50个字节,取决于调试的模式)但是可以精确地回溯和分析。您可以只在选定的一段代码甚至是一条指令中进行Run跟踪,或者您可以跳过无关紧要的代码。对于每个地址,OllyDbg能够计算这个地址在Run跟踪日志中出现的次数,虽然会导致执行缓慢但是可以得到代码执行的统计。比如说,某命令让您在每个已识别的过程入口处进行Run跟踪,那么统计[profile]就会给您每个过程被调用的次数。在到达某条指令、某个地址范围或指令计数器达到某一数值时Run跟踪可以自动地暂停[pause]。
在多线程程序里OllyDbg可以自动管理线程[threads],如果您单步调试或跟踪程序,它会自动恢复当前线程而挂起其它线程。如果您运行程序,OllyDbg 会恢复先前的线程状态。
您可以为内存块建立快照(叫做备份)。OllyDbg会高亮显示所有的改动。您可以把备份保存到文件或从文件中读取出来,从而发现两次运行的不同之处。您可以查看备份,搜索下一处改动,恢复全部或选定的改动。补丁管理器[Patch manager]记录了上次应用到程序中的所有补丁,在下次调试时可以再次应用它们。
您可以很容易地把您的补丁加在可执行文件上。OllyDbg 会自动进行修正。
您不能在带有 Win32 的16位 Windows 下使用 OllyDbg。这种32位扩展操作系统无法实现某些必需的调试功能。
您既不能调试 DOS 程序也不能调试16位 NE(New Executable)格式文件,我也没有打算在未来的版本中支持这些。安息吧,古老而美好的命令提示符!
三,反汇编器[Disassembler]
反汇编器识别所有的标准80x86、保护、FPU、MMX和3DNow!指令集(包括Athlon扩展的MMX指令集)。但它不识别ISSI命令,尽管计划要在下个版本中支持这种命令。某些过时或者未公开的命令,像LOADALL,也不支持。
反汇编器可以正确解码16位地址。但它假设所有的段都是32位的(段属性使用32位)。这对于PE[Portable Executable]格式文件总是真的。OllyDbg不支持16位的NE
[New Executables]格式。
如果您熟悉MASM或者TASM,那么反汇编的代码对于您没有任何问题。但是,一些特例也是存在的。以下命令的解码与Intel的标准不同:
AAD (ASCII Adjust AX Before Division) -
该命令的解码后的一般形式为:AAD imm8
AAM (ASCII Adjust AX After Multiply) -
该命令(非十进制数)的一般解码形式为:AAM imm8
SLDT (Store Local Descriptor Table register) -
操作数总被解码为16位。这个命令的32位形式会在目的操作数的低16位中存储段选择器,并保留高16位不变。
SALC (Sign-extend Carry bit to AL, undocumented) -
OllyDbg 支持这个未公开指令。
PINSRW (Insert Word From Integer Register, Athlon extension to MMX) -
在AMD的官方文档中,这个命令的内存形式使用了16位内存操作数;然而寄存器形式需要32位寄存器,但只使用了低16位。为了方便处理,反汇编器解码寄存器为16
位形式。而汇编器两种形式都支持。
CVTPS2PI and CVTTPS2PI (Convert Packed Single-Precision Floating to Packed Doubleword, Convert with Truncation Packed Single-Precision Floating to Packed Doubleword) -
在这些命令中,第一个操作数是MMX寄存器,第二个或者是128位XMM寄存器或者是64位内存区域。为了方便处理,内存操作数也被解码为128位。
有些指令的助记符要依赖操作数的大小:
不分大小的形式 明确的16位形式 明确的32位形式
PUSHA PUSHAW PUSHAD
POPA POPAW POPAD
LOOP LOOPW LOOPD
LOOPE LOOPWE LOOPDE
LOOPNE LOOPWNE LOOPDNE
PUSHF PUSHFW PUSHFD
POPF POPFW POPFD
IRET IRETW IRETD
您可以改变解码大小敏感助记符[decoding of size-sensitive mnemonics].。根据选项,反汇编器从三种可能中选择之一进行解码。这个选项也会影响汇编器的默认处理方式。
解码MMX和3DNow!指令总是开启的,尽管您的处理器并不支持这些指令。四,分析器[Analysis]
OllyDbg 整合了一个快速而强大的代码分析器。您可以从快捷菜单,或者在CPU窗口的反汇编面板中按 Ctrl+A ,或者在可执行模块中选择“分析全部模块[Analyze all modules]”,来使用它。
分析器有很高的启发性。它能区分代码和数据,标记入口和跳转目的地址,识别转换表[switch tables],ASCII 和 UNICODE 串,定位函数过程,循环,高阶转换[
high-level switches]并且能解码标准API函数的参数(示例[example])。OllyDbg 的其他部分也广泛的使用了分析后的数据。
这是如何实现的?我将为您揭开这一神秘面纱。第一遍,OllyDbg反汇编代码段中所有可能的地址,并计算调用的每个目的地址的个数。当然,很多调用是假的,但不可能两个错误的调用都指向了相同的命令,当然如果有三个的话,就更不可能了。因此如果有三个或者更多的调用指向了相同的地址,我可以肯定的说这个地址是某个频繁使用的子程序的入口。从定位的入口出发,我继续跟踪所有的跳转和函数调用,等等。按这种方法,我可能准确定位99.9% 的命令。但是,某些字节并不在这个链条上。我再用20多种高效的启发方法(最简单的方法,比如“直接访问前64K内存是不允许的,像在MOV [0],EAX中”)来探测他们
有时,分析器在您感兴趣的地方分析错误。有两种解决方法:或者从选中的部分移除分析(快捷键退格键),这样 OllyDbg 将使用默认的解码(反汇编)方式;或者设置
解码提示[decoding hints]并重新分析。注意:在某些情况下,当分析器认为您的提示是不合适的,或者有冲突,则可能忽略您的设置。
探测程序的函数过程也很简单。在分析器眼中看来,程序只是一个连绵不断的代码,从一个入口开始,可能达到(至少从理论上)所有的命令(除了NOP以及类似的用于填充间隙的命令)。您可能指定三个识别级别。严格的函数过程要求有准确的一个入口,并且至少有一个返回。在启发级别下,分析器只要求过程有一个入口。而如果您选择模糊模式,差不多连贯的代码都会被识别为单独的过程。现代编译器进行全局代码优化,有可能把一个过程分成几个部份。在这种情况下,模糊模式非常有用。但是也会误识别的机率也就更高。
同样地,循环是一个封闭的连续的命令序列,并有一个到开始处的跳转作为一个入口,还有若干个出口。循环与高级操作命令 do, while 和 for 相对应。OllyDbg 能够识别任何复杂的嵌套循环。他们会在反汇编栏[Disassembly]中用长而粗括号标记。如果入口不是循环的第一个命令,OllyDbg会用一个小三角进行标记。
为了实现一个转换[switch], 许多编译器,读取转换变量[switch variable]到寄存器中,然后减它,像如下的代码序列:
MOV EDX,
SUB EDX,100
JB DEFAULTCASE
JE CASE100 ; Case 100
DEC EDX
JNE DEFAULTCASE
... ; Case 101
这个序列可能还包含一到两阶的转换表、直接比较、优化和其他元素。如果在比较或跳转的很深处,这就很难知道哪是一个分支[Case]。OllyDbg 会帮助您,它会标记所有的分支,包括默认的,甚至尝试分析每个分支的含义,如'A'、WM_PAINT 或者 EXCEPTION_ACCESS_VIOLATION。如果命令序列没有修改寄存器(也就是仅仅由比较组成),那么这可能不是转换,而很有可能是选择嵌套:
if (i==0) {...}
else if (i==5) {...}
else if (i==10) {...}
如果需要OllyDbg将选择嵌套解码成选择语句,请在分析1[Analysis1]中设置相关选项。
OllyDbg包含多达1900条常用API函数,这些都作为内部预处理资源。这个列表包含了KERNEL32, GDI32, USER32, ADVAPI32, COMDLG32, SHELL32, VERSION, SHLWAPI, COMCTL32, WINSOCK, WS2_32 和 MSVCRT。您可以添加自己的函数描述[add your own descriptions]。如果分析器遇到的调用,使用了已知的函数名(或者跳转到这样的函数),它将在调用之前立即解码PUSH命令。因此,您只需略微一看就能明白函数调用的含义。OllyDbg还包含了大约400多种的标准C函数。如果您有原始的库文件,我推荐您在分析前扫描目标文件。这样OllyDbg将能解码这些C函数的参数。
如果选项“猜测未知函数的参数个数”开启,分析器将会决定这个调用函数过程使用的长度为双字的参数个数。并且标记他们为参数1[Arg1],参数2[ Arg2],等等。注意:无论如何,寄存器参数是无法识别的,所以不会增加参数的数目。分析器使用了一种比较安全的方法。例如,它不能识别的没有参数的函数过程,或者该过程POP
命令直接做返回前的寄存器恢复,而不销毁参数。然而,识别出来的函数参数数目通常非常高,这大大加大了代码的可读性。
分析器能够跟踪整型寄存器的内容。现代优化编译器,特别是奔腾系列,频繁地使用寄存器读取常量和地址,或使用尽量少的使用内存。如果某个常量读取到寄存器中,分析器会注意它,并尝试解码函数和其参数。分析器还能完成简单的算术计算,甚至可以跟踪压栈和出栈。
分析器不能区分不同类的名称[different kinds of names]. 。如果您将某些函数指定为已知的名称,OllyDbg将会解码所有到该地址的调用。这是几个预定义的特殊名称
WinMain, DllEntryPoint and WinProc。您可能使用这些标签标记主程序、DLL的的入口以及窗口过程(注意:OllyDbg不检查用户自定义的标签是否唯一)。另外,假定预定义参数assume predefined arguments是一种更好的方法
不幸的是,没有一般规则能够做到100%的准确分析。在某些情况下,例如当模块包含了P-Code或代码段中包换了大量的数据,分析器可能将一些数据解释成代码。如果统计分析显示代码部分很可能是压缩包或者经过加密了,分析器会发出警告。如果您想使用Hit跟踪[Hit trace],我建议您不要使用模糊分析[fuzzy analysis],因为设置断点的地方可能正是数据部分。
自解压文件[Self-extractable files] 通常有一个自提取器,在“正式”代码段之外。如果您选择自解压选项[SFX option]中的“扩展代码段,包含提取器[Extend code section to include self-extractor]”,OllyDbg将会扩展代码段,形式上允许分析它,并可以使用Hit跟踪[Hit] trace和Run跟踪[Run trace]。
2005-9-6 15:27 乾龙五,Object扫描器[Object scanner]
扫描器将特定的目标文件或者目标库(包括OMF和COFF两种格式),提取出代码段,然后将这些段定位在当前模块的代码节[Code section]中.如果段定位好了,扫描器将从目标文件中的调试信息提取名称(也就是所谓的库标签[library labels])。这极大的增加了代码与数据的可读性.
扫描器并不会对已识别的目标文件进行标签匹配,所以它不能识别非常小或相似的函数(比如:两个函数只是在重定位有区别)。因此要经常检查扫描器发送到登陆窗口的警告列表!六,Implib扫描器 [Implib scanner]
某些DLL的输出符号仅仅是一个序号。许多符号都是井号加数字(比如:MFC42.#1003),这非常不便于理解。幸运的是,软件零售商提供了输入连接库(implibs),它与序号符号名相关。
使用implib扫描器的方法:从主菜单中选择调试[Debug]|选择输入链接库[Select import libraries]。当您加载应用程序时,OllyDbg会读取链接库并从内置表格[
internal tables]中提取符号名。每次遇到序号符号,而对应的链接库已经注册到OllyDbg中时,这个序号符号会被替换。七,如何开始调试[How to start debugging session]
最简单的方法是:运行 OllyDbg,点击菜单上的文件[File]|打开[Open],选择您想调试的程序。如果程序需要命令行参数,您可以在对话框底部的输入栏中,输入参数或者选择以前调试时输入过的一条参数。
OllyDbg 能够调试独立的DLL[stand-alone DLLs]。在这种情况下,OllyDbg 会创建并运行一个小的应用程序来加载链接库并根据您的需要调用输出函数。
如果您想重新启动上一次调试的程序,只要按一下 Ctrl+F2(这是重启程序的快捷键),这样 OllyDbg 会以同样的参数运行这个程序。另一种做法是在菜单中选择文件[File],从历史列表中选择程序。您也可以在 Windows 资源管理器中将可执行文件或 DLL 文件拖拽到 OllyDbg 中。
当然,您可以在 OllyDbg 启动时,运行指定带有运行参数的被调试程序。例如:您可以在桌面创建一个 OllyDbg 的快捷方式,右击并选择“属性”,在“快捷方式”中的“目标”中添加调试的程序的全路径。这样,您每次双击快捷方式时,OllyDbg 将自动运行被调试程序。注意:DLL文件不支持这种方式。
您可以把正在运行的进程挂接到 OllyDbg 中。在菜单中打开 文件[File]|挂接[Attach],从进程列表中选择要挂接的进程。注意:在您关闭 OllyDbg 的同时,这个进程也会被关闭。不要挂接系统进程,否则可能会导致整个操作系统的崩溃。(事实上在大多数情况下,操作系统禁止您挂接敏感进程)。
OllyDbg 可以作为即时[just-in-time]调试器。这需要在系统注册表中注册。在菜单中选择选项[Options]|即时调试[Just-in-time debugging] 并在弹出的对话框中单击按钮“设置OllyDbg为即时调试器”[Make OllyDbg just-in-time debugger]。今后,如果某个应用程序发生了非法操作,系统将提示您是否用 OllyDbg 调试这个程序。操作系统会启动 OllyDbg 并直接停在发生异常的地方。如果您选择了“挂接时不询问”[attaching without confirmation],则在即时调试时OllyDbg不会弹出询问对话框。如果想恢复成以前的即时调试器[Restore old just-in-time debuger],按相应的按钮即可。
另一种方法是把 OllyDbg 添加到与可执行文件关联的快捷菜单中(这个想法是 Jochen Gerster 提出的)。在主菜单中,选择选项[Options]|添加到资源管理器中[Add to Explorer]。以后您可以在所有的文件列表中,右击可执行文件或DLL,在快捷菜单中选择OllyDbg。这个功能会创建四个注册表键值:
HKEY_CLASSES_ROOT\exefile\shell\Open with OllyDbg
HKEY_CLASSES_ROOT\exefile\shell\Open with OllyDbg\command
HKEY_CLASSES_ROOT\dllfile\shell\Open with OllyDbg
HKEY_CLASSES_ROOT\dllfile\shell\Open with OllyDbg\command
OllyDbg能够调试控制台程序(基于文字的)。
OllyDbg不能调试.NET应用程序。.NET程序是由微软的中间语言这种伪指令组成的,或是on-the-fly to native ?6 commands编译的。
注意:如果您运行的是Windows NT、2000 或XP操作系统,您应该拥有管理员权限以
八,CPU 窗口[CPU window]
对于用户来说,CPU窗口在OllyDbg中是最重要的窗口。您调试自己程序的绝大部分操作都要在这个窗口中进行。它包括以下五个面板(这五个面板的大小都是可以调节的):
反汇编[Disassembler]
信息[Information]
数据[Dump]
寄存器[Registers]
栈[Stack]
按TAB键,可以切换到下一个CPU面板中(顺时针方向)。
按Shift+TAB,可以切换到前一个CPU面板(逆时针方向)。九,断点[Breakpoints]
OllyDbg支持数种不同类型的断点:
- 一般断点[Ordinary breakpoint], 将您想中断的命令的第一个字节,用一个特殊命令INT3(调试器陷阱)来替代。您可以在反汇编窗口中选中要设断点的指令行并按下 F2 键就可以设定一个此类型的断点。也可以在快捷菜单中设置。再次按下 F2 键时,断点将被删除。注意,程序将在设断指令被执行之前中断下来。
INT3断点的设置数量是没有限制的。当您关闭被调试程序或者调试器的时候,OllyDbg将自动把这些断点保存到硬盘中,永远不要试图在数据段或者指令的中间设置这种断点,如果您试图在代码段以外设置断点,OllyDbg将会警告。您可以在安全选项[Security options]中永远关闭这个提示,在某些情况下调试器会插入自带的临时INT3
断点。
- 条件断点[Conditional breakpoint] (快捷键 Shift+F2) 是一个带有条件表达式的普通INT3断点。当调试器遇到这类断点时,它将计算表达式的值,如果结果非零或者表达式无效,将暂停被调试程序,当然,由条件为假的断点引起的开销是非常高的(主要归因于操作系统的反应时间)。在Windows NT、奔腾Ⅱ/450处理器环境下
OllyDbg每秒最多处理2500个条件为假的断点。条件断点的一个典型使用情况就是在Windows消息上设置断点(比如 WM_PAINT)。为此,您可以将伪变量 MSG 同适当的参数说明联合使用。如果窗口被激活,参考一下后面的消息断点描述。
- 条件记录断点 [Conditional logging breakpoint] (Shift+F4)是一种条件断点,每当遇到此类断点或者满足条件时,它将记录已知函数表达式或参数的值。例如,您可以在一些窗口过程函数上设置记录断点并列出对该函数的所有调用。或者只对接收到的WM_COMMAND消息标识符设断,或者对创建文件的函数(CreateFile)设断,并且记录以只读方式打开的文件名等,记录断点和条件断点速度相当,并且从记录窗口中浏览上百条消息要比按上百次F9轻松的多,您可以为表达式选择一个预先定义好的解释说明。
您可以设置通过的次数 - 每次符合暂停条件时,计数器就会减一。如果通过计数在减一前,不等于零,OllyDbg就会继续执行。如果一个循环执行100次(十进制),在循环体内设置一个断点,并设置通过次数为99(十进制)。OllyDbg将会在最后一次执行循环体时暂停。
另外,条件记录断点允许您传递一个或多个命令给插件[plugins]。例如,您需要使用命令行插件改变一个寄存器的内容,然后继续执行程序。
- 消息断点[Message breakpoint]和条件记录断点基本相同,除了OllyDbg会自动产生一个条件,这个条件允许在窗口过程的入口处设置某些消息(比如WM_PSINT)断点,您可以在窗口[Windows]中设置它。
- 跟踪断点[Trace breakpoint] 是在每个选中命令上设置的一种特殊的INT3断点。如果您设置了Hit跟踪[hit trace] ,断点会在命令执行后移除,并在该地址处做一个标记。如果您使用的是Run跟踪[run trace] ,OllyDbg会添加跟踪数据记录并且断点仍然是保持激活状态。
- 内存断点[Memory breakpoint] OllyDbg每一时刻只允许有一个内存断点。您可以在反汇编窗口、CPU窗口、数据窗口中选择一部分内存,然后使用快捷菜单设置内存断点。如果有以前的内存断点,将被自动删除。您有两个选择:在内存访问(读,写,执行)时中断,或内存写入时中断。设置此类断点时,OllyDbg将会改变所选部分的内存块的属性。在与80x86兼容的处理器上将会有4096字节的内存被分配并保护起来。即使您仅仅选择了一个字节,OllyDbg 也会将整个内存块都保护起来。这将会引起大量的错误警告,请小心使用此类断点。某些系统函数(特别是在Windows95/98下)在访问受保护的内存时不但不会产生调试事件反而会造成被调试程序的崩溃。
- 硬断点[Hardware breakpoint](仅在Windows ME,NT或2000下可用)在80x86兼容的处理器上,允许您设置4个硬件断点。和内存断点不同,硬件断点并不会降低执行速度,但是最多只能覆盖四个字节。在单步执行或者跟踪代码时,OllyDbg能够使用硬断点代替INT3断点。
- 内存访问一次性断点[Single-shot break on memory access] (仅在Windows NT或2000下可用)。您可以通过内存窗口的快捷菜单(或按F2),对整个内存块设置该类断点。当您想捕捉调用或返回到某个模块时,该类断点就显得特别有用。中断发生以后,断点将被删除。
- 暂停Run跟踪[Run trace pause] (快捷键:Ctrl+T)是在每一步Run跟踪[run trace] 时都要检查的一个条件集.您可以在EIP进入某个范围或超出某个范围时暂停,某个条件为真时暂停,或者命令与指定的模式匹配时暂停,或者当命令可疑的时候暂停。注意,这一选择会极大的(高达20%)降低Run跟踪的速度。
OllyDbg也可以在一些调试事件[debugging events]上暂停程序执行。比如加载或卸载DLL,启动或终止线程,或者程序发出调试字符串的时候。
10,数据窗口[Dump]
数据窗口用于显示内存或文件的内容。您可以从以下预处理格式[predefined formats]中选择一种显示方式:字节[byte]、文本[text]、整数[integer]、浮点数[float
]、地址[address],反汇编[disassembly]、 PE头[PE Header]。
所有的dump窗口支持备份[backup]、搜索和编辑操作。CPU 窗口[CPU window]的Dump面板允许您对可执行代码的数据和可执行文件(.exe,或.dll)的内存映射做如下操作:定义标签[labels]、设置 内存断点[memory breakpoints], 查找参考[references]。数据菜单[Dump menu]只显示与选中部分相关的命令。
如果 备份[backup]可用,则单击第一个列标题栏,会在地址[Address]/备份[Backup] 两种显示模式之间切换。点击其他列标题栏,会改变Dump模式。
像反汇编窗口一样,数据窗口也保存了大量查看内存地址的历史记录。您可以通过“+”和“-”键来访问您过去查看过的数据地址空间。
要翻动一字节的数据,可以按住Ctrl l键并按上/下方向键。
可执行模块窗口[Executable modules window]
可执行模块窗口(快捷键:Alt+E)列出了当前被调试进程加载的所有可执行模块。它也显示了很多有用的信息,比如模块大小、入口地址、模块版本、以及可执行文件路径等。一些信息,如以十进制显示的模块大小、入口地址的符号名、是否为系统模块等,通常是被隐藏的。如果想看,可以增加相应栏的宽度。快捷菜单支持以下操作:
刷新[Actualize] - 重新扫描模块并去除对新加载模块的高亮显示。在大多数情况下,OllyDbg会自动完成该操作。
查看内存[View memory] - 打开内存窗口,并定位到属于该模块镜像的第一个内存块处。
在CPU窗口中查看代码[View code in CPU] (快捷键:回车键) - 在反汇编窗口中显示模块的可执行代码。
跟进到入口[Follow entry] - 在反汇编窗口中跟进到模块的入口处。
在CPU窗口中查看数据[Dump data in CPU] -在CPU窗口的数据面板中显示模块的数据段。块代码段。
显示名称[View names] (快捷键:Ctrl+N) -显示当前模块定义或使用的全部名称[names](包括输出表、引入表、链接库、用户自定义)。
标记为系统DLL[Mark as system DLL],
标记为非系统DLL[Mark as non-system DLL] - 将选中模块标记为系统或非系统属性。如果设置为系统属性,则在Run跟踪[Run trace] 时会直接执行(不进行跟踪)这个模块,从而大大加快跟踪速度。默认情况下,所有驻留在系统目录(通常在Windows 95/98下为c:\windows\system ,在WinNT/2000/XP下为c:\winnt\system32)的模块都认为是系统模块。
立即更新.udd文件[Update .udd file now] -向文件“.udd”写入模块相关的全部数据,udd文件保存了在调试期间设置的断点、标签、注释、监视、分析等信息。当模块卸载时OllyDbg会自动创建.udd文件。
查看可执行文件[View executable file] - 显示可执行文件的全部内容。
查看全部资源[View all resources] - 以列表形式显示模块定义的全部资源,并带有一个简短信息。OllyDbg并不把资源当作单独实体来支持。您可以提取[Dump]并以二进制的形式进行编辑。
查看资源字符串[View resource strings] -以列表形式显示资源字符串及其标识符。
查看Run跟踪的统计[View run trace profile] - 在此模块中计算统计[profile] 。相关信息:Run跟踪[Run trace].
分析全部模块[Analyze all modules] -允许同时分析全部模块。分析将从代码中提取大量的有用信息;代码经过分析后再进行调试,通常会非常快并且可靠。
鼠标双击某一行,将会在反汇编窗口中显示模块的执行代码。十,内存映射窗口[Memory map window]
内存映射窗口显示了被调试程序分配的所有内存块。因为没有标准的方法来完成这项任务,所以OllyDbg可能会把一个大的内存块分成几个部分。然而,在大多数情况下,并非一定要精确处理。如果想查看由应用程序通过调用GlobalAlloc()和LocalAlloc()等申请的内存块列表,请使用堆列表[Heap list]。
如果内存块是可执行模块的一个节,OllyDbg则会报告这个内存块所包含的数据类型:代码、数据、资源等。
Windows95/98是和WindowsNT/2000是有一些区别的。在Windows95/98下,OllyDbg是不能显示被映射文件的名称的。另外,Windows95/98不允许的访存类型为读和写,然而,在WindowsNT/2000下,OllyDbg却有拥有更多功能,包括执行访问,写复制[copy-on-write]以及监视标志位。OllyDbg忽略写复制[copy-on-write]属性。
如果OllyDbg发现程序分配了新内存或者重新分配了已经存在的内存块,它将在内存映射窗口中高亮显示相应的记录,去掉高亮度显示,可以选择快捷菜单中的刷新[
Actualize]项。
您可以按Alt+M来调用内存窗口。
以下是快捷菜单中可以选择的菜单项:
刷新[Actualize] - 更新已分配内存的列表并去除对新内存块的高亮显示。
在反汇编窗口中查看[View in Disassembler] -在反汇编窗口中查看:在反汇编窗口中打开内存块,这一选项仅在某些模块的内存块中包含可执行代码或者自解压器时可用。
在CPU数据窗口中查看[Dump in CPU] - 在CPU的数据窗口中显示内存块的内容。
数据窗口[Dump] - 在单独窗口中显示内存块内容。如果内存块的类型已知,则OllyDbg会自动选择显示格式。
查看全部资源[View all resources] - 如果内存块包含资源数据,则列出所有资源及相关数据。OllyDbg并不把资源当作单独实体来支持。您可以显示其数据并以二进制的形式进行编辑。
查看资源字符串[View resource strings] - 如果内存块包含资源数据,则列出全部资源字符串及其标识符。
搜索[Search] - 允许搜索所有的内存块,从选择处开始,搜索匹配的二进制串。如果找到,则OllyDbg将显示该内存块。内存映像窗口和数据窗口共享同一种搜索模式,所以您可以在弹出的数据窗口中立即继续搜索该二进制串出现的下一位置。按Esc键可以关闭数据窗口。
搜索下一个[Search next](快捷键:Ctrl+L) - 继续上次搜索。
设置访问中断[Set break-on-access] (快捷键:F2,仅在WindowsNT/2000下可用) - 保护整个内存块。当中断发生后OllyDbg暂停被调试程序并清除断点。这类断点在您想捕捉调用或返回到某个模块的时候特别有用。
清除访问中断[Remove break-on-access] (快捷键:F2) - 从内存块中清除访问中断保护。
设置内存访问断点[Set memory breakpoint on access] - 在整个内存块上设置断点,每当该内存块被访问时程序都将中断。OllyDbg只支持一个内存访问断点。在
Windows95/98下,当系统程序访问含有内存断点的内存块时,可能会导致所被调试程序崩溃,因此,不到万不得已,请不要设置这种断点。
设置内存写入断点[Set memory breakpoint on write] - 在整个内存块上设置断点,每当该内存块被写入数据时程序都将中断。在Windows95/98下,当系统程序访问含有内存断点的内存块时,可能会导致所被调试程序崩溃,因此,不到万不得已,请不要设置这种断点。
清除内存断点[Remove memory breakpoint] - 清除内存断点。
清除自解压内存断点[Remove SFX memory breakpoint] - 停止搜索自解压程序[self-extractable (SFX) program]的真实入口。这个搜索使用了特殊类型的内存断点。
访问设置[Set access] -设置整个内存块的保护属性,可选择的有:
禁止访问[No access]
只读[Read only]
读/写[Read/write]
执行[Execute]
执行/读[Execute/read]
完全访问[Full access]
复制到剪切板[Copy to clipboard]
整行[Whole line] -以多行文本(包括解释)的方式把所选记录复制到剪切板,如果复制时想排除某些列,可将该列的宽度置为最小(该栏剩余的边框将变灰)。
整个表格[Whole table] -以多行文本的方式将整个内存映像信息复制到剪切板,该文本的第一行为窗口标题("内存映射[Memory map]"), 第二行为列标题栏,后面几行的内容为内存数据记录。复制将保持列的宽度。如果复制时想排除某些列,可将该列的宽度置为最小(该栏剩余的边框将变灰)。十一,监视与监察器[Watches and inspectors]
监视[Watch] 窗口包含若干个表达式[expressions]。它在第二列里显示这些表达式的值。OllyDbg 会把这些表达式保存到主模块的.UDD文件中,因此它们在下一次调试时同样有效。
监察器[inspector]是显示若干变量、1/2维数组或是选定项目结构数组[selected items of array of structures]的独立窗口。它的表达式与监视窗口中的基本相同,只是多包含了两个参数:%A和%B。您可以指定这两个参数的界限,OllyDbg 将会用所有可能的组合代替表达式中的%A和%B。从0开始一直到界限(不包含界限),并在表格中显示结果。参数%B(列数)的界限不能超过16。
例如,如果您指定了表达式%A+%B,并且限定%A和%B的上限为3,您将获得如下的表格:
十三,线程[Threads]
OllyDbg 以简单而有效的线程管理为特色。如果您单步调试、跟踪、执行到返回或者执行到所选,则线程管理器将停止除当前线程以外的所有线程。即使当前线程被挂起,它也会将其恢复。在这种情况下,如果您手动挂起或者恢复线程,动作将被延期。如果您运行被调试的应用程序,OllyDbg将恢复最初的线程状态。(从调试器的角度来看,Hit跟踪[hit trace]和自由运行是等效的)。
依据这种方案,线程窗口可能会有如下五种线程状态:
激活[Active] - 线程运行中,或被调试信息暂停t
挂起[Suspended] - 线程被挂起
跟踪[Traced] - 线程被挂起,但OllyDbg正在单步跟踪此线程
暂停[Paused] - 线程是活动的,但OllyDbg临时将其挂起,并在跟踪其它的线程
结束[Finished] - 线程结束
.
线程窗口同时也显示了最后的线程错误(GetlastError函数的返回值)并计算该线程以用户模式和系统模式(仅NT/2000/XP)运行的时间。线程窗口还会高亮主线程的标识符。
以下在快捷菜单中可用:
刷新[Actualize] - 标记所有线程为旧的。
挂起[Suspend] - 挂起线程。
恢复[Resume] - 恢复先前挂起的线程。
设置优先级[Set priority] - 调整进程中线程的优先级。以下选项可用:
空闲[Idle] - 进程中线程的最低优先级
最低[Lowest]
低[Low]
标准[Normal]
高[High]
最高[Highest]
时间临界[Time critical] - 最高优先级
在CPU窗口打开[Open in CPU](双击)- 在CPU窗口中显示所选线程的当前状态。十四,复制到剪切板[Copy to clipboard]
整行[Whole line] -全部行--以多行文本的形式并带注释将所选记录复制到剪切板。如果在复制时想排除某个栏目,可以将该栏的宽度置为最小(栏目的残留部分将变灰)。
整个表格[Whole table] - 整个表格--以多行文本的形式将整个内存映象复制到剪切板,该文本的第一行包含窗口标题(“内存映射[Memory map]”),第二行是栏目标题,所有后继行是内存数据记录。复制将保持栏目的宽度。如果在复制时想排除某些栏目,可以将该栏的宽度置为最小(栏目的残留部分将变灰)。十五,调用栈[Call stack]
调用栈窗口(快捷键:Alt+K)根据选定线程的栈,尝试反向跟踪函数调用顺序并将其显示出来,同时包含被调用函数的已知的或隐含的参数。如果调用函数创建了标准的堆栈框架(PUSH EBP; MOV EBP,ESP),则这个任务非常容易完成。现代的优化编译器并不会为栈框架而操心,所以OllyDbg另辟蹊径,采用了一个变通的办法。例如,跟踪代码到下一个返回处,并计算其中全部的入栈、出栈,及 ESP 的修改。如果不成功,则尝试另外一种办法,这个办法风险更大,速度也更慢:移动栈,搜索所有可能的返回地址,并检查这个地址是否被先前的已分析的命令调用。如果还不行,则会采用启发式搜索。栈移动[Stack Walk]可能会非常慢。OllyDbg 仅在调用栈窗口打开时才会使用。
调用栈窗口包含5个栏目:地址[Address]、栈[Stack]、过程[Procedure],调用来自[Called from],框架[Frame]。地址[Adress]栏包含栈地址,栈[Stack]
栏显示了相应的返回地址或参数值。
函数[Procedure](或 函数/参数[Procedure / arguments])显示了被调用函数的地址,在某些情况下,OllyDbg并不能保证该地址是正确的并会添加如下标记之一:
? 找到的入口点不可靠
可能[Maybe] OllyDbg无法找到精确的入口点,报告的地址是用启发式算法猜测的。
包含[Includes] OllyDbg无法找到入口点,仅知道该函数包含显示的地址
通过按例标题栏上的按钮或从菜单中选择“隐藏/显示参数[Hide/Show arguments]”,可以在显示或隐藏函数的参数之间切换。
调用来自[Called from]用于显示调用该函数的命令地址。最后一栏是框架[Frame]这一栏默认是隐藏的,如果框架指针的值(寄存器EBP)已知的话,则该栏用于显示这个值。
当调用函数经过分析[analyzed].后,栈移动会更可靠并且迅速。十六,调用树[Call tree]
调用树(快捷键:在反汇编窗口中Ctrl+K)利用分析[Analysis]的结果来找出指定函数过程直接或间接调用的函数列表,同时列出指定函数过程被调用的地址。为了避免由此可能造成的副作用。调用树会判断选定函数是否明确地是递归的。“明确地”意味着它不会跟踪目标未知的调用,比如CALL EAX。如果函数过程中有未知调用,调用树将会添加标记“未知目标”。
某些函数调用将会添加如下注释之一:
叶子[Leaf] 不调用其他函数
纯函数[Pure] 不调用函数,不会产生副作用
单返回[RETN] 只有一个RETN 命令
系统[Sys] 系统动态链接库中的函数。系统动态链接库定义为保存在系统目录下的动态链接库。
如果想在调用树上移动,可以双击“被调用[Called from]”或“调用/直接调用[Calls/Calls directly]”两栏中的地址。调用树窗口保存了移动记录(快捷键“-”和“+”)。
如果被调试的程序包含几个模块,推荐您分析所有模块。Call tree 不会试图处理系统函数。十七,选项[Options]
外观选项[Appearance options]
常规[General]
默认[Defaults]
对话框[Dialogs]
目录[Directories]
字体[Fonts]
颜色[Colours]
代码高亮[Code highlighting]
调试选项[Debugging options] (Alt+O)
安全[Security]
调试[Debug]
事件[Events]
异常[Exceptions]
跟踪[Trace]
自解压[SFX]
字符串[Strings]
地址[Addresses]
命令[Commands]
反汇编[Disasm]
CPU
寄存器[Registers]
栈[Stack]
分析1[Analysis 1]
分析2[Analysis 2]
分析3[Analysis 3]
即时调试[Just-in-time debugging]
添加到资源管理器[Add to Explorer]十八,搜索[Search]
OllyDbg 允许您使用以下的搜索方式:
符号名(标签)[Symbolic name (label)]
二进制串[binary string]
常量[constant]
命令[command]
命令序列[sequence of commands]
模块间调用[intermodular calls]
修改过的命令或数据[modified command or data]
自定义标签[user-defined label]
自定义注释[user-defined comment
文本字符串[text string]
Run跟踪的记录[record in run trace]
参考命令[referencing commands]
十九,自解压文件[Self-extracting (SFX) files]
自解压文件由提取程序和压缩的原程序两部分组成。当遇到自解压文件(SFX)文件时,我们通常希望跳过解压部分,而直接跳到原始程序的入口(真正的入口)。
OllyDbg 包含了几个便于完成这一任务的功能。
通常提取程序的加载地址都在执行代码之外。在这种情况下,OllyDbg 将这类文件均视作为自解压文件(SFX)。
当自解压选项[SFX options]要求跟踪真正入口时,OllyDbg 在整个代码节[Code section]设置内存断点,最初这里是空的,或者只包含压缩数据。当程序试图执行某个在这个保护区域的命令,而这些命令不是 RET 和 JMP 时,OllyDbg 会报告真正的入口。这就是提取工作的原理。
上面的方法非常慢。有另外一种比较快的方法。每次读取数据发生异常时,OllyDbg 使这个4K内存区域变为可读,而使原先可读的区域变为无效。而每次发生写数据异常时,
OllyDbg 使这个区域变为可写,而使原先可写的区域变为无效。当程序执行在保留的保护区域中的指令时,OllyDbg 报告真正的入口。但是,当真正的入口点在可读或可写区域内部时,报告的地址就可能有误。
您可以纠正入口位置,选择新的入口,从反汇编窗口的快捷菜单中选择“断点[Breakpoint]|设置真正的自解压入口[Set real SFX entry here]”。如果相应的SFX选项是开启的,OllyDbg下次可以迅速而可靠的跳过自提取程序。
注意:OllyDbg 在跟踪采取了保护或者反调试技术的解压程序时通常会失败。 二十,单步执行与自动执行[Step-by-step execution and animation]
您可以通过按 F7(单步步入)或 F8(单步步过),对程序进行单步调试。这两个单步执行操作的主要区别在于:如果当前的命令是一个子函数,按F7,将会进入子函数,并停在子函数的第一条命令上;而按 F8,将会一次运行完这个子函数。如果您单步步过的子函数中含有断点或其他调试事件,执行将会被暂停,但 OllyDbg 会在子函数的后一条命令上,自动下一个断点,而这个断点您迟早会碰到。
如果被调试程序停在异常上,您可以跳过它,并转到被调试程序建立的句柄处。只需简单的 Shift 键和任何一个单步命令。
如果需要连续按F7、F8键上百次,您可以使用自动执行(Ctrl+F7或者Ctrl+F8)功能。在这种情况下,OllyDbg 将自动重复F7或者F8操作,并且实时更新所有的窗口。这个过程会在下面情况停止:
- 按 Esc 键或发出任何单步命令
- OllyDbg 遇到断点
- 被调试程序发生异常
使用“+”和“-”按键,可以回朔以前的执行历史[execution history].
注意:当执行停止时 OllyDbg 将会刷新大部分窗口。如果动态执行过程非常慢,可以尝试关掉或最小化没有用的窗口。
另外,更快捷的找到以前执行指令的办法是Run跟踪[run trace]。它将创建一个执行协议并告知您指定指令的执行时间和次数二一,Hit跟踪[Hit trace] portant; FLOAT: none; WORD-SPACING: 0px; FONT: 14px/25px verdana, SimSun, Arial, Helvetica, sans-serif; TEXT-TRANSFORM: none; COLOR: rgb(0,0,0); TEXT-INDENT: 0px; WHITE-SPACE: normal; LETTER-SPACING: normal; BACKGROUND-COLOR: rgb(204,232,204); TEXT-ALIGN: left; orphans: 2; widows: 2; webkit-text-size-adjust: auto; webkit-text-stroke-width: 0px">资源:如果 Windows API 函数使用了参考资源串,OllyDbg 可以显示它。其支持显示的类型仅限于附带资源[attached resources]的列表、数据显示及二进制编辑、。
断点: OllyDbg 支持各种断点:一般断点、条件断点、记录断点(比如记录函数参数到记录窗口)、内存读写断点、硬件断点(只适用于ME/NT/2000)等。在Hit跟踪情况下,可以在模块的每条命令上都设置INT3断点。在使用500-MHZ处理器的 Windows NT 中,OllyDbg 每秒可以处理高达 5000 个中断。
监视与监察器:每个监视都是一个表达式并能实时显示表达式的值。您可以使用寄存器、常数、地址表达式、布尔值以及任何复杂代数运算,您还可以比较ASCII和UNICODE
字符串。监察器[inspectors]是一种包含了两个的索引序列的监视[Watches],它以二维表的形式呈现,可以对数组和结构进行解码分析。
Heap walk.:在基于Win95的系统中,OllyDbg 可以列出所有的已分配的堆。
句柄:在基于NT的系统中,OllyDbg 可列出被调试程序的所有系统句柄。
执行:.您可以单步执行、步入子程序或者步过子程序。您也可以执行程序直到函数返回时、执行到指定地址处,还可以自动执行。当程序运行时,您仍然可以操纵程序并能够查看内存、设置断点甚至修改代码。您也可以任意的暂停或重启被调试的程序。
Hit跟踪:.Hit跟踪可以显示出目前已执行的指令或函数过程,帮助您检验代码的各个分支。Hit跟踪会在指定指令到达之前设置断点,而在这个指令执行后,会把这个断点清除掉。
译者注:Hit在英文中是“击中”的意思,指令如果运行了就表示这个指令被“击中”了,没有执行的指令就是“未击中”,这样我们就很容易看出被调试程序哪些部分运行了,而哪些没有运行。
Run跟踪: Run跟踪可以单步执行程序,它会在一个很大的循环缓冲区中模拟运行程序。这个模拟器包含了除了SSE指令集以外的所以寄存器、标志、线程错误、消息、已经函数的参数。您可以保存命令,这样可以非常方便地调试自修改代码(译者注:比如加壳程序)。您可以设置条件中断,条件包括地址范围、表达式、命令。您可以将Run
跟踪信息保存到一个文件中,这样就可以对比两次运行的差别。Run跟踪可以回溯分析已执行过的上百万条命令的各种细节。
统计: 统计[Profiler]可以在跟踪时计算某些指令出现的次数。因此您就能了解代码的哪一部分被频繁执行。
补丁: 内置汇编器能够自动找到修改过的代码段。二进制编辑器则会以ASCII、UNICODE或者十六进制的形式同步显示修改后的数据。修改后的数据同其它数据一样,能够进行复制-粘贴操作。原来的数据会自动备份,以便数据恢复时使用。您可以把修改的部分直接复制到执行文件中,OllyDbg会自动修正。OllyDbg还会记录以前调试过程中使用的所有补丁。您可以通过空格键实现补丁的激活或者禁止。
自解压文件: 当调试自解压文件时,您往往希望跳过解压部分,直接停在程序的原始入口点。OllyDbg的自解压跟踪将会使您实现这一目的。如果是加保护的自解压段,自解压跟踪往往会失败。而一旦OllyDbg找到了入口点,它将会跳过解压部分,并准确的到达入口点。
插件:您可以把自己的插件添加到 OllyDbg 中,以增加新的功能。OllyDbg 的插件能够访问几乎所有重要的数据的结构、能够在 OllyDbg 的窗口中添加菜单和快捷键,能够使用100个以上的插件API函数。插件API函数有详细的说明文档。默认安装已经包含了两个插件:命令行插件和书签插件。
UDD:OllyDbg 把所有程序或模块相关的信息保存至单独的文件中,并在模块重新加载时继续使用。这些信息包括了标签、注释、断点、监视、分析数据、条件等等
更多:这里介绍的功能,仅仅是 OllyDbg 的部分功能。因为其具有如此丰富的功能,以至于 OllyDbg 能成为非常方便的调试器!
2005-9-6 15:25 乾龙二,一般原理[General principles]
我希望您能对80x86系列处理器的内部结构有所了解,同时具有一定的编写汇编程序的能力。对于Microsoft Windows方面的知识,您也要熟悉。
OllyDbg是运行在Windows 95、Windows 98、Windows ME、Windows NT 和 Windows 2000系统下的一个单进程、多线程的分析代码级调试工具。它可以调试PE格式的执行文件及动态链接库,并可以对其打补丁。“代码级”意味着您可以直接与比特、字节或处理器指令打交道。OllyDbg 仅使用已公开的 Win32 API 函数,因此它可以在所有 Windows 操作系统及后继版本中使用。但是由于我没有对 XP 系统进行彻底测试,因此不能保证 OllyDbg 功能的充分发挥。注意:OllyDbg 不支持对 .NET 程序的调试。
OllyDbg不是面向编译器的。它没有特别的规则规定必须是哪一个编译器产生的代码。因此,OllyDbg可以非常好的处理通过编译器生成的代码,或是直接用汇编写入的代码。
OllyDbg可以并行调试程序。您无须暂停执行程序,就可以浏览代码和数据,设置断点、停止或恢复线程,甚至直接修改内存。(这可以视为一种软件调试的模式,与之相对的硬件模式则是当进程在运行时调试器被阻滞,反之亦然)。假使所需的操作比较复杂,OllyDbg会让进程终止一小段时间,但是这种暂停对于用户来说是透明的。
有时进程会发生非法操作。您可以把OllyDbg设置成即时[just-in-time]调试器,它会挂接出错程序,并停在程序产生异常的地方。
通过OllyDbg,您可以调试单独的DLL[standalone DLLs]文件。操作系统不能直接运行 DLL 文件,因此 OllyDbg 将一个可以加载 DLL 的小程序压缩到资源里,这个程序允许您调用最多10个参数的输出函数。
OllyDbg是完全面向模块[module-oriented]的。模块[Module]包括可执行文件(扩展名通常为.EXE)和在启动时加载或需要时动态加载的动态链接库(扩展名通常为.DLL
)。在调试期间,您可以设置断点[breakpoints]、定义新的标签[labels]、注释[comment]汇编指令,当某个模块从内存中卸载[unload]时,调试器会把这些信息保存在文件中,文件名就是模块的名称,扩展名为.UDD(表示 用户自定义文件[User-Defined Data])当OllyDbg下一次加载该模块时,它会自动恢复所有的调试信息,而不管是哪一个程序使用这个模块。假设您正在调试程序Myprog1,这个程序使用了Mydll。您在 Mydll 中设置了一些断点,然后您开始调试Myprog2,这个程序同样使用了Mydll。这时您会发现,所有 Mydll 中的断点依然存在,即使 Mydll 加载到不同的位置!
一些调试器把被调试进程的内存当作一个单一的(并且大部分是空的)大小为2 ^32字节的区域。OllyDbg采用了与之不同的技术:在这里,内存由许多独立的块组成,任何对内存内容的操作都被限制在各自的块内。在大多数情况下,这种方式工作得很好并且方便了调试。但是,如果模块包含好几个可执行段[executable sections],您将不能一次看到全部代码,然而这种情况是非常少见的。
OllyDbg 是一个很占用内存的程序[memory-hungry application]。它在启动时就需要 3 MB,并且当您第一次装载被调试的程序时还需要一到两兆的内存。每一次的分析、备份、跟踪或者文件数据显示都需要占用一定的内存。因此当您调试一个很大的项目,发现程序管理器显示有 40 或 60 兆内存被占用时,请不要惊慌。
为了有效地调试一些不带源码的程序,您必须首先理解它是如何工作的。OllyDbg 包含的大量特性可以使这种理解变得非常容易。
首先,OllyDbg包含一个内置的代码分析器。分析器遍历整个代码,分出指令和数据,识别出不同的数据类型和过程,分析出标准API函数(最常用的大约有1900个)的参数并且试着猜出未知函数的参数数目。您也可以加入自己的函数说明[your own function descriptions]。它标记出程序入口点和跳转目的地,识别出跳转表[table-driven switches]和指向字符串的指针,加入一些注释,甚至标示出跳转的方向等等。在分析结果的基础上,调用树[call tree]显示哪些函数被指定过程调用(直接或间接)并且识别出递归调用、系统调用和叶子过程[leaf procedures]。如果需要的话,您可以设置解码提示[decoding hints]来帮助分析器解析那些不明确的代码或数据。
OllyDbg还包含Object扫描器[Object Scanner]。如果您有库文件[libraries]或目标文件[object files],扫描器会在被调试的程序中定位这些库函数。在全部函数调用中,对标准函数的调用占很重要的一部分(据我估计可达70%)。如果您知道正要被调用的函数的功能,您就不必把注意力集中在这个函数上,可以简单地单步步过[
step over]这个call。分析器知道400多个标准C函数,比如fopen和memcpy。然而我必须承认当前版本的OllyDbg不能定位很短的函数(比一个return命令多不了多少的)或相似的函数(只在重定位上有不同)。
Object扫描器[Object scanner]也能够识别输入库[import libraries]。如果某个DLL是按序号输出的,您不会看到函数名,只会发现一堆无意义的神秘数字。这种DLL的开发者通常会提供一个输入库来实现函数符号名与序号间的对应。让OllyDbg使用这个输入库,它就会恢复原始的函数符号名。
面向对象的语言(如C++),使用了一种叫做名称修饰[name mangling]的技术,把函数类型和参数都加入函数名中。OllyDbg 可以解码[demangle]这种函数名,使程序更易读。
译者注:C++的名称修饰是编译器将函数的名称转变成为一个唯一的字符串的过程,这个字符串会对函数的类、其命名空间、其参数表,以及其他等等进行编码。C++的名称修饰适用于静态成员函数,也适用于非静态成员函数。静态函数的名称修饰的一个好处之一,是能够在不同的类里使用同一个名称来声明两个或者更多的静态成员函数----而不会发生名称上的冲突。
OllyDbg完全支持 UNICODE,几乎所有对 ASCII 字符串的操作都可以同样应用于 UNICODE。
汇编指令都是很相似的。您经常会搞不清自己是不是已经跟踪过某一段代码。在 OllyDbg 中您可以加入自己的标签[labels]和注释[comments]。这些极大地方便了调试。注意一旦您注释了某个DLL,以后每次加载这个DLL时,注释和标签都有效----尽管您在调试不同的程序。
OllyDbg可以跟踪标准的栈帧[stack frames](由PUSH EBP; MOV EBP,ESP所创建的)。现代编译器有禁止产生标准栈框架的选项,在这种情况下分配栈[stack walk
]是不可能的。当程序运行到已知的函数时,栈窗口[stack window]解析它的参数,调用栈[Call stack]窗口显示到达当前位置所调用函数的序列。
现代的面向对象应用程序广泛地使用了一种叫做结构化异常处理[Structured Exception Handling,SHE]的技术。SHE窗口[SEH window] 可以显示异常处理链。
多种不同的搜索[search]选项可以让您找到二进制代码或数据、命令或命令序列、常量或字符串、符号名或在 Run跟踪中的一条记录。
对于任何地址或常量,OllyDbg 可以找出参考[referencing]到该地址或常量的全部命令的列表。然后您可以在这个列表里找出对您来说是重要的参考。举例来说,某个函数可能被直接调用,或者经过编译器优化后把地址放入寄存器间接调用,或者把地址压入堆栈作为一个参数----没问题,OllyDbg 会找出所有这样的地方。它甚至能找到并列出所有和某个指定的位置有关的跳转。(真的?哦,天哪!……)
OllyDbg 支持所有标准类型的断点[breakpoints]----非条件和条件断点、内存断点(写入或访问)、硬件断点或在整个内存块上下断点(后两项功能只在Window ME,NT,2000,XP中有效)。条件表达式可以非常复杂(“当 [ESP+8] 的第 2 位被设置,并且 123456 位置处的字[word]小于10,或者 EAX 指向一个以“ABC”开头的 UNICODE 字串,但跳过前10次断点而在第11次中断”)。您可以设定一条或多条指令,当程序暂停时由OllyDbg传递给插件插件[plugins]。除了暂停,您还可以记录某个表达式的值(可以带有简短的说明),或者记录 OllyDbg 已知的函数的参数。在Athlon 2600+、Windows2000 环境下,OllyDbg 可以每秒处理多达 25000 个条件断点。
另一个有用的特性是跟踪。OllyDbg 支持两种方式的跟踪:hit和run。在第一种情况下,它对指定范围内的每条指令上设置断点(比如在全部可执行代码中)。当到达设断的指令后,OllyDbg 清除断点并且把该指令标记为hit。这种方法可以用来检测某段代码是否被执行。Hit跟踪速度惊人的快,在一个很短时间的启动后程序几乎达到了全速(译者注:这应该是与不进行调试时速度相比而言)。因为INT3断点可能对数据有灾难性的影响,所以我建议不要使用模糊识别过程。当代码没有被分析时Hit跟踪是不可以使用的。
Run跟踪[Run trace] 是一步一步地执行程序,同时记录精确的运行历史和所有寄存器的内容、已知的参数和可选的指令(当代码是自修改时会有帮助)。当然,这需要大量的内存(每个指令需要15至50个字节,取决于调试的模式)但是可以精确地回溯和分析。您可以只在选定的一段代码甚至是一条指令中进行Run跟踪,或者您可以跳过无关紧要的代码。对于每个地址,OllyDbg能够计算这个地址在Run跟踪日志中出现的次数,虽然会导致执行缓慢但是可以得到代码执行的统计。比如说,某命令让您在每个已识别的过程入口处进行Run跟踪,那么统计[profile]就会给您每个过程被调用的次数。在到达某条指令、某个地址范围或指令计数器达到某一数值时Run跟踪可以自动地暂停[pause]。
在多线程程序里OllyDbg可以自动管理线程[threads],如果您单步调试或跟踪程序,它会自动恢复当前线程而挂起其它线程。如果您运行程序,OllyDbg 会恢复先前的线程状态。
您可以为内存块建立快照(叫做备份)。OllyDbg会高亮显示所有的改动。您可以把备份保存到文件或从文件中读取出来,从而发现两次运行的不同之处。您可以查看备份,搜索下一处改动,恢复全部或选定的改动。补丁管理器[Patch manager]记录了上次应用到程序中的所有补丁,在下次调试时可以再次应用它们。
您可以很容易地把您的补丁加在可执行文件上。OllyDbg 会自动进行修正。
您不能在带有 Win32 的16位 Windows 下使用 OllyDbg。这种32位扩展操作系统无法实现某些必需的调试功能。
您既不能调试 DOS 程序也不能调试16位 NE(New Executable)格式文件,我也没有打算在未来的版本中支持这些。安息吧,古老而美好的命令提示符!
三,反汇编器[Disassembler]
反汇编器识别所有的标准80x86、保护、FPU、MMX和3DNow!指令集(包括Athlon扩展的MMX指令集)。但它不识别ISSI命令,尽管计划要在下个版本中支持这种命令。某些过时或者未公开的命令,像LOADALL,也不支持。
反汇编器可以正确解码16位地址。但它假设所有的段都是32位的(段属性使用32位)。这对于PE[Portable Executable]格式文件总是真的。OllyDbg不支持16位的NE
[New Executables]格式。
如果您熟悉MASM或者TASM,那么反汇编的代码对于您没有任何问题。但是,一些特例也是存在的。以下命令的解码与Intel的标准不同:
AAD (ASCII Adjust AX Before Division) -
该命令的解码后的一般形式为:AAD imm8
AAM (ASCII Adjust AX After Multiply) -
该命令(非十进制数)的一般解码形式为:AAM imm8
SLDT (Store Local Descriptor Table register) -
操作数总被解码为16位。这个命令的32位形式会在目的操作数的低16位中存储段选择器,并保留高16位不变。
SALC (Sign-extend Carry bit to AL, undocumented) -
OllyDbg 支持这个未公开指令。
PINSRW (Insert Word From Integer Register, Athlon extension to MMX) -
在AMD的官方文档中,这个命令的内存形式使用了16位内存操作数;然而寄存器形式需要32位寄存器,但只使用了低16位。为了方便处理,反汇编器解码寄存器为16
位形式。而汇编器两种形式都支持。
CVTPS2PI and CVTTPS2PI (Convert Packed Single-Precision Floating to Packed Doubleword, Convert with Truncation Packed Single-Precision Floating to Packed Doubleword) -
在这些命令中,第一个操作数是MMX寄存器,第二个或者是128位XMM寄存器或者是64位内存区域。为了方便处理,内存操作数也被解码为128位。
有些指令的助记符要依赖操作数的大小:
不分大小的形式 明确的16位形式 明确的32位形式
PUSHA PUSHAW PUSHAD
POPA POPAW POPAD
LOOP LOOPW LOOPD
LOOPE LOOPWE LOOPDE
LOOPNE LOOPWNE LOOPDNE
PUSHF PUSHFW PUSHFD
POPF POPFW POPFD
IRET IRETW IRETD
您可以改变解码大小敏感助记符[decoding of size-sensitive mnemonics].。根据选项,反汇编器从三种可能中选择之一进行解码。这个选项也会影响汇编器的默认处理方式。
解码MMX和3DNow!指令总是开启的,尽管您的处理器并不支持这些指令。四,分析器[Analysis]
OllyDbg 整合了一个快速而强大的代码分析器。您可以从快捷菜单,或者在CPU窗口的反汇编面板中按 Ctrl+A ,或者在可执行模块中选择“分析全部模块[Analyze all modules]”,来使用它。
分析器有很高的启发性。它能区分代码和数据,标记入口和跳转目的地址,识别转换表[switch tables],ASCII 和 UNICODE 串,定位函数过程,循环,高阶转换[
high-level switches]并且能解码标准API函数的参数(示例[example])。OllyDbg 的其他部分也广泛的使用了分析后的数据。
这是如何实现的?我将为您揭开这一神秘面纱。第一遍,OllyDbg反汇编代码段中所有可能的地址,并计算调用的每个目的地址的个数。当然,很多调用是假的,但不可能两个错误的调用都指向了相同的命令,当然如果有三个的话,就更不可能了。因此如果有三个或者更多的调用指向了相同的地址,我可以肯定的说这个地址是某个频繁使用的子程序的入口。从定位的入口出发,我继续跟踪所有的跳转和函数调用,等等。按这种方法,我可能准确定位99.9% 的命令。但是,某些字节并不在这个链条上。我再用20多种高效的启发方法(最简单的方法,比如“直接访问前64K内存是不允许的,像在MOV [0],EAX中”)来探测他们
有时,分析器在您感兴趣的地方分析错误。有两种解决方法:或者从选中的部分移除分析(快捷键退格键),这样 OllyDbg 将使用默认的解码(反汇编)方式;或者设置
解码提示[decoding hints]并重新分析。注意:在某些情况下,当分析器认为您的提示是不合适的,或者有冲突,则可能忽略您的设置。
探测程序的函数过程也很简单。在分析器眼中看来,程序只是一个连绵不断的代码,从一个入口开始,可能达到(至少从理论上)所有的命令(除了NOP以及类似的用于填充间隙的命令)。您可能指定三个识别级别。严格的函数过程要求有准确的一个入口,并且至少有一个返回。在启发级别下,分析器只要求过程有一个入口。而如果您选择模糊模式,差不多连贯的代码都会被识别为单独的过程。现代编译器进行全局代码优化,有可能把一个过程分成几个部份。在这种情况下,模糊模式非常有用。但是也会误识别的机率也就更高。
同样地,循环是一个封闭的连续的命令序列,并有一个到开始处的跳转作为一个入口,还有若干个出口。循环与高级操作命令 do, while 和 for 相对应。OllyDbg 能够识别任何复杂的嵌套循环。他们会在反汇编栏[Disassembly]中用长而粗括号标记。如果入口不是循环的第一个命令,OllyDbg会用一个小三角进行标记。
为了实现一个转换[switch], 许多编译器,读取转换变量[switch variable]到寄存器中,然后减它,像如下的代码序列:
MOV EDX,
SUB EDX,100
JB DEFAULTCASE
JE CASE100 ; Case 100
DEC EDX
JNE DEFAULTCASE
... ; Case 101
这个序列可能还包含一到两阶的转换表、直接比较、优化和其他元素。如果在比较或跳转的很深处,这就很难知道哪是一个分支[Case]。OllyDbg 会帮助您,它会标记所有的分支,包括默认的,甚至尝试分析每个分支的含义,如'A'、WM_PAINT 或者 EXCEPTION_ACCESS_VIOLATION。如果命令序列没有修改寄存器(也就是仅仅由比较组成),那么这可能不是转换,而很有可能是选择嵌套:
if (i==0) {...}
else if (i==5) {...}
else if (i==10) {...}
如果需要OllyDbg将选择嵌套解码成选择语句,请在分析1[Analysis1]中设置相关选项。
OllyDbg包含多达1900条常用API函数,这些都作为内部预处理资源。这个列表包含了KERNEL32, GDI32, USER32, ADVAPI32, COMDLG32, SHELL32, VERSION, SHLWAPI, COMCTL32, WINSOCK, WS2_32 和 MSVCRT。您可以添加自己的函数描述[add your own descriptions]。如果分析器遇到的调用,使用了已知的函数名(或者跳转到这样的函数),它将在调用之前立即解码PUSH命令。因此,您只需略微一看就能明白函数调用的含义。OllyDbg还包含了大约400多种的标准C函数。如果您有原始的库文件,我推荐您在分析前扫描目标文件。这样OllyDbg将能解码这些C函数的参数。
如果选项“猜测未知函数的参数个数”开启,分析器将会决定这个调用函数过程使用的长度为双字的参数个数。并且标记他们为参数1[Arg1],参数2[ Arg2],等等。注意:无论如何,寄存器参数是无法识别的,所以不会增加参数的数目。分析器使用了一种比较安全的方法。例如,它不能识别的没有参数的函数过程,或者该过程POP
命令直接做返回前的寄存器恢复,而不销毁参数。然而,识别出来的函数参数数目通常非常高,这大大加大了代码的可读性。
分析器能够跟踪整型寄存器的内容。现代优化编译器,特别是奔腾系列,频繁地使用寄存器读取常量和地址,或使用尽量少的使用内存。如果某个常量读取到寄存器中,分析器会注意它,并尝试解码函数和其参数。分析器还能完成简单的算术计算,甚至可以跟踪压栈和出栈。
分析器不能区分不同类的名称[different kinds of names]. 。如果您将某些函数指定为已知的名称,OllyDbg将会解码所有到该地址的调用。这是几个预定义的特殊名称
WinMain, DllEntryPoint and WinProc。您可能使用这些标签标记主程序、DLL的的入口以及窗口过程(注意:OllyDbg不检查用户自定义的标签是否唯一)。另外,假定预定义参数assume predefined arguments是一种更好的方法
不幸的是,没有一般规则能够做到100%的准确分析。在某些情况下,例如当模块包含了P-Code或代码段中包换了大量的数据,分析器可能将一些数据解释成代码。如果统计分析显示代码部分很可能是压缩包或者经过加密了,分析器会发出警告。如果您想使用Hit跟踪[Hit trace],我建议您不要使用模糊分析[fuzzy analysis],因为设置断点的地方可能正是数据部分。
自解压文件[Self-extractable files] 通常有一个自提取器,在“正式”代码段之外。如果您选择自解压选项[SFX option]中的“扩展代码段,包含提取器[Extend code section to include self-extractor]”,OllyDbg将会扩展代码段,形式上允许分析它,并可以使用Hit跟踪[Hit] trace和Run跟踪[Run trace]。
2005-9-6 15:27 乾龙五,Object扫描器[Object scanner]
扫描器将特定的目标文件或者目标库(包括OMF和COFF两种格式),提取出代码段,然后将这些段定位在当前模块的代码节[Code section]中.如果段定位好了,扫描器将从目标文件中的调试信息提取名称(也就是所谓的库标签[library labels])。这极大的增加了代码与数据的可读性.
扫描器并不会对已识别的目标文件进行标签匹配,所以它不能识别非常小或相似的函数(比如:两个函数只是在重定位有区别)。因此要经常检查扫描器发送到登陆窗口的警告列表!六,Implib扫描器 [Implib scanner]
某些DLL的输出符号仅仅是一个序号。许多符号都是井号加数字(比如:MFC42.#1003),这非常不便于理解。幸运的是,软件零售商提供了输入连接库(implibs),它与序号符号名相关。
使用implib扫描器的方法:从主菜单中选择调试[Debug]|选择输入链接库[Select import libraries]。当您加载应用程序时,OllyDbg会读取链接库并从内置表格[
internal tables]中提取符号名。每次遇到序号符号,而对应的链接库已经注册到OllyDbg中时,这个序号符号会被替换。七,如何开始调试[How to start debugging session]
最简单的方法是:运行 OllyDbg,点击菜单上的文件[File]|打开[Open],选择您想调试的程序。如果程序需要命令行参数,您可以在对话框底部的输入栏中,输入参数或者选择以前调试时输入过的一条参数。
OllyDbg 能够调试独立的DLL[stand-alone DLLs]。在这种情况下,OllyDbg 会创建并运行一个小的应用程序来加载链接库并根据您的需要调用输出函数。
如果您想重新启动上一次调试的程序,只要按一下 Ctrl+F2(这是重启程序的快捷键),这样 OllyDbg 会以同样的参数运行这个程序。另一种做法是在菜单中选择文件[File],从历史列表中选择程序。您也可以在 Windows 资源管理器中将可执行文件或 DLL 文件拖拽到 OllyDbg 中。
当然,您可以在 OllyDbg 启动时,运行指定带有运行参数的被调试程序。例如:您可以在桌面创建一个 OllyDbg 的快捷方式,右击并选择“属性”,在“快捷方式”中的“目标”中添加调试的程序的全路径。这样,您每次双击快捷方式时,OllyDbg 将自动运行被调试程序。注意:DLL文件不支持这种方式。
您可以把正在运行的进程挂接到 OllyDbg 中。在菜单中打开 文件[File]|挂接[Attach],从进程列表中选择要挂接的进程。注意:在您关闭 OllyDbg 的同时,这个进程也会被关闭。不要挂接系统进程,否则可能会导致整个操作系统的崩溃。(事实上在大多数情况下,操作系统禁止您挂接敏感进程)。
OllyDbg 可以作为即时[just-in-time]调试器。这需要在系统注册表中注册。在菜单中选择选项[Options]|即时调试[Just-in-time debugging] 并在弹出的对话框中单击按钮“设置OllyDbg为即时调试器”[Make OllyDbg just-in-time debugger]。今后,如果某个应用程序发生了非法操作,系统将提示您是否用 OllyDbg 调试这个程序。操作系统会启动 OllyDbg 并直接停在发生异常的地方。如果您选择了“挂接时不询问”[attaching without confirmation],则在即时调试时OllyDbg不会弹出询问对话框。如果想恢复成以前的即时调试器[Restore old just-in-time debuger],按相应的按钮即可。
另一种方法是把 OllyDbg 添加到与可执行文件关联的快捷菜单中(这个想法是 Jochen Gerster 提出的)。在主菜单中,选择选项[Options]|添加到资源管理器中[Add to Explorer]。以后您可以在所有的文件列表中,右击可执行文件或DLL,在快捷菜单中选择OllyDbg。这个功能会创建四个注册表键值:
HKEY_CLASSES_ROOT\exefile\shell\Open with OllyDbg
HKEY_CLASSES_ROOT\exefile\shell\Open with OllyDbg\command
HKEY_CLASSES_ROOT\dllfile\shell\Open with OllyDbg
HKEY_CLASSES_ROOT\dllfile\shell\Open with OllyDbg\command
OllyDbg能够调试控制台程序(基于文字的)。
OllyDbg不能调试.NET应用程序。.NET程序是由微软的中间语言这种伪指令组成的,或是on-the-fly to native ?6 commands编译的。
注意:如果您运行的是Windows NT、2000 或XP操作系统,您应该拥有管理员权限以
八,CPU 窗口[CPU window]
对于用户来说,CPU窗口在OllyDbg中是最重要的窗口。您调试自己程序的绝大部分操作都要在这个窗口中进行。它包括以下五个面板(这五个面板的大小都是可以调节的):
反汇编[Disassembler]
信息[Information]
数据[Dump]
寄存器[Registers]
栈[Stack]
按TAB键,可以切换到下一个CPU面板中(顺时针方向)。
按Shift+TAB,可以切换到前一个CPU面板(逆时针方向)。九,断点[Breakpoints]
OllyDbg支持数种不同类型的断点:
- 一般断点[Ordinary breakpoint], 将您想中断的命令的第一个字节,用一个特殊命令INT3(调试器陷阱)来替代。您可以在反汇编窗口中选中要设断点的指令行并按下 F2 键就可以设定一个此类型的断点。也可以在快捷菜单中设置。再次按下 F2 键时,断点将被删除。注意,程序将在设断指令被执行之前中断下来。
INT3断点的设置数量是没有限制的。当您关闭被调试程序或者调试器的时候,OllyDbg将自动把这些断点保存到硬盘中,永远不要试图在数据段或者指令的中间设置这种断点,如果您试图在代码段以外设置断点,OllyDbg将会警告。您可以在安全选项[Security options]中永远关闭这个提示,在某些情况下调试器会插入自带的临时INT3
断点。
- 条件断点[Conditional breakpoint] (快捷键 Shift+F2) 是一个带有条件表达式的普通INT3断点。当调试器遇到这类断点时,它将计算表达式的值,如果结果非零或者表达式无效,将暂停被调试程序,当然,由条件为假的断点引起的开销是非常高的(主要归因于操作系统的反应时间)。在Windows NT、奔腾Ⅱ/450处理器环境下
OllyDbg每秒最多处理2500个条件为假的断点。条件断点的一个典型使用情况就是在Windows消息上设置断点(比如 WM_PAINT)。为此,您可以将伪变量 MSG 同适当的参数说明联合使用。如果窗口被激活,参考一下后面的消息断点描述。
- 条件记录断点 [Conditional logging breakpoint] (Shift+F4)是一种条件断点,每当遇到此类断点或者满足条件时,它将记录已知函数表达式或参数的值。例如,您可以在一些窗口过程函数上设置记录断点并列出对该函数的所有调用。或者只对接收到的WM_COMMAND消息标识符设断,或者对创建文件的函数(CreateFile)设断,并且记录以只读方式打开的文件名等,记录断点和条件断点速度相当,并且从记录窗口中浏览上百条消息要比按上百次F9轻松的多,您可以为表达式选择一个预先定义好的解释说明。
您可以设置通过的次数 - 每次符合暂停条件时,计数器就会减一。如果通过计数在减一前,不等于零,OllyDbg就会继续执行。如果一个循环执行100次(十进制),在循环体内设置一个断点,并设置通过次数为99(十进制)。OllyDbg将会在最后一次执行循环体时暂停。
另外,条件记录断点允许您传递一个或多个命令给插件[plugins]。例如,您需要使用命令行插件改变一个寄存器的内容,然后继续执行程序。
- 消息断点[Message breakpoint]和条件记录断点基本相同,除了OllyDbg会自动产生一个条件,这个条件允许在窗口过程的入口处设置某些消息(比如WM_PSINT)断点,您可以在窗口[Windows]中设置它。
- 跟踪断点[Trace breakpoint] 是在每个选中命令上设置的一种特殊的INT3断点。如果您设置了Hit跟踪[hit trace] ,断点会在命令执行后移除,并在该地址处做一个标记。如果您使用的是Run跟踪[run trace] ,OllyDbg会添加跟踪数据记录并且断点仍然是保持激活状态。
- 内存断点[Memory breakpoint] OllyDbg每一时刻只允许有一个内存断点。您可以在反汇编窗口、CPU窗口、数据窗口中选择一部分内存,然后使用快捷菜单设置内存断点。如果有以前的内存断点,将被自动删除。您有两个选择:在内存访问(读,写,执行)时中断,或内存写入时中断。设置此类断点时,OllyDbg将会改变所选部分的内存块的属性。在与80x86兼容的处理器上将会有4096字节的内存被分配并保护起来。即使您仅仅选择了一个字节,OllyDbg 也会将整个内存块都保护起来。这将会引起大量的错误警告,请小心使用此类断点。某些系统函数(特别是在Windows95/98下)在访问受保护的内存时不但不会产生调试事件反而会造成被调试程序的崩溃。
- 硬断点[Hardware breakpoint](仅在Windows ME,NT或2000下可用)在80x86兼容的处理器上,允许您设置4个硬件断点。和内存断点不同,硬件断点并不会降低执行速度,但是最多只能覆盖四个字节。在单步执行或者跟踪代码时,OllyDbg能够使用硬断点代替INT3断点。
- 内存访问一次性断点[Single-shot break on memory access] (仅在Windows NT或2000下可用)。您可以通过内存窗口的快捷菜单(或按F2),对整个内存块设置该类断点。当您想捕捉调用或返回到某个模块时,该类断点就显得特别有用。中断发生以后,断点将被删除。
- 暂停Run跟踪[Run trace pause] (快捷键:Ctrl+T)是在每一步Run跟踪[run trace] 时都要检查的一个条件集.您可以在EIP进入某个范围或超出某个范围时暂停,某个条件为真时暂停,或者命令与指定的模式匹配时暂停,或者当命令可疑的时候暂停。注意,这一选择会极大的(高达20%)降低Run跟踪的速度。
OllyDbg也可以在一些调试事件[debugging events]上暂停程序执行。比如加载或卸载DLL,启动或终止线程,或者程序发出调试字符串的时候。
10,数据窗口[Dump]
数据窗口用于显示内存或文件的内容。您可以从以下预处理格式[predefined formats]中选择一种显示方式:字节[byte]、文本[text]、整数[integer]、浮点数[float
]、地址[address],反汇编[disassembly]、 PE头[PE Header]。
所有的dump窗口支持备份[backup]、搜索和编辑操作。CPU 窗口[CPU window]的Dump面板允许您对可执行代码的数据和可执行文件(.exe,或.dll)的内存映射做如下操作:定义标签[labels]、设置 内存断点[memory breakpoints], 查找参考[references]。数据菜单[Dump menu]只显示与选中部分相关的命令。
如果 备份[backup]可用,则单击第一个列标题栏,会在地址[Address]/备份[Backup] 两种显示模式之间切换。点击其他列标题栏,会改变Dump模式。
像反汇编窗口一样,数据窗口也保存了大量查看内存地址的历史记录。您可以通过“+”和“-”键来访问您过去查看过的数据地址空间。
要翻动一字节的数据,可以按住Ctrl l键并按上/下方向键。
可执行模块窗口[Executable modules window]
可执行模块窗口(快捷键:Alt+E)列出了当前被调试进程加载的所有可执行模块。它也显示了很多有用的信息,比如模块大小、入口地址、模块版本、以及可执行文件路径等。一些信息,如以十进制显示的模块大小、入口地址的符号名、是否为系统模块等,通常是被隐藏的。如果想看,可以增加相应栏的宽度。快捷菜单支持以下操作:
刷新[Actualize] - 重新扫描模块并去除对新加载模块的高亮显示。在大多数情况下,OllyDbg会自动完成该操作。
查看内存[View memory] - 打开内存窗口,并定位到属于该模块镜像的第一个内存块处。
在CPU窗口中查看代码[View code in CPU] (快捷键:回车键) - 在反汇编窗口中显示模块的可执行代码。
跟进到入口[Follow entry] - 在反汇编窗口中跟进到模块的入口处。
在CPU窗口中查看数据[Dump data in CPU] -在CPU窗口的数据面板中显示模块的数据段。块代码段。
显示名称[View names] (快捷键:Ctrl+N) -显示当前模块定义或使用的全部名称[names](包括输出表、引入表、链接库、用户自定义)。
标记为系统DLL[Mark as system DLL],
标记为非系统DLL[Mark as non-system DLL] - 将选中模块标记为系统或非系统属性。如果设置为系统属性,则在Run跟踪[Run trace] 时会直接执行(不进行跟踪)这个模块,从而大大加快跟踪速度。默认情况下,所有驻留在系统目录(通常在Windows 95/98下为c:\windows\system ,在WinNT/2000/XP下为c:\winnt\system32)的模块都认为是系统模块。
立即更新.udd文件[Update .udd file now] -向文件“.udd”写入模块相关的全部数据,udd文件保存了在调试期间设置的断点、标签、注释、监视、分析等信息。当模块卸载时OllyDbg会自动创建.udd文件。
查看可执行文件[View executable file] - 显示可执行文件的全部内容。
查看全部资源[View all resources] - 以列表形式显示模块定义的全部资源,并带有一个简短信息。OllyDbg并不把资源当作单独实体来支持。您可以提取[Dump]并以二进制的形式进行编辑。
查看资源字符串[View resource strings] -以列表形式显示资源字符串及其标识符。
查看Run跟踪的统计[View run trace profile] - 在此模块中计算统计[profile] 。相关信息:Run跟踪[Run trace].
分析全部模块[Analyze all modules] -允许同时分析全部模块。分析将从代码中提取大量的有用信息;代码经过分析后再进行调试,通常会非常快并且可靠。
鼠标双击某一行,将会在反汇编窗口中显示模块的执行代码。十,内存映射窗口[Memory map window]
内存映射窗口显示了被调试程序分配的所有内存块。因为没有标准的方法来完成这项任务,所以OllyDbg可能会把一个大的内存块分成几个部分。然而,在大多数情况下,并非一定要精确处理。如果想查看由应用程序通过调用GlobalAlloc()和LocalAlloc()等申请的内存块列表,请使用堆列表[Heap list]。
如果内存块是可执行模块的一个节,OllyDbg则会报告这个内存块所包含的数据类型:代码、数据、资源等。
Windows95/98是和WindowsNT/2000是有一些区别的。在Windows95/98下,OllyDbg是不能显示被映射文件的名称的。另外,Windows95/98不允许的访存类型为读和写,然而,在WindowsNT/2000下,OllyDbg却有拥有更多功能,包括执行访问,写复制[copy-on-write]以及监视标志位。OllyDbg忽略写复制[copy-on-write]属性。
如果OllyDbg发现程序分配了新内存或者重新分配了已经存在的内存块,它将在内存映射窗口中高亮显示相应的记录,去掉高亮度显示,可以选择快捷菜单中的刷新[
Actualize]项。
您可以按Alt+M来调用内存窗口。
以下是快捷菜单中可以选择的菜单项:
刷新[Actualize] - 更新已分配内存的列表并去除对新内存块的高亮显示。
在反汇编窗口中查看[View in Disassembler] -在反汇编窗口中查看:在反汇编窗口中打开内存块,这一选项仅在某些模块的内存块中包含可执行代码或者自解压器时可用。
在CPU数据窗口中查看[Dump in CPU] - 在CPU的数据窗口中显示内存块的内容。
数据窗口[Dump] - 在单独窗口中显示内存块内容。如果内存块的类型已知,则OllyDbg会自动选择显示格式。
查看全部资源[View all resources] - 如果内存块包含资源数据,则列出所有资源及相关数据。OllyDbg并不把资源当作单独实体来支持。您可以显示其数据并以二进制的形式进行编辑。
查看资源字符串[View resource strings] - 如果内存块包含资源数据,则列出全部资源字符串及其标识符。
搜索[Search] - 允许搜索所有的内存块,从选择处开始,搜索匹配的二进制串。如果找到,则OllyDbg将显示该内存块。内存映像窗口和数据窗口共享同一种搜索模式,所以您可以在弹出的数据窗口中立即继续搜索该二进制串出现的下一位置。按Esc键可以关闭数据窗口。
搜索下一个[Search next](快捷键:Ctrl+L) - 继续上次搜索。
设置访问中断[Set break-on-access] (快捷键:F2,仅在WindowsNT/2000下可用) - 保护整个内存块。当中断发生后OllyDbg暂停被调试程序并清除断点。这类断点在您想捕捉调用或返回到某个模块的时候特别有用。
清除访问中断[Remove break-on-access] (快捷键:F2) - 从内存块中清除访问中断保护。
设置内存访问断点[Set memory breakpoint on access] - 在整个内存块上设置断点,每当该内存块被访问时程序都将中断。OllyDbg只支持一个内存访问断点。在
Windows95/98下,当系统程序访问含有内存断点的内存块时,可能会导致所被调试程序崩溃,因此,不到万不得已,请不要设置这种断点。
设置内存写入断点[Set memory breakpoint on write] - 在整个内存块上设置断点,每当该内存块被写入数据时程序都将中断。在Windows95/98下,当系统程序访问含有内存断点的内存块时,可能会导致所被调试程序崩溃,因此,不到万不得已,请不要设置这种断点。
清除内存断点[Remove memory breakpoint] - 清除内存断点。
清除自解压内存断点[Remove SFX memory breakpoint] - 停止搜索自解压程序[self-extractable (SFX) program]的真实入口。这个搜索使用了特殊类型的内存断点。
访问设置[Set access] -设置整个内存块的保护属性,可选择的有:
禁止访问[No access]
只读[Read only]
读/写[Read/write]
执行[Execute]
执行/读[Execute/read]
完全访问[Full access]
复制到剪切板[Copy to clipboard]
整行[Whole line] -以多行文本(包括解释)的方式把所选记录复制到剪切板,如果复制时想排除某些列,可将该列的宽度置为最小(该栏剩余的边框将变灰)。
整个表格[Whole table] -以多行文本的方式将整个内存映像信息复制到剪切板,该文本的第一行为窗口标题("内存映射[Memory map]"), 第二行为列标题栏,后面几行的内容为内存数据记录。复制将保持列的宽度。如果复制时想排除某些列,可将该列的宽度置为最小(该栏剩余的边框将变灰)。十一,监视与监察器[Watches and inspectors]
监视[Watch] 窗口包含若干个表达式[expressions]。它在第二列里显示这些表达式的值。OllyDbg 会把这些表达式保存到主模块的.UDD文件中,因此它们在下一次调试时同样有效。
监察器[inspector]是显示若干变量、1/2维数组或是选定项目结构数组[selected items of array of structures]的独立窗口。它的表达式与监视窗口中的基本相同,只是多包含了两个参数:%A和%B。您可以指定这两个参数的界限,OllyDbg 将会用所有可能的组合代替表达式中的%A和%B。从0开始一直到界限(不包含界限),并在表格中显示结果。参数%B(列数)的界限不能超过16。
例如,如果您指定了表达式%A+%B,并且限定%A和%B的上限为3,您将获得如下的表格:
十三,线程[Threads]
OllyDbg 以简单而有效的线程管理为特色。如果您单步调试、跟踪、执行到返回或者执行到所选,则线程管理器将停止除当前线程以外的所有线程。即使当前线程被挂起,它也会将其恢复。在这种情况下,如果您手动挂起或者恢复线程,动作将被延期。如果您运行被调试的应用程序,OllyDbg将恢复最初的线程状态。(从调试器的角度来看,Hit跟踪[hit trace]和自由运行是等效的)。
依据这种方案,线程窗口可能会有如下五种线程状态:
激活[Active] - 线程运行中,或被调试信息暂停t
挂起[Suspended] - 线程被挂起
跟踪[Traced] - 线程被挂起,但OllyDbg正在单步跟踪此线程
暂停[Paused] - 线程是活动的,但OllyDbg临时将其挂起,并在跟踪其它的线程
结束[Finished] - 线程结束
.
线程窗口同时也显示了最后的线程错误(GetlastError函数的返回值)并计算该线程以用户模式和系统模式(仅NT/2000/XP)运行的时间。线程窗口还会高亮主线程的标识符。
以下在快捷菜单中可用:
刷新[Actualize] - 标记所有线程为旧的。
挂起[Suspend] - 挂起线程。
恢复[Resume] - 恢复先前挂起的线程。
设置优先级[Set priority] - 调整进程中线程的优先级。以下选项可用:
空闲[Idle] - 进程中线程的最低优先级
最低[Lowest]
低[Low]
标准[Normal]
高[High]
最高[Highest]
时间临界[Time critical] - 最高优先级
在CPU窗口打开[Open in CPU](双击)- 在CPU窗口中显示所选线程的当前状态。十四,复制到剪切板[Copy to clipboard]
整行[Whole line] -全部行--以多行文本的形式并带注释将所选记录复制到剪切板。如果在复制时想排除某个栏目,可以将该栏的宽度置为最小(栏目的残留部分将变灰)。
整个表格[Whole table] - 整个表格--以多行文本的形式将整个内存映象复制到剪切板,该文本的第一行包含窗口标题(“内存映射[Memory map]”),第二行是栏目标题,所有后继行是内存数据记录。复制将保持栏目的宽度。如果在复制时想排除某些栏目,可以将该栏的宽度置为最小(栏目的残留部分将变灰)。十五,调用栈[Call stack]
调用栈窗口(快捷键:Alt+K)根据选定线程的栈,尝试反向跟踪函数调用顺序并将其显示出来,同时包含被调用函数的已知的或隐含的参数。如果调用函数创建了标准的堆栈框架(PUSH EBP; MOV EBP,ESP),则这个任务非常容易完成。现代的优化编译器并不会为栈框架而操心,所以OllyDbg另辟蹊径,采用了一个变通的办法。例如,跟踪代码到下一个返回处,并计算其中全部的入栈、出栈,及 ESP 的修改。如果不成功,则尝试另外一种办法,这个办法风险更大,速度也更慢:移动栈,搜索所有可能的返回地址,并检查这个地址是否被先前的已分析的命令调用。如果还不行,则会采用启发式搜索。栈移动[Stack Walk]可能会非常慢。OllyDbg 仅在调用栈窗口打开时才会使用。
调用栈窗口包含5个栏目:地址[Address]、栈[Stack]、过程[Procedure],调用来自[Called from],框架[Frame]。地址[Adress]栏包含栈地址,栈[Stack]
栏显示了相应的返回地址或参数值。
函数[Procedure](或 函数/参数[Procedure / arguments])显示了被调用函数的地址,在某些情况下,OllyDbg并不能保证该地址是正确的并会添加如下标记之一:
? 找到的入口点不可靠
可能[Maybe] OllyDbg无法找到精确的入口点,报告的地址是用启发式算法猜测的。
包含[Includes] OllyDbg无法找到入口点,仅知道该函数包含显示的地址
通过按例标题栏上的按钮或从菜单中选择“隐藏/显示参数[Hide/Show arguments]”,可以在显示或隐藏函数的参数之间切换。
调用来自[Called from]用于显示调用该函数的命令地址。最后一栏是框架[Frame]这一栏默认是隐藏的,如果框架指针的值(寄存器EBP)已知的话,则该栏用于显示这个值。
当调用函数经过分析[analyzed].后,栈移动会更可靠并且迅速。十六,调用树[Call tree]
调用树(快捷键:在反汇编窗口中Ctrl+K)利用分析[Analysis]的结果来找出指定函数过程直接或间接调用的函数列表,同时列出指定函数过程被调用的地址。为了避免由此可能造成的副作用。调用树会判断选定函数是否明确地是递归的。“明确地”意味着它不会跟踪目标未知的调用,比如CALL EAX。如果函数过程中有未知调用,调用树将会添加标记“未知目标”。
某些函数调用将会添加如下注释之一:
叶子[Leaf] 不调用其他函数
纯函数[Pure] 不调用函数,不会产生副作用
单返回[RETN] 只有一个RETN 命令
系统[Sys] 系统动态链接库中的函数。系统动态链接库定义为保存在系统目录下的动态链接库。
如果想在调用树上移动,可以双击“被调用[Called from]”或“调用/直接调用[Calls/Calls directly]”两栏中的地址。调用树窗口保存了移动记录(快捷键“-”和“+”)。
如果被调试的程序包含几个模块,推荐您分析所有模块。Call tree 不会试图处理系统函数。十七,选项[Options]
外观选项[Appearance options]
常规[General]
默认[Defaults]
对话框[Dialogs]
目录[Directories]
字体[Fonts]
颜色[Colours]
代码高亮[Code highlighting]
调试选项[Debugging options] (Alt+O)
安全[Security]
调试[Debug]
事件[Events]
异常[Exceptions]
跟踪[Trace]
自解压[SFX]
字符串[Strings]
地址[Addresses]
命令[Commands]
反汇编[Disasm]
CPU
寄存器[Registers]
栈[Stack]
分析1[Analysis 1]
分析2[Analysis 2]
分析3[Analysis 3]
即时调试[Just-in-time debugging]
添加到资源管理器[Add to Explorer]十八,搜索[Search]
OllyDbg 允许您使用以下的搜索方式:
符号名(标签)[Symbolic name (label)]
二进制串[binary string]
常量[constant]
命令[command]
命令序列[sequence of commands]
模块间调用[intermodular calls]
修改过的命令或数据[modified command or data]
自定义标签[user-defined label]
自定义注释[user-defined comment
文本字符串[text string]
Run跟踪的记录[record in run trace]
参考命令[referencing commands]
十九,自解压文件[Self-extracting (SFX) files]
自解压文件由提取程序和压缩的原程序两部分组成。当遇到自解压文件(SFX)文件时,我们通常希望跳过解压部分,而直接跳到原始程序的入口(真正的入口)。
OllyDbg 包含了几个便于完成这一任务的功能。
通常提取程序的加载地址都在执行代码之外。在这种情况下,OllyDbg 将这类文件均视作为自解压文件(SFX)。
当自解压选项[SFX options]要求跟踪真正入口时,OllyDbg 在整个代码节[Code section]设置内存断点,最初这里是空的,或者只包含压缩数据。当程序试图执行某个在这个保护区域的命令,而这些命令不是 RET 和 JMP 时,OllyDbg 会报告真正的入口。这就是提取工作的原理。
上面的方法非常慢。有另外一种比较快的方法。每次读取数据发生异常时,OllyDbg 使这个4K内存区域变为可读,而使原先可读的区域变为无效。而每次发生写数据异常时,
OllyDbg 使这个区域变为可写,而使原先可写的区域变为无效。当程序执行在保留的保护区域中的指令时,OllyDbg 报告真正的入口。但是,当真正的入口点在可读或可写区域内部时,报告的地址就可能有误。
您可以纠正入口位置,选择新的入口,从反汇编窗口的快捷菜单中选择“断点[Breakpoint]|设置真正的自解压入口[Set real SFX entry here]”。如果相应的SFX选项是开启的,OllyDbg下次可以迅速而可靠的跳过自提取程序。
注意:OllyDbg 在跟踪采取了保护或者反调试技术的解压程序时通常会失败。 二十,单步执行与自动执行[Step-by-step execution and animation]
您可以通过按 F7(单步步入)或 F8(单步步过),对程序进行单步调试。这两个单步执行操作的主要区别在于:如果当前的命令是一个子函数,按F7,将会进入子函数,并停在子函数的第一条命令上;而按 F8,将会一次运行完这个子函数。如果您单步步过的子函数中含有断点或其他调试事件,执行将会被暂停,但 OllyDbg 会在子函数的后一条命令上,自动下一个断点,而这个断点您迟早会碰到。
如果被调试程序停在异常上,您可以跳过它,并转到被调试程序建立的句柄处。只需简单的 Shift 键和任何一个单步命令。
如果需要连续按F7、F8键上百次,您可以使用自动执行(Ctrl+F7或者Ctrl+F8)功能。在这种情况下,OllyDbg 将自动重复F7或者F8操作,并且实时更新所有的窗口。这个过程会在下面情况停止:
- 按 Esc 键或发出任何单步命令
- OllyDbg 遇到断点
- 被调试程序发生异常
使用“+”和“-”按键,可以回朔以前的执行历史[execution history].
注意:当执行停止时 OllyDbg 将会刷新大部分窗口。如果动态执行过程非常慢,可以尝试关掉或最小化没有用的窗口。
另外,更快捷的找到以前执行指令的办法是Run跟踪[run trace]。它将创建一个执行协议并告知您指定指令的执行时间和次数二一,Hit跟踪[Hit trace]
上一篇:如何正确选择美国虚拟主机下一篇:CISCO防火墙
业务联系电话:0592-5908028
业务联系QQ:173723134
业务联系QQ:173723134