[原创]ollydbg中文版帮助资料[doc]-软件逆向-看雪-安全社区

[原创]ollydbg中文版帮助资料[doc]

发表于:

2006-1-14 17:46

24199

[原创]ollydbg中文版帮助资料[doc]

qdxxw

2006-1-14 17:46

24199

我在学习破解的时候,由于初学ollydbg,很不熟练,需要熟练学习ollydbg的使用方法,可是,原来中文版help文件只能在电脑上看,很不方便,我希望打印出来随时研究,因此,我进行了整理,提供给大家,如果您觉得需要,可以复制出来然后打印

声明:原版全文,如果我侵犯了您的权利,请来信告诉我或者请帮主锁定

由于论坛限制字数,分几次提供

$#K{bmc bm0.WMF}OllyDbg v1.10

概述

什么是 OllyDbg

1.10版新增的功能

官方资料

法律条款

隐私和安全

注册

技术支持

关于汉化

OllyDbg 汉化

TT小组

准备工作

系统要求

安装

组件

一般原理

反汇编器

汇编器

分析器

Object 扫描器

Implib 扫描器

OllyDbg的使用

如何开始调试 [How to start debugging session]

CPU 窗口 [CPU window]

断点 [Breakpoints]

数据 [Dump]

模块 [Modules]

内存映射 [Memory map]

窗口 [Windows]

监视与监察器 [Watches and inspectors]

线程 [Threads]

调用栈 [Call stack]

调用树 [Call tree]

选项 [Options]

搜索 [Search]

自解压文件(SFX) [Self-extracting(SFX) files]

单步执行 [Step-by-step execution]

Hit 跟踪 [Hit trace]

Run 跟踪 [Run trace]

快捷键 [Shortcuts]

插件 [Plugins]

技巧提示 [Tips and tricks]

其他功能

调试独立的DLL [Debugging of stand-alone DLLs]

解码提示 [Decoding hints]

表达式 [Expressions]

自定义函数 [Custom function descriptions]

问题和致歉申明

已知的bugs和问题

致歉申明

OllyDbg 2000-2004 Oleh Yuschuk, 保留以下所有权利:

OllyDbg(包括相关附件及这个帮助文件)中使用的商标名,产品名,注册商标以及买卖双方名称等。如若转载请保留原文的完整性。

$#K什么是 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 能成为非常方便的调试器!

$#K1.10新增功能[What's new in version 1.10]

1.10版是最终版本。这个工程已经结束,我不再作开发了。但不用用担心:不久就会推出全新打造的OllyDbg 2.00!

・ 最重要的新功能:

- 调试单独的DLL(不需要主程序);

- SEH 链窗口;

- 分析提示,以帮助分析器解码不明确的代码片断;

- 支持记录断点和跟踪条件,向OllyDbg传递一个计数器,这个计数器告诉 OllyDbg 在断点执行了 n 次或在 Run 跟踪缓冲区中记录了 n 条命令以后暂停执行

- 中断时,条件记录断点可以传递给命令行文本给插件,来进行自动控制;

- 您可以标记 DLL 为系统的或者不是系统的,这在 Run 跟踪时需要跳过系统的DLL时非常有用;

- 新的安全选项“保存模块外的用户数据到主 .udd 文件”以允许您保存不属于任何特定模块和代码的断点或注释;

- Run 跟踪可以有选择的显示或记录文件修改标志;

- 参数最大串长,从1024增加到4096个字符;

- 您可以在单步跟踪中指定当前命令之后保持几条命令可见。

・ 新的插件函数:

- 当被调试程序暂停时,都会调用回调用函数 ODBG_Paused(int reason,t_reg *registers) 或其的扩展版本 ODBG_Pausedex(int reasonex,int extmode,reg *registers,DEBUG_EVENT *debugevent);

- 当应用程序因条件断点暂停,并且断点包含有传递给插件的命令,都会调用回调函数 ODBG_Plugincmd(int reason,t_reg *registers,char *cmd).

- 函数Function Settracecount(ulong count) 用于设置命令执行多少次后Run跟踪暂停;

- 函数 Settracepauseoncommands(char *cmdset) s用于指定暂停的命令集;

- 函数 Getbreakpointtypecount(ulong addr,ulong *passcount) 和 Setbreakpointext(ulong addr,ulong type,char cmd,ulong passcount) 支持传递条件断点中的计数器;

- 函数 Listmemory() 用于实现内存块列表。

・ Bug修正:

- 寄存器菜单选项“复制所有的寄存器到剪切板[Copy all registers to clipboard]”现在也可以复制 EAX了;

- 在不符合区块对齐标准地代码中,分析器和显示的代码不同步,因此单击某些行时,会选中不同的行;

- 菜单“跟进到数据窗口[Follow in Dump]” 可以显示更直观的选项,假如操作数之一隐式地指向堆栈(如PUSH);

- OllyDbg 现在可以正确地反汇编两个Win95驱动使用的命令 VxDCall 和 VxDJump ,但汇编它们为相同的命令。在用户要使用这一伪命令的极端情况下(这是一种近乎不可能的情况), 用户必须设置二进制位0x00008000来区分 Call 和 Jump;

- OllyDbg 接受无用命令像 REP STOS FWORD [EDI] 并将其编译为 REP STOS DWORD [EDI];

- 在新加载模块时,名称窗口有时会丢失内容;

- 汇编器支持 IMUL命令的简单形式。 IMUL reg,const (反汇编为 IMUL reg,reg,const);

- 反汇编器使用地址大小代替操作数大小,来解码偏移大小(JMP FAR ssss:oooooooo);

- 在反汇编窗口中的注释栏或信息面板的tab显示为一个长方形。现在Tab会显示为8个空格;

- ARPL 的操作数被解码32位大小(正确的解码为:ARPL r/m16,r16);

- OllyDbg 现在可以在多监视配置下正常工作(但我不能肯定);

- 2字节 INT 3 (CD 03) 处理错误;

- “句柄[Handle]”栏从线程窗口中移除。该栏错误显示 OllyDbg 指定给线程的句柄。这个句柄是对调试程序来说是无含义的;

- 分析器在处理很大的模块时会崩溃,这是由于跳转跟踪表溢出;

- 非标准模块(没有按照4096标准对齐)丢失所有用户自定义的信息,像断点或注释;

- 在尝试步过调用 ExitThread() or ExitProcess()时,OllyDbg尝试在下一个命令上设置 INT3 断点,在某些情况下,这个位置是数据;

- 在需要直接一起将Run跟踪数据到文件时,写了无效命令;

- OllyDbg 不检查.ini文件指定的.udd目录是否存在;

- 在二进种编辑后,反汇编窗口不能立即更新选择部分,这样可能只有部分命令被选中;

- OllyDbg 在接受“a.exe %.622496x”类似形式的命令行时,发生崩溃;

- 数据窗口重定位地址的下划线超出了数据内存区域;

- 但用户从一个显示位置到移动另外一个位置时,十六进制编辑窗口行为不可预知,并且有些字符显示不完整;

- FSAVE/FRSTOR 和 FLDENV/FSTENV 显示无效的操作数长度,当使用66前缀时。

- 分析器会被挂起(永远和几分钟)如果参数不足的函数被置于内存块开始处附近;

- 低级失误:“保存文件[Save file]” 窗口调用了函数 GetOpenFileName() ,而不是函数GetSaveFileName();

- ESP 将不记录到Run跟踪打开的文件中,即使相应的选项已经设置;

- 给定(无效)命令MOV QWORD [1234],0 (或许多其他的内存地址和常量之间的操作),汇编器鲁莽地将其编译为8字节的立即数;

- 当第二次打开都引用参数行的可执行文件 (a.exe "ab" "cd"),OllyDbg会移除多余的引号(a.exe ab" "cd)。说实话,这不是我的错,而是GetPrivateProfileString()的问题!1.09c版新增功能

・ 新功能:

- 在跟踪时,反汇编窗口会尝试在当前命令之后保持1到2行可见;

- Run跟踪保存标志寄存器的高16位;

- 增加全局快捷键 Ctrl+P 用于打开补丁窗口;

- OllyDbg 两个新的输出函数: int Attachtoactiveprocess(int newprocessid) 和 HWND Createpatchwindow(void)。

・ Bug修正:

- PEXTRW 交换两个操作数(MMX 或通用寄存器);

- 当设置为总在最上方时,某些错误消息会被主窗口隐藏;

- OllyDbg识别某些绝对正确的PE文件失败,由于节定位错误;

- LOCK 不允许在寄存器与寄存器之间操作,如果不写内存的话;

- 汇编器报告 IN 命令为无效助记符,因为扫描器将助记符与 IN 混淆了;

- 增加支持非标准的短 PE 可选头;

- 当因为硬断点暂停后,OllyDbg不能步过某个命令,如果自动硬断点允许的话;

- 太长的程序参数(大于256字节)导致OllyDbg由于缓冲区溢出而崩溃;

- 命令 LEA 带有16位地址,会报告“多余的前缀”,因为其标记了不能访问的内存;

- NEAR/FAR 高亮显示为随机颜色;

- 转换日本语UNICDOE文本到多字节时出现问题(这没有检查,因为我不会日本语);

- 当 ModRegRM 域没有使用寄存器但不等于0时,命令SETZ, SETO 不能识别。现在如果“非标准命令形式”关闭时,OllyDbg会发出警告信息;

- OllyDbg 在编译或反汇编无效命令 MOV CS,R16 没有警告;

- 如果按Alt+F2 (或在工具栏上的 X)) 但后来没有结束被调试进程,OllyDbg仍然移除所有进程数据,使调试不可能;

- I如果执行代码大小小于节的大小或模块的大小,分析数据会在滚动代码时消失。1.09b版新增功能:

・ 新功能:

- 补丁管理器可能是最重要的新功能。OllyDbg会记住所有在调试过程中对被调试程序的所有修改。从补丁窗口,您可以快速应用补丁或恢复原始代码;

- 使用一个命令,您可以复制模块中所有修改过的地方到可执行文件;

- 一个MDI窗口可以声明为“总在最上方”。注意:为了支持这个功能,插件必须传递WM_WINDOWPOSCHANGED 到函数Tablefunction();

- 您可以指定OllyDbg将.udd文件保持在哪里,以及插件的路径

- 如果选择的命令是一个跳转的目的地址,OllyDbg会显示“Jump from”路径;

- 在基于NT的系统下,具体句柄窗口用于显示被调试程序的所有句柄;

- 您可以不必关闭选项对话框,而直接从调试选项转换外观。

・ 增强的分析功能:

- “搜索所有模块间调”包含了预测的调用;

- 选项在整个函数过程中号跟踪寄存器。以前分析器只是在线性代码段(没有跳到外面的跳转)上预测寄存器;

- 选项让分析器对未知函数的寄存器EBX, ESI 和 EDI 进行保护。如果这不是正确的,寄存器中以此的结果可能是错误的。因此选择该项请小心。

・ Bug修正:

- 在调用树中,OllyDbg 有时会忘记先前由寄存器跟踪而预测的调用;

- 有时,OllyDbg 在调试完成后,创建新的.udd文件(xxx_1, xxx_2,等等)。 1.09版新增功能:

・ 新功能:

- 除了 MASM 和 IDEAL 两种反汇编模式,1.09版又增加了HLA语法(High Level Assembly,由Randall Hyde开始)。HLA是一个公开在网上的软件,可能连同源代码一起下载它 2afK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6W2j5Y4y4@1k6i4u0Q4x3X3g2U0M7#2)9J5k6i4g2U0M7W2)9J5k6h3g2V1N6g2!0q4c8W2!0n7b7#2)9&6b7R3`.`.

- 分析器知道有些调用不会返回,比如kernel32.ExitThread() 和 kernel32.ExitProcess() 并解释他们作为过程的中止;

- 如果某些模块的8.3格式文件名相同,OllyDbg会将其重命名为xxx_1, xxx_2 等等;

- 为了当主文件与DLL文件重名或者DLL有相同的文件名而不在同一个目录时,避免.udd混淆文件的问题,OllyDbg增加_1, _2 以视区分。这个功能在选项“安全|忽略路径和扩展名”关闭时,才有新;

- 选项同步CPU与源当面;

- OllyDbg 支持含有由BCC 5.5生成的调试信息中显示相关源代码;

- 调试引擎,现在可以步入未知命令,如SSE2指令集 (新的安全选项);

- 选项锁定栈(也就是说栈窗口不会滚动,在跟踪时);

- 寄存器窗口显示调试寄存器DR0..3,6,7。调试寄存器不能保存到Run跟踪中,并且您不能修改它们。警告插件作者:t_reg结构的大小已经改变!

- 从可执行文件数据中,您能够跳转到反汇编窗口或CPU数据面板的内存映像中;

- OllyDbg识别“真”(未公开)SAL 指令,但由于在Intel的文档中假定其为SHL。两个指令有相同的效果;

- 新的未公开的操作数: ICEBP (INT1);

- 在栈中搜索地址和二进制串(现在还不是正式支持);

- 选项保存列宽到.ini文件种;

- 增加了新的跳转。在CPU信息面板,列出了关于选择指令的所有已知的跳转并显示相关的菜单(本地或模块区调用);

- 如果您在一个对话框中浏览分支、跳转、调用,那么当您改变选择时,反汇编窗口会跳到相应的命令。在取消后,会恢复以前选择的位置。

・ Bug修正:

- 如果您关闭调试程序(Alt+F2), OllyDbg 现在会正确关闭所有已分配的句柄。打开句柄使得不可能再编译可执行文件;

- 在某些情况下,某些文件名包含空格,空格后面的符号会解释为命令行的参数。例如,程序奇怪的消失

- OllyDbg 可以正确的挂接任务管理器。警告:即时调试器记录格式保存在注册表的(增加引用文件名),因此新的版本不识别旧版本的即时调试器申明;

- 短(无操作数)形式的INS and OUTS 可以识别为 I/O 命令;

- 修正SSE指令集的MOVHLPS 与 MOVLPS 的无效解码。 Intel公司使得这个处理非常困难: MOVHLPS 是寄存器到寄存器,而MOVLPS 是寄存器到内存。它们的命令相同,但行为不同……

- 有时,OllyDbg会在运行“执行到返回”时发生崩溃。嗯,这是因为我忘记检查 NULL 指针的问题;

- 主模块即使放在系统目录中,还会认为其是用户代码;

- 另外,改进了其他一些低级失误。1.08版新增功能:

OllyDbg 1.08 是继1.06版后又一个“稳定”的版本。我将把奇数版本认为是测试版,并且只在我个人的网站发表。(但您可以免费下载并再分发它们)。注册的OllyDbg用户将会得到每个新版本的通知。

如果自1.06版以后的全部更新都列在这里,会是非常非常的长。这里只列出最重要的一部份:

・ 新功能:

- 通过使用dbghelp.dll实现了支持微软格式的调试信息。这包括CodeView, COFF, PDB SYM 格式以及(希望)将来会支持的其他任何格式;

- 调用栈能够嵌套,即使函数过程没有使用标准的 prologs 和 epilogs;

- 调用树可以分析每个函数过程调用的哪些函数,会被哪些函数调用。另外,调用树识别递归函数(自记直接或间接的调用自己)和纯函数(除了修改栈里的变量外,没有调用任何函数,也不修改内存);

- 堆列表可以识别所有已分配的内存块,不幸的这这个选项不能在基于NT的系统(NT、2000、XP)下使用;

- 代码高亮。您可以高亮不同类型的命令。比如FPU/MMX/SSE、 跳转与条件跳转、入栈与出栈、调用、返回、特权、坏命令以及填充命令。选择高亮操作数,通用寄存器、FPU/SSE与段与系统寄存器、在栈中的内存操作(也是就是要通过 ESP or EBP)以及普通内存。还有有效的内存地址常量和其他的常量是不同的。您可以创建自定义的高亮方案;

- 基本窗口信息列表(窗口类、窗口函数、父窗口、窗口风格)可以显示,并且允许在窗口类、单窗口、或者选择的消息或消息组上设置断点;

- 您可以搜索所有的模块间调用,包括间接的(例如,用GetProcAddress()加载的)。还可以在一次在对某个函数的所有的调用上设置断点。命令行插件利用这个功能实现了“bpx API”命令。

・ 增强的分析功能:

- 函数过程识别速度大大加快;

- 识别循环。循环的定义是一个封闭的,只有一个入口,任意多个出口的命令序列(最后一条命令是一个跳到第一条命令的跳转)。注意:入口不一定是循环的第一条命令;

- 识别Switch语句。而且,OllyDbg甚至可以尝试分析每个单独 Case 语句的含义;

- 分析器识别使用RET语句代替的JMP (但其中间不能有PUSH、 POP 或 CALL);识别4或8字节的浮点数入栈,如:ADD ESP,-4; FSTP [DWORD SS:EBP] 以及函数的结构异常处理;

- 分析器识别参数个数变化的函数。

・ 安全:

- OllyDbg 尝试恢复代码节[Code section]的大小。当PE头中代码节的偏移和大小均为0时。

- 访问包含 INT3 内存断点(读或写)以及命令CLI 在Run跟踪期间均认为是可疑;

- 如果在NT系统下为非管理员权限,OllyDbg会警告;

- 如果随OllyDbg分发的 psapi.dll 或 dbghelp.dll 版本低于系统的目录中的,OllyDbg会建议您删除本地目录中的版本。

・ 罕见或未公开的命令与助记符:

- AMD特有指令:SYSCALL 和 SYSRET;

- 未公开的指令: FFREEP STn;

- 汇编器您理解新的助记符:JNAE, JAE 和 SAL.

・ 表达式:

- 表达式支持数千个符号常量,像 WM_PAINT 或 O_RDONLY;

- 新的操作符“IN”可以在表达式使用,这可以非常容易的指定范围;

- 新的伪函数 WINTEXT (别名 GetWindowText)可以在表达式返回指定窗口句柄的ASCII文本。注意:这个文本会被认为是字符串常量,因此比较长度而忽略大小写;

- 修正监视窗口语法高亮错误,以及在表达式中选择定位出错。

・ 其他改进:

- 栈面板识别结构异常处理链;

- 当地址既有符号名又有序号名时,符号名优先;

- 如果条件跳转不发生,则跳转变灰;

- 自动唤醒执行了 WaitMessage() 的线程;

- 统计整个模块或整个应用程序,可以选择邻近的命令为一组与每个命令单独记数;

- 数据窗口支持直接复制修改的可执行文件;

- 模块窗口显示可执行文件的版本信息;;

- 二进制搜索对话框支持10项以前搜索过的历史记录;

- 多例程窗口(像单独的数据或名称窗口)可以记住上次选择的外观(字体、颜色及滚动条)。内存和文件数据窗口可以有不同的外观;

- 执行到用户代码(快捷键:Alt+F9)允许从系统DLL返回到用户代码。在系统文件夹中的DLL默认为系统DLL;

- 可以选择分析所有的模块;

- 执行Shift+鼠标左键选择数据或代码。

・ 许多修正的Bug:

- SFENCE/LFENCE/MFENCE 命令解码错误;

- FXSAVE/FXRSTOR 命令导致通用保护错误,当OllyDbg尝试解码512字节操作数时;

- 当尝试编译SETcc 汇编器报错。

- FSTSW AX 编译不正确(带有16位前缀);

- 在参考窗口中,有时不能跟进到反汇编窗口中;

- 字体(全部)/颜色(全部)不能在CPU数据面板上工作;

- 当OllyDbg尝试关闭被调试程序因为异常而终止时,有时OllyDbg会被锁定;

- 在调试窗口按 Ctrl+G 后,窗口内容没有更新(相应的菜单,可能正常工作);

- 在表达式中的文本常量解释错误,如符号“\\”“\n”等等;

- 还有其他一些不很重要的错误。

$#K技巧提示[Tips and tricks]

¨ OllyDbg 可以作为二进制编辑器使用。选择视图[View]→文件[File]并选定需要查看的文件。文件不能大于剩余内存数量。

¨ 假使您修改了内存中的执行文件,这时您想恢复修改的部分,但是您忘记哪里被修改了,您可以把原始文件当作备份进行加载,这样您就可以找到修改的部分了。

¨ 分析前,先扫描 OBJ 文件。这时 OllyDbg 会对已知 C 函数的参数进行解码。

¨ 一些表格中包含了隐藏数据。可以通过增加列宽来显示出来。

¨ 所有数据窗口(包括反汇编窗口),可以通过双击显示相对的地址。

¨ 您可以通过 Ctrl +↑ 或 Ctrl+↓ 对数据窗口翻动一个字节。

$#K致歉申明[Apologies]

"We apologize for inconveniences"

D. A.

英语不是我的母语。请原谅我犯的语法错误。如果您能将文章中出现的令人不愉快的措辞以及替代方法告诉我,我会十分感谢您的。

请原谅我在C代码中的犯的语义错误。这些错误通常会导致程序弹出非法操作窗口,这个窗口上一般都写着由于在某处内存地址处发生命令或数据问题,导致处理器发生异常。当然这只能怪我的编译器不够优秀,因为它只是原样照搬我写的代码,而不是照搬我的想法[it did literally what I wrote, not what I meant]。请您能原谅这些事情,并将发生问题的地址连同 OllyDbg 版本号以及问题的简短描述发送给我。

所有给您带来的不便之处,我都表示歉意。如果您需要一些有用的功能,请写信给我,但是不要报太高的期望。

$#K本地化操作系统存在的问题[Problems with localized versions of operating system]

我认为如果您运行 OllyDbg 在非英文版本的 Microsoft Windows 操作系统应该没什么问题的,但是我没有进行任何测试。OllyDbg 使用了英语(我希望您能看明白);但是在某些情况下,OllyDbg还依赖于操作系统,像资源中的语言标识等等。结果,有时您可能看到英语与本地语言在 OllyDbg中被混合使用。如果本地文字出现乱码,请尝试使用 UNICODE 字体(Courier 或 Lucida)。

一些用户报告说 OllyDbg 不能运行在 Windows XP 的本地语言版本。但我不能够再现这种情况。

$#K系统最低配置[Minimal system requirements]

为了 OllyDbg 能顺利运行,您的计算机至少有以下的配置:

- 586 处理器 (推荐166 MHz 以上)

- Microsoft Windows 95 (OSR2),Windows 98,Windows ME,Windows NT 4.0 (Service Pack 2+),Windows 2000 或者 Windows XP(名称只用于辨别操作系统版本,完整的名称应该有注册商标的标志)

- 64 MB 物理内存(推荐128MB以上)

- 至少有 1MB 剩余硬盘空间

- 屏幕分辨率 800x600 (强烈推荐 1024x768 或更高)

- 鼠标或兼容设备(必需)

调试 Windows NT,2000,或XP下的程序时,您应该具有管理员权限。

OllyDbg 不支持对.NET应用程序的调试。

Win32s (Microsoft Windows 3.1的32位扩展操作系统)不支持所有重要的调试函数。OllyDbg不能工作于Win32s操作系统。

相关信息: 本地化操作系统存在的问题[Problems with localized versions of operating system]

$#K安装[Installation]

OllyDbg 不需要安装。只需简单的创建一个新的文件夹,并把 Odbg110.zip 压缩包内的所有文件释放到这个文件夹内即可。如果需要的话,可以用拖拽 ollydbg.exe 到桌面的方法,创建快捷方式。

如果在 Windows NT 4.0下运行OllyDbg的话,您需要有psapi.dll这个文件。如果需要读取 Microsoft 格式(CodeView、COFF、PDB 和 SYM)的符号调试信息,您需要有 dbghelp.dll 文件。这些文件均是Microsoft发放的文件,它们都已经放入压缩包中。不过某些系统安装时已经包含了这些链接库。如果OllyDbg发现系统中已经含有更高版本的链接库,或者不需要 psapi.dll,它就会询问您是否成 OllyDbg 的文件夹中删除这些不必要的文件。

在一些 Windows 95 的老版本中并不包含 VirtualQueryEx 和 VirtualProtectEx 这两个函数。但是这两个函数对于调试非常重要。如果OllyDbg报告这个两个函数不可用。正常的调试将不可能正常进行。请升级您的操作系统。

相关信息:隐私与安全[Your privacy and security]

$#K技术支持[Support]

有限的技术支持来自网上355K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3S2G2L8h3g2Q4x3X3g2@1i4K6u0V1L8$3&6D9K9h3&6W2i4K6u0W2k6r3g2Q4x3V1k6Z5L8$3#2W2i4K6u0r3e0$3I4D9P5h3c8T1k6#2!0q4x3#2)9^5x3q4)9^5x3W2!0q4y4q4!0n7b7W2)9^5c8g2!0q4z5q4!0n7c8W2)9&6z5g2!0q4z5g2)9^5y4#2)9^5b7#2!0q4y4W2)9^5x3W2!0m8z5q4!0q4y4g2!0n7x3q4)9^5y4W2!0q4y4g2)9^5c8W2!0m8c8W2!0q4y4q4!0n7b7W2!0m8y4g2!0q4y4q4!0n7z5q4)9^5b7W2!0q4z5q4!0n7c8q4!0n7c8q4!0q4y4W2)9&6b7#2)9^5x3q4!0q4y4W2)9&6y4W2!0n7x3q4!0q4y4q4!0n7c8W2!0m8c8g2!0q4y4W2!0m8c8q4!0m8x3#2!0q4y4#2)9&6b7g2)9^5y4q4!0q4y4#2)9^5z5g2)9^5z5q4!0q4y4W2)9&6b7#2!0m8b7#2!0q4x3#2)9^5x3q4)9^5x3W2!0q4y4g2!0m8y4W2)9^5x3W2!0q4y4W2)9&6c8g2)9&6b7#2!0q4y4W2)9^5x3#2!0n7x3#2!0q4y4g2)9^5c8W2)9^5b7g2!0q4y4W2)9&6y4#2!0n7y4W2!0q4y4g2!0n7c8g2)9&6y4#2!0q4y4g2)9^5z5q4!0n7x3q4!0q4y4W2)9&6b7W2!0n7y4q4!0q4y4W2)9&6y4W2!0n7x3q4!0q4z5g2)9^5x3q4)9&6b7g2!0q4y4#2)9&6c8W2!0m8y4g2!0q4c8W2!0n7b7#2)9^5b7#2!0q4z5q4!0m8c8W2!0n7y4#2!0q4y4W2!0n7x3#2!0m8z5q4!0q4y4g2)9^5y4W2)9^5b7#2!0q4x3#2)9^5x3q4)9^5x3W2!0q4y4g2!0m8y4W2)9^5x3W2!0q4y4W2)9&6c8g2)9&6b7#2!0q4y4W2)9^5x3W2!0m8z5q4!0q4y4W2)9&6b7#2)9^5z5g2!0q4y4q4!0n7b7W2)9^5x3q4!0q4y4q4!0n7z5g2)9^5z5q4!0q4z5g2)9&6y4#2!0m8c8g2!0q4z5g2!0m8x3W2)9&6z5q4!0q4c8W2!0n7b7#2)9^5b7#2!0q4z5q4!0m8c8W2!0n7y4#2!0q4y4g2)9^5c8W2)9&6x3g2!0q4y4q4!0n7c8W2!0m8x3g2!0q4z5q4)9^5y4#2!0n7x3H3`.`. Ollydbg[AT]t-online.de。通常我会在一个星期内回复。我会保留将您的信件贴到我的网站上的权利,除非您明确提出不允许。

我已经免费公开了基于GPL授权的反汇编器(不包括分析器和SSI支持)和汇编器代码(不包括SSI)的源代码。您可以从我的网站下载。

全部的源代码您也可以得到,但您需要花费一些费用。毕竟这些代码花费了我一年多的时间。代码多达32MB并有非常好的注释文档,可以方便日后的维护。这些代码非常“干净”,绝对没有包含任何第三方代码。您既可以订购全部源代码,也可以只订购其中的一部分,如反汇编器、汇编器或分析器的代码。想获得这方面的更多细节,请写信联系。

.udd的文件格式只要您需要,即可免费获得。

$#K注册[Registration]

OllyDbg 1.10版权所有 2000-2004 Oleh Yuschuk。这不是一个免费软件。您若长期使用或者出于商业目的,您必须注册。注册是完全免费的,并且不需要您履行金融或其他方面的义务。我仅仅是想知道谁喜欢用我的软件。注册中的任何关于您的个人资料都是可选的(您可以使用您的昵称或笔名)。

如果您将 OllyDbg 同 Randall Hyde 的 HLA (高级汇编语言[High Level Assembly])一起使用,那么您可以不必注册(当然您也可以注册)。

在注册时,您可以订阅关于这个软件的新版本信息(电子邮件)。请不要把这些信息当作垃圾邮件,因为一年绝不会超过4封,内容也不会是第三方广告。如果您不希望收到这封邮件,那么请您告诉我,我会立即将您的地址从我的数据库里删除掉。

如果您已经是 OllyDbg 的注册用户,那么您不需要再次注册这个版本。

否则,请您阅读授权协议, ,添写注册表格(register.txt) 或者从帮助文件中复制并填写以下各部分,并把它寄到 Ollydbg[AT]t-online.de。我将秘密保留您的信息,保证不会给第三个人,除非法律强迫。

Registration form for OllyDbg v1.10To use OllyDbg, you must agree with all of the terms and

conditions of the accompanying License Agreement. All other

answers are optional.

Name ___________________________________________________

Title ___________________________________________________

Company ___________________________________________________

City,state___________________________________________________

Country ___________________________________________________

Where did you find OllyDbg __________________________________

___________________________________________________

Are you going to write your own plugins

(____) Yes (____) No (____) Don't know

I agree with all the terms and condition of the accompanying

License Agreement (Very important! Please mark!)

(____) Yes (____) No

Date of registration ________________________________________

If you want to receive notifications when OllyDbg 2.00 and

subsequent versions will be ready, please enter your email

address here:

_____________________________________________________________ Thank you. If you have ideas how to improve OllyDbg and make

it easier in use, or want to have some new features, please

let me know. Your opinion helps me a lot!

Your first idea: ____________________________________________

_____________________________________________________________

Your second idea: ___________________________________________

_____________________________________________________________

Your third idea: ____________________________________________

_____________________________________________________________$#K法律部份[Legal part]

商标信息

OllyDbg(包括相关附件及这个帮助文件)中使用的商标名,产品名,注册商标以及买卖双方名称等,仅是用于鉴别目的。

授权协议

该授权协议(以下简称“协议”)仅限于 OllyDbg 1.10 版、OllyDbg 插件开发工具包1.10版,以及相关文件(以下简称“软件”)。在使用本软件时,您必须同意遵照本协议的全部条款。

本软件分发时必须保证完整性,不需要任何形式的授权,包括明确或含蓄的;但若要用于特殊目的,则必须授权才能使用。,由于使用或错误使用该软件而造成特殊的、偶然的、间接的或其他任何损失(包括任何失去的利润或储蓄),本作者不承担任何责任,尽管作者已经尽可能的考虑过避免这种危害发生的办法。

本软件属于 Oleh Yuschuk (以下简称“作者”) 并且版权所有 (c) 2000-2004 Oleh Yuschuk。您若长期使用或者出于商业目的,您必须注册。您需要填写注册表格 并发送给做作者。如果您专门使用 Randall Hyde 的 High Level Assembly,那么您不需要注册。如果您已经是 OllyDbg的用户,那么您不需要再注册本软件。如果本软件注册给一个公司或组织,则该公司或组织的任何人都可以使用它来工作。您可以在任何存储设备上安装注册过的本软件,比如硬盘、软盘等等。并且允许有本软件的多个拷贝。

您不能够修改,反汇编,逆向本软件,除非相关法律明确允许这样做。您不能独立分发或使用本软件。您可以分发本软件,如果满足以下条件:

a) 拷贝包含所有原始文件,并保持这些文件没有任何变化;

b) 如果您其他文件(比如,插件)与本软件一起分发,他们必须明确表示这些文件不能有比本协议更多的限制条件。

c) 即使您附加了别的文件,您也不能收费(除了传播介质费用,如CD或磁盘)。

您可以开发并分发您自己的插----一种连接本软件的动态链接库并会增加本软件的功能----免费提供:

a) 您的插件不能以任何形式强迫用户注册,或对未注册的插件有功能上的限制;

b) 允许您以类似本软件的条款免费分发您的插件

c) 您不能收费(除了传播介质费用,如CD或磁盘)。

如果您希望开发商业插件,请与作者联系以获得特殊的协议。

分发包含了 PSAPI.DLL 和 DBGHELP.DLL 两个文件,他们都属于 Microsoft(R) 可再分发文件。这些文件应该放在本软件所在的文件夹内。只有在 Windows NT(R) 4.0 平台上时,您才需要 PSAPI.DLL 文件的支持。不允许您单独分发本软件中 PSAPI.DLL 和/或 DBGHELP.DLL 文件。

本协议仅适用于当前的 OllyDbg 1.10 版和 OllyDbg 插件开发包。其他版本都有各自适用的许可协议。

公平使用

许多软件制作商明确不允许您尝试反汇编、逆向工程或修改他们程序。这个限制同样适用于您的应用程序所使用的第三方动态链接库,包括系统链接库。如果您有任何疑问,请联系版权的拥有者。这里所有的“公平使用”条款可能会让人误解。您可能需要与律师一起讨论这是否适用于您的情况。请不要将OllyDbg用于非法目的!

$#K隐私与安全[Your privacy and security]

以下声明适用于 1.00-110 之间的全部版本,以及我在网上(“原始的 OllyDbg”)更新的相应文档(包括 OllyDbg.exe及其支持文件)。该声明不适用于任何第三方插件。

我保证原始的OllyDbg:

- 没有监视除被调试程序以外的进程,没有网络客户端或服务端的行为,不会以任何手段(除非用户自己指定远程文件)发送任何数据到其他计算机中,也不会有任何的特洛伊木马行为;

- 既不读取也不修改系统注册表,除非您明确要求。并且需要修改的注册表键也仅限于以下6个:

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

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug\Debugger HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug\Auto

- 不会在系统目录内创建,重写或修改任何文件;

- 不会在任何计算机上修改任何可执行文件或DLL,包括OllyDbg本身,除非您明确要求;

- 仅在您明确要求时(除了保存了文件历史的ollydbg.ini和带有调试信息的*.udd文件),才会记录您的调试活动。甚至我可以保证没有您的允许,OllyDbg创建或修改的文件将仅限于自己的目录;

- 最后(当然还有很多没有提到),不包含任何显示或隐藏的“警告”框,以强迫您注册这个共享软件,也不会在某个时间后限制 OllyDbg 的某些功能。

如果您需要相关的 OllyDbg 插件也有类似的隐私与安全声明,请与相关插件的作者联系。我对任何第三方插件不负责任。因为插件 bookmark.dll 是免费发放的,我对此插件出现的问题也不负责任,除非您是直接从我的网站下载的。

小心病毒。 尽管我已经使用了多种扫描器对原始文档进行检查,但请您在分发OllyDbg 时不要假定它不会含有病毒,或是假定它不会是伪装成OllyDbg 或支持程序样子的特洛伊木马。对于附在压缩包内的任何木马和病毒或者第三方修改的 OllyDbg,对您的机器造成的任何破坏,我均不负责任。

$#K一般原理[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)格式文件,我也没有打算在未来的版本中支持这些。安息吧,古老而美好的命令提示符!

$#K如何开始调试[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 86 commands编译的。

注意:如果您运行的是Windows NT、2000 或XP操作系统,您应该拥有管理员权限以便能够调试程序。。,

$#K调试独立的DLL[Debugging of stand-alone DLLs]

动态链接库[Dynamic-link libraries]包含被其他模块调用的函数,但并身不能直接执行。为了调试DLL,OllyDbg释放并运行一个小程序,用于加载DLL并允许传递给输出函数多达10个参数。

loaddll.exe (这里是源代码)这个程序被压缩存放在资源段里。如果OllyDbg所在文件夹内没有loaddll.exe,则OllyDbg会释放这个文件。Loaddll 包含了非常大的补丁区域,您可在这个区域里存放其它的指定任务代码。如果您不在需要这些代码,请删除 loaddll.exe ,OllyDbg 会在下次释放时清除。

打开DLL,也可以直接将其从资源管理器拖放到 OllyDbg 上。OllyDbg 会询问您并将该文件的全路径作为参数传递给loaddll.exe.。然后链接库被加载并停在代码的入口()。您可以设置断点,运行或跟踪启动代码,等等。在初始化完成后,应该程序会再次暂停。这次停在标签名为 Firstbp 的位置,其在立即进入主消息循环之前。

现在,您可以调用DLL函数。从主菜单选择“调试[Debug]|调用DLL输出[Call DLL export]”。这时会弹出一个对话框。由于这个对话框是无模式对话框,因此您仍然能够使用OllyDbg的全部功能,比如查看代码、数据,查看断点,修改内存等等。

选择您想调用的函数。例如我们将开始使用 USER32.DLL 里的MessageBox 函数。注意loaddll.exe 已经使用了这个链接库,因此会假定这个 DLL 已经初始化而不再调用入口。MessageBox 这个函数名是通用函数名,实事上,这个函数有处理 ASCII 的 MessageBoxA 和处理 Unicode 的MessageBoxW 两种。我们继续往下看:

{bmc bm1.WMF}

在我们选择这个函数后,右边的消息框中会出现 Number of arguments: 4(有四个参数)的字样。OllyDbg 会根据函数尾部的RET 10语句来正确识别参数的数量。RET nnn 是使用PASCAL调用约定的函数的典型特征。(参数被放入栈中,第一个参数会被最后一个压入栈中,函数调用完毕后,参数会被遗弃)。大多数的 Windows API 函数都是PASCAL形式的。

下一步,我们要设定栈中参数的个数。在这个例子中,不必做进行这个操作,因为OllyDbg已经知道了MessageBoxW函数的参数数量。但是,如果您愿意的话,也可以单击左边的复选框,改变成您认为合适的参数数量

现在填写参数列表。这个对话框中支持至多10个参数. 参数可以是任何有效的表达式,而不必使用寄存器。如果操作数指向了内存,则参数右边的缓冲区窗口会显示内存中的数据。Loaddll.exe 有10个大小为1K的缓冲区,这些缓冲区被标记为Arg1 .. Arg10,,您可以方便自由的使用它们。 另外,对话框还支持两个伪变量:由loaddll.exe创建的父窗口句柄, 以及loaddll的实例句柄。为了方便您的使用,在您第一次使用调用输出函数时,OllyDbg就已经将这两个伪变量加到了历史列表中去了。

MessageBoxW e函数需要4个参数:

・ 父窗口句柄。 这里我们选择 ;handle of owner window. Here, we simply select ;

・ 在消息框中UNICODE文本的地址。选择Arg2并按回车。缓冲区窗口会以16进制的格式显现内存中的缓冲区。这个缓冲区初始化全是0。点击第一个字节,并按快捷键Ctrl+E(另外, 也可以从菜单中选择“二进制[Binary]|编辑[Edit]”)。这时会出现一个对话框,在对话框中键入“Text in box”或者其他希望显示的字符串;

・ 消息框标题的UNICODE文本的地址。选择Arg3并在Unicode格式的内存中写上“Box title”;

・ 消息框的风格。使用常量MB_xxx进行组合.OllyDbg 可以识别这些常量。在这里我们键入:MB_OK|MB_ICONEXCLAMATION。

这里不需要寄存器参数。

现在我们准备调用输出函数。选项“在调用时隐藏[Hide on call]”意思是说,当函数运行时对话框将会从屏幕消失。当我们执行一个会运行很长时间的函数,或者设置了断点的时候,这个选项非常的有用。您也可以手动关闭对话框。当函数执行完毕后,OllyDbg会重新自动打开。“调用输出函数”对话框。选项“在调用后暂停[Pause after call]”意思是说,在执行完函数后,loaddll将会被暂停。

按“调用[Call]按钮”后,OllyDbg 会自动备份所有的内存、校验、参数、寄存器等信息。并隐藏对话框,然后调用 MessageBoxW 函数。和期望的一样,消息框在屏幕中出现了:

{bmc bm2.WMF}

函数 MessageBoxW 不会修改参数。如果您调用的函数更新了内存,比如函数 GetWindowName,修改的字节将会在数据区里高亮。注意:EAX 返回值为1,表示成功。

其他的例子请访问我的网站:

83fK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3S2G2L8h3g2Q4x3X3g2@1i4K6u0V1L8$3&6D9K9h3&6W2i4K6u0W2k6r3g2Q4x3V1k6Z5L8$3#2W2i4K6u0r3e0$3I4D9P5h3c8T1k6#2)9J5c8V1I4G2j5h3c8V1L8r3I4Q4x3X3g2Z5N6r3#2Q4x3X3f1`.

不幸的是,您不能通过这种方式调试OllyDbg的插件,插件关联到ollydbg.exe文件,Windows系统不能在同一个应用程序里加载并运行两个可执行文件。

$#KLOADDLL.EXE

这是 loaddll.exe 的完整源代码,可以在 Borland 的 TASM32 中用以下列命令编译:

tasm32 -mx -zi -m5 loaddll.asm,,loaddll.lst

tlink32 -v- -c -S:40000 -B:400000 -Tpe -aa -m loaddll,,,import32.lib

brc32 loaddll.rc -feloaddll.exe

程序从 START 标号处开始执行,loaddll 接受命令行参数,跳过可执行文件名(必须以双引号引用),解析DLL路径并传递给 LoadLibrary。如果发生错误,它将在固定位置设置指向错误信息的指针,并以退出码0x1001退出。如果加载成功,它将建立一个简单的主窗口并停在第一个断点上(标号为Firstbp)。该断点在启动时由OllyDbg设置。

所有与 OllyDbg 的通信行为都要借助128字节的关联区域。这个区域必须在标志性短语[keyphrase]之后从0x420020地址处立即开始。区域的头几个字包含了 OllyDbg 在 loaddll.exe 中用来设置断点和参数的地址、接着是待调用函数的地址[address of function to call]、寄存器的内容、参数个数以及参数本身。其中参数不得超过10个。如果将参数是指向内存区域的指针,那么您可以使用10个大小为1K字节的数据缓冲区,名字分别为Arg1、Arg2、……、Arg10。这些参数名以及其他的一些名称将被输出并通知OllyDbg。

每当loaddll执行完主窗口循环(WINLOOP),它会检测在PROCADR处的输出的函数地址是否为0。如果是的话,loaddll首先会保存ESP和EBP的内容同时将16个0压入堆栈。这是为了避免用户指定了无效的参数个数而导致的崩溃。然后它会把参数压入堆栈并设置寄存器。在Prepatch处有16个NOP指令,您可以在这里编写补丁。如果需要更多的空间,您可以跳到Patcharea处,那里有2K字节的空间。需要注意的是,如果以 loaddll.exe 为名的文件已经存在,则 OllyDbg 不会再把 loaddll.exe 从资源中释放出来。

输出函数在 CallDLL 处被调用。这个命令后面也紧跟了16个NOP。然后程序会保存修改过的寄存器以及调用之后ESP的偏移。如果您向遵循PASCAL约定的函数提供了无效的参数个数,OllyDbg将会向您报告这一错误。最后,loaddll 恢复ESP和EBP的值,清空PROCADR并在Finished地址处的INT3指令上中断下来。到达这里后,OllyDbg就得知执行已经结束。

请将 LOADDLL.ASM 当作自由软件对待。我不反对您在自己的程序中不带版权地使用这一程序代码的部分或全部,但请勿在与 OllyDbg 无关的项目中使用 GreenBug(LOADDLL.RC)图标……我的说明就这么多了,好好享用吧!

LOADDLL.ASM:

P586 ; 使用32位指令!

MODEL FLAT,PASCAL

IDEAL ; 我真的很喜欢它!

LOCALS

PUBLICDLL WndProc,Firstbp,Prepatch,CallDLL,Finished;

PUBLICDLL Patcharea,Endpatch

PUBLICDLL Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7,Arg8,Arg9,Arg10

SEGMENT _DATA1 PARA PUBLIC USE32 'DATA'

; 下面的文本是OllyDbg用来确认LoadDll文件正常的标志性短语[keyphrase]。

; 它总是被加载到固定地址00420000处。 Never change! Note

; 不要修改!我是怎样一个胆小鬼啊:您不能替换版权,否则这段代码无法工作!

DB "DLL Loader (C) 2004 Oleh Yuschuk"

; 关联区域[Link area]。不要修改下面32个双字变量定义或顺序!

ERRMSG DD 0 ;指向错误信息的指针

HINST DD 0 ;进程实例句柄

HWND DD 0 ; 主窗口句柄

DLLBASE DD 0 ; 被加载DLL的基址或者就是零

DD OFFSET Firstbp ; 第一个断点的地址

DD OFFSET Prepatch ; 函数调用之前的补丁区地址

DD OFFSET Arg1 ; 10个参数x1024个字节的基址

DD OFFSET Finished ; 函数调用后的断点地址

DUMMY DD 4 DUP(0) ; 保留未作使用

PROCADR DD 0 ; 过程地址,从这里开始执行

REGEAX DD 0 ; 寄存器参数

REGECX DD 0

REGEDX DD 0

REGEBX DD 0

REGESI DD 0

REGEDI DD 0

NARG DD 0 ; 压栈参数的个数

ARGLIST DD 10 DUP(0) ; DLL参数列表

ESPDIFF DD 0 ; 代码导致ESP偏移

DD 0 ; 保留未作使用

WCLASS = THIS DWORD ; 手工构造的WNDCLASS结构

DD 0000002Bh ; CS_HREDRAW|VREDRAW|DBLCLKS|OWNDC

DD WndProc ; 窗口过程

DD 0 ; 类附加字节

DD 0 ; 窗口附加字节

WCINST DD 0 ; 实例句柄

WCICON DD 0 ; 图标

HCURS DD 0 ; 光标r

HBGND DD 0 ; 背景刷

DD 0 ; 无菜单

DD CLSNAME ; 类名

MSG = THIS DWORD ; 手工构造的MSG结构

DD 0 ; 窗口句柄

MSGID DD 0 ; 消息ID

DD 0 ; wParam

DD 0 ; lParam

DD 0 ; 时间戳

DD 0 ; X 坐标

DD 0 ; Y 坐标

PSTRUCT = THIS DWORD ; 手工构造的PAINTSTRUCT结构

DD 0 ; HDC

DD 0 ; fErase

DD 0 ; rcPaint.left

DD 0 ; rcPaint.top

DD 0 ; rcPaint.right

DD 0 ; rcPaint.bottom

DD 0 ; fRestore

DD 0 ; fIncUpdate

DB 32 DUP(0) ; rgbReserved

ORIGESP DD 0 ; 函数调用前的原始ESP

ORIGEBP DD 0 ; 函数调用前的原始EBP

EXPESP DD 0 ; 调用完成后ESP的预期值

WNDNAME DB "OllyDbg DLL Loader",0

CLSNAME DB "LoadDLLClass",0

ICONAME DB "MAINICON",0 ; 绿色的喝醉的虫子图标

E_NONAM DB "Missing DLL name",0 ; 错误通知给OllyDbg

E_NODLL DB "Unable to load DLL",0

E_NPARM DB "Too many parameters",0

ALIGN 16

Arg1 DB 1024 DUP (?) ; 10个内存参数,每个大小1K

Arg2 DB 1024 DUP (?)

Arg3 DB 1024 DUP (?)

Arg4 DB 1024 DUP (?)

Arg5 DB 1024 DUP (?)

Arg6 DB 1024 DUP (?)

Arg7 DB 1024 DUP (?)

Arg8 DB 1024 DUP (?)

Arg9 DB 1024 DUP (?)

Arg10 DB 1024 DUP (?)

ENDS _DATA1

SEGMENT _TEXT1 PARA PUBLIC USE32 'CODE'

EXTRN GetModuleHandleA: PROC

EXTRN GetCommandLineA: PROC

EXTRN LoadIconA: PROC

EXTRN LoadCursorA: PROC

EXTRN GetStockObject: PROC

EXTRN RegisterClassA: PROC

EXTRN CreateWindowExA: PROC

EXTRN DestroyWindow: PROC

EXTRN PostQuitMessage: PROC

EXTRN ShowWindow: PROC

EXTRN Sleep: PROC

EXTRN BeginPaint: PROC

EXTRN EndPaint: PROC

EXTRN DefWindowProcA: PROC

EXTRN LoadLibraryA: PROC

EXTRN PeekMessageA: PROC

EXTRN TranslateMessage: PROC

EXTRN DispatchMessageA: PROC

EXTRN ExitProcess: PROC

; LoadDLL主窗口的窗口过程。

PROC WndProc

ARG LP:DWORD,WP:DWORD,MS:DWORD,HW:DWORD

PUSH EDX

PUSH EDI

PUSH ESI

MOV EAX,[MS]

CMP EAX,0001h ; WM_CREATE

JE RET0

CMP EAX,0002h ; WM_DESTROY

JNE @@080

PUSH 0

CALL PostQuitMessage

JMP RET0

@@080: CMP EAX,000Fh ; WM_PAINT

JNE @@100

PUSH OFFSET PSTRUCT

PUSH [HW]

CALL BeginPaint

PUSH OFFSET PSTRUCT

PUSH [HW]

CALL EndPaint

JMP RET0

@@100: CMP EAX,0010h ; WM_CLOSE

JNE @@200

PUSH [HW]

CALL DestroyWindow

JMP RET0

@@200: ; 以上没有列出的消息,传递给函数 DefWindowProc()处理。

PUSH [LP]

PUSH [WP]

PUSH [MS]

PUSH [HW]

CALL DefWindowProcA

JMP RETA

RET0: XOR EAX,EAX

JMP SHORT RETA

RET1: MOV EAX,1

RETA: POP ESI

POP EDI

POP EDX

RET

ENDP WndProc

START: MOV EBP,ESP ; 这里开始运行

PUSH 0

CALL GetModuleHandleA

MOV [DWORD DS:WCINST],EAX

MOV [DWORD DS:HINST],EAX

CALL GetCommandLineA ; 引用中已包含LOADDLL的路径

MOV ESI,EAX

INC ESI ; 跳过第一个引用

@@10: MOV AL,[BYTE DS:ESI] ; 跳过LOADDLL.EXE的路径

INC ESI

OR AL,AL

JNE @@12

MOV [DWORD DS:ERRMSG],OFFSET E_NONAM

JMP ERROR

@@12: CMP AL,'"'

JNE @@10

@@20: MOV AL,[BYTE DS:ESI] ; 跳过空格

CMP AL,' '

JNE @@30

INC ESI

JMP SHORT @@20

@@30: PUSH ESI

CALL LoadLibraryA ; 加载DLL

OR EAX,EAX

JNE @@32

MOV [DWORD DS:ERRMSG],OFFSET E_NODLL

JMP ERROR

@@32: MOV [DWORD DS:DLLBASE],EAX

PUSH OFFSET ICONAME

PUSH [DWORD DS:HINST]

CALL LoadIconA

MOV [DWORD DS:WCICON],EAX

PUSH 7F88h ; IDC_NO

PUSH 0 ; 扩展资源

CALL LoadCursorA

MOV [DWORD DS:HCURS],EAX

PUSH 0 ; WHITE_BRUSH

CALL GetStockObject

MOV [DWORD DS:HBGND],EAX

PUSH OFFSET WCLASS

CALL RegisterClassA

PUSH 0 ; Parameters: none

PUSH [DWORD DS:HINST] ;实例

PUSH 0 ; 菜单:无

PUSH 0 ; 父窗口:无

PUSH 100 ; 宽度

PUSH 200 ; 高度

PUSH 80000000h ; CW_USEDEFAULT

PUSH 80000000h ; CW_USEDEFAULT

PUSH 10CF0000h ; WS_OVERLAPPEDWINDOW|WS_VISIBLE

PUSH OFFSET WNDNAME ; 窗口名

PUSH OFFSET CLSNAME ; 类名

PUSH 0 ; 无扩展风格

CALL CreateWindowExA

MOV [DWORD DS:HWND],EAX ; 保存句柄

PUSH 9 ; SW_RESTORE

PUSH EAX

CALL ShowWindow

Firstbp: NOP ; 第一个中断设在这里

WINLOOP: CMP [DWORD DS:PROCADR],0 ; 需要调用南某个函数?

JE NOCALL

MOV [DWORD DS:ORIGESP],ESP

MOV [DWORD DS:ORIGEBP],ESP

PUSH 0 ; 安全缓冲区(32字节)

PUSH 0

PUSH 0

PUSH 0

PUSH 0

PUSH 0

PUSH 0

PUSH 0

PUSH 0

PUSH 0

PUSH 0

PUSH 0

PUSH 0

PUSH 0

PUSH 0

PUSH 0

MOV ECX,[DWORD DS:NARG]

JECXZ @@44

CMP ECX,10

JBE @@40

MOV [DWORD DS:ERRMSG],OFFSET E_NPARM

JMP ERROR

@@40: MOV EAX,OFFSET ARGLIST

@@42: PUSH [DWORD EAX] ; 输入需要参数的个数

ADD EAX,4

LOOP @@42

@@44: MOV [DWORD DS:EXPESP],ESP ; 返回后期望的返回值

MOV EAX,[DWORD DS:REGEAX] ; 调整寄存器

MOV ECX,[DWORD DS:REGECX]

MOV EDX,[DWORD DS:REGEDX]

MOV EBX,[DWORD DS:REGEBX]

MOV ESI,[DWORD DS:REGESI]

MOV EDI,[DWORD DS:REGEDI]

Prepatch: NOP ; 在调用前的补丁区域

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

CallDLL: CALL [DWORD DS:PROCADR] ; 调用DLL函数

NOP ; 调用后的补丁区域

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

NOP

MOV [DWORD DS:REGEAX],EAX ; 获得修改过的寄存器

MOV [DWORD DS:REGECX],ECX

MOV [DWORD DS:REGEDX],EDX

MOV [DWORD DS:REGEBX],EBX

MOV [DWORD DS:REGESI],ESI

MOV [DWORD DS:REGEDI],EDI

MOV EAX,ESP

SUB EAX,[DWORD DS:EXPESP]

MOV [DWORD DS:ESPDIFF],EAX

MOV EBP,[DWORD DS:ORIGEBP]

MOV ESP,[DWORD DS:ORIGESP]

MOV [DWORD DS:PROCADR],0 ; 确认执行

NOP

Finished: INT 3 ; 运行完后暂停

NOP

NOCALL: PUSH 0

CALL Sleep ; 留给其他应用程序

PUSH 1 ; PM_REMOVE

PUSH 0 ; 处理所有消息

PUSH 0

PUSH 0 ; 任何窗口

PUSH OFFSET MSG

CALL PeekMessageA

OR EAX,EAX

JZ WINLOOP

PUSH OFFSET MSG

CALL TranslateMessage

PUSH OFFSET MSG

CALL DispatchMessageA

MOV EAX,[DWORD DS:MSGID]

CMP EAX,12h ; WM_QUIT

JNE WINLOOP

PUSH 0

CALL ExitProcess ; 退出!

ERROR: PUSH 00001001h ; 特殊返回代码,菜单错误

CALL ExitProcess ; 发生错误

ALIGN 4

Patcharea: DB 2047 DUP(90h) ; 大的补丁区域(2千个 NOP 命令)

Endpatch: NOP

ENDS _TEXT1

END START

LOADDLL.RC:

MAINICON ICON // 绿色虫子

{

'00 00 01 00 02 00 20 20 10 00 00 00 00 00 E8 02'

'00 00 26 00 00 00 10 10 10 00 00 00 00 00 28 01'

'00 00 0E 03 00 00 28 00 00 00 20 00 00 00 40 00'

'00 00 01 00 04 00 00 00 00 00 80 02 00 00 00 00'

'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'

'00 00 00 00 80 00 00 80 00 00 00 80 80 00 80 00'

'00 00 80 00 80 00 80 80 00 00 80 80 80 00 C0 C0'

'C0 00 00 00 FF 00 00 FF 00 00 00 FF FF 00 FF 00'

'00 00 FF 00 FF 00 FF FF 00 00 FF FF FF 00 00 00'

'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'

'00 00 00 00 02 A0 00 00 00 00 A2 00 00 00 00 00'

'00 00 00 00 0A 20 00 00 00 0A 2A 2A 00 00 00 00'

'00 00 00 00 A2 A2 00 00 00 A2 A2 A2 00 00 00 00'

'00 00 00 00 2A 2A 00 00 0A 2A 2A 2A 00 00 00 00'

'00 00 00 00 A2 A2 00 00 A2 A2 A2 A0 00 00 00 00'

'00 00 00 00 2A 2A 00 0A 2A 2A 2A 20 00 00 02 A2'

'00 00 00 00 02 A2 A0 A2 A2 A2 A2 00 00 00 0A 2A'

'2A 2A 00 00 0A 2A 2A 2A 2A 2A 20 00 00 00 02 A2'

'A2 A2 A0 00 02 A2 A2 A2 A2 A2 00 00 00 00 0A 2A'

'2A 2A 2A 2A 2A 2A 2A 2A 2A 00 00 00 00 00 00 A2'

'A2 A2 A2 A2 A2 A2 A2 A2 00 00 00 00 00 00 00 00'

'2A 2A 2A 2A 2A 2A 2A 2A 00 00 00 00 00 00 00 00'

'00 02 A2 A2 A2 A2 A2 A2 00 00 00 00 00 00 00 00'

'00 00 0A 2A 2A 2A 2A 2A 2A 00 00 00 00 00 00 00'

'00 00 02 A2 A2 A2 A2 A2 A2 A2 A2 00 00 00 00 00'

'00 00 0A 2A 2A 2A 2A 2A 2A 2A 2A 20 00 00 00 00'

'00 00 02 A2 A2 A2 A2 A2 A2 A2 A2 A2 A2 00 00 00'

'00 00 0A 2A 2A 2A 2A 2A 00 00 2A 2A 2A 20 00 00'

'00 00 A2 A2 A0 A2 A2 A0 00 00 02 A2 A2 A0 00 00'

'00 00 2A 2A 00 0A 2A 20 00 00 00 2A 2A 20 00 00'

'00 00 00 00 00 00 A2 A0 00 00 00 00 00 00 00 00'

'00 00 00 00 00 00 2A 20 00 00 00 00 00 00 00 00'

'00 00 00 00 00 00 A2 A0 00 00 00 00 00 00 00 00'

'00 2A 20 00 00 00 2A 2A 00 00 00 00 00 00 00 00'

'A2 A2 A0 00 00 00 A2 A2 00 00 00 00 00 00 00 00'

'2A 2A 20 00 00 00 2A 2A 00 00 00 00 00 00 00 00'

'A2 A2 A0 00 00 00 02 A2 00 00 00 00 00 00 00 0A'

'2A 2A 20 00 00 00 0A 2A 00 00 00 00 00 00 00 02'

'A2 A2 00 00 00 00 00 00 00 00 00 00 00 00 00 0A'

'2A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'

'00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF F9'

'FF 3F FF F0 FE 0F FF F0 FC 07 FF E0 78 07 FF E0'

'70 07 FF E0 60 0F 8F E0 40 0F 00 F0 00 1F 00 70'

'00 3F 00 10 00 7F 00 00 00 FF 80 00 03 FF C0 00'

'0F FF E0 00 03 FF FC 00 00 3F FF 00 00 1F FF 00'

'00 03 FF 00 00 01 FF 00 00 00 FE 00 0F 00 FE 04'

'0F 80 FF 0E 0F C1 FF FE 0F FF FC 7E 0F FF F0 3E'

'07 FF E0 3E 07 FF E0 3E 07 FF C0 3F 07 FF C0 3F'

'07 FF C0 7F 0F FF C0 FF FF FF E3 FF FF FF 28 00'

'00 00 10 00 00 00 20 00 00 00 01 00 04 00 00 00'

'00 00 C0 00 00 00 00 00 00 00 00 00 00 00 00 00'

'00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80'

'00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80'

'00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF'

'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'

'00 00 FF FF FF 00 00 00 00 00 00 00 00 00 00 00'

'00 AA 00 0A AA 00 00 00 00 AA 00 AA AA 00 00 00'

'00 AA 0A AA A0 00 0A AA 00 0A AA AA 00 00 0A AA'

'AA AA AA 00 00 00 00 0A AA AA AA 00 00 00 00 00'

'0A AA AA A0 00 00 00 00 0A AA AA AA AA 00 00 00'

'AA AA AA 00 AA A0 00 00 00 00 A0 00 00 00 00 00'

'00 00 A0 00 00 00 00 0A 00 00 AA 00 00 00 00 AA'

'00 00 AA 00 00 00 00 AA 00 00 00 00 00 00 00 00'

'00 00 00 00 00 00 FC E3 00 00 F8 41 00 00 F8 01'

'00 00 88 03 00 00 00 07 00 00 00 0F 00 00 80 1F'

'00 00 E0 03 00 00 F0 01 00 00 E0 00 00 00 F0 31'

'00 00 EE 3F 00 00 86 1F 00 00 86 1F 00 00 87 3F'

'00 00 8F FF 00 00'

}

$#K分析器[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]。

相关信息: Object扫描器[Object scanner], 分析选项1[Analysis options - part 1], 分析选项2[Analysis options - part 2], 分析选项3[Analysis options - part 3], 调用树[Call tree]

$#K解码提示[Decoding hints]

在某些情况下,分析器不能区分代码和数据。让我们看看下面的例子:

const char s[11] = "0123456789";

...

for (i=0x30; i<0x3a; i++) t[i-0x30]=s[i-0x30];

好的编译器将会将上面的代码优化成如下样子: e

for (i=0x30; i<0x3a; i++) (t-0x30)[i]=(s-0x30)[i];

这里t-0x30 和 s-0x30 都是常量,并编译成如下形式:

MOV AL,[BYTE s_minus_30+EBX]

MOV [BYTE t_minus_30+EBX],AL

编译器也可能将常量字符串"0123456789"插入到执行代码中。在1.10版本中,我打算用寄存器的值来决定是否的数据或代码。当遇到上面的命令,分析器将假定地址s_minus_30处包含字符数据。但事实上,可能那里是代码。

万一出现上述问题,我们应该怎么办呢?有两种办法:最快最笨的办法是:将分析错误的部分删除(快捷键:退格键),这样OllyDbg将使用默认的反汇编器进行解码。

更好的办法是使用解码提示[decoding hints]。您可以告诉OllyDbg如何解释选中的内存内容。这种方法在重新分析(Ctrl+A)时,解释依然有效。

设置提示的方法:在反汇编窗口中,选中需要修正提示的代码或数据,然后在快捷菜单中选择 分析[Analysis]|在下次分析时,将选择部分视为[During next analysis, treat selection as]。选择以下选项之一:

命令[Command] - 第一个被选中的字节开始的有效命令。这条命令,还有所有后面的部分,直到有Jump或Return命令出现,以及含有Jump或Call命令所到达位置的部分,都会被视为命令;

字节[Byte],

字[Word],

双字[Doubleword] - 选中的前1、2、4字节视为对应大小的数据;

所有选中命令[Commands] - 全部选中部分(直到第一个无效命令)和可以到达由有效命令集组成的目的地址;

字节[Bytes],

字[Words],

双字[Doublewords], - 全部选中部分以1、2、或 4字节分组;

ASCII字符串[ASCII text],

UNICODE字符串[UNICODE text] - 全部选中部分为ASCII 或 UNICODE 字符串;

默认(移除提示)[Default (remove hints)] - 从选中部分中移除全面提示;

移除全部提示[Remove all hints] - 从全部模块中移除解码提示。

OllyDbg 保存提示到.udd文件中。

$#KObject扫描器[Object scanner]

扫描器将特定的目标文件或者目标库(包括OMF和COFF两种格式),提取出代码段,然后将这些段定位在当前模块的代码节[Code section]中.如果段定位好了,扫描器将从目标文件中的调试信息提取名称(也就是所谓的库标签[library labels])。这极大的增加了代码与数据的可读性.

扫描器并不会对已识别的目标文件进行标签匹配,所以它不能识别非常小或相似的函数(比如:两个函数只是在重定位有区别)。因此要经常检查扫描器发送到登陆窗口的警告列表!

相关信息: 分析器[Analysis], Implib扫描器[Implib scanner]

$#KImplib扫描器 [Implib scanner]

某些DLL的输出符号仅仅是一个序号。许多符号都是井号加数字(比如:MFC42.#1003),这非常不便于理解。幸运的是,软件零售商提供了输入连接库(implibs),它与序号符号名相关。

使用implib扫描器的方法:从主菜单中选择调试[Debug]|选择输入链接库[Select import libraries]。当您加载应用程序时,OllyDbg会读取链接库并从内置表格[internal tables]中提取符号名。每次遇到序号符号,而对应的链接库已经注册到OllyDbg中时,这个序号符号会被替换。

相关信息:分析器[Analysis],Object扫描器[Object scanner]

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课