在安全应用中,分析者经常会使用一些调试工具,以便高效找出软件中存在的错误。而在逆向分析领域,分析者也会利用相关的调试工具来分析软件的行为并验证分析结果。在使用调试工具分析程序的过程中,程序会按调试者的意愿以指令为单位执行。由于操作系统都会提供完善的调试接口,所以利用各类调试工具,可以非常方便灵活地观察和控制目标软件。
OD特点及操作简介
1.OD特点
调试逆向分为动态分析技术和静态分析技术。动态分析技术指的是使用调试工具加载程序并运行,随着程序运行,调试者可以随时中断目标的指令流程,以便观察相关计算的结果和当前的设备情况。而静态分析技术是相对于动态分析而言的。比如,在实际分析中,很多场合不方便运行目标,例如病毒程序,设备不兼容,软件的单独某一模块等,这个时候就可以将静态分析技术派上用场了!
OD(OllyDbg)和IDAPro这两款工具分别是调试逆向的倚天剑和屠龙刀。虽然两者都兼容动态和静态的调试方式,但就动态调试而言,OD更为灵活和强大,而静态调试工具的王者理所应当是功能极为强大的IDAPro。OllyDbg界面如图1所示。
图1
在上图中,1为汇编代码对应的地址窗口,2为汇编代码对应的十六进制机器码窗口,3为反汇编窗口,4为反汇编代码对应的注释信息窗口,5为寄存器信息窗口,6为当前执行到的反汇编代码的信息窗口,7~9为数据所在的内存地址、十六进制、ASCII码,10~12为栈地址,存放的数据,对应说明信息。
2.基础知识介绍
1)关于寄存器
寄存器就好比是CPU身上的口袋,方便CPU随时从里边拿出需要的东西来使用。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。通常会涉及到以下寄存器:EAX(扩展累加寄存器),EBX(扩展基址寄存器),ECX(扩展计数寄存器),EDX(扩展数据寄存器),ESI(扩展来源寄存器),EDI(扩展目标寄存器),EBP(扩展基址指针寄存器),ESP(扩展堆栈指针寄存器),EIP(扩展的指令指针寄存器)。
这些寄存器的大小是32位(4个字节),它们可以容纳从0-FFFFFFFF(无符号数)的数据,除了以下三个寄存器,其他都可以随意使用:
EBP:主要是用于栈和栈帧。
ESP:指向当前进程的栈空间地址。
EIP:总是指向下一条要被执行的指令。
2)关于栈
栈是在内存中的一部分,它有两个特殊的性质。第一是FILO(FirstInLastOut),即先进后出;第二是地址反向增长(栈底为大地址,栈顶为小地址)。如图2所示。
3)关于系统API
Windows应用程序运行在Ring3级别(包括OllyDBG),如图3所示。
但有时候需要Ring0级别才能进行操作,那咋整?我们可以通过系统为我们搭建的桥梁:API函数,也称之为系统提供给我们的接口。因为系统只信任自己提供的函数,所以我们要通过API才能实现对内核的操作。你可以这么想,假如我送给你一辆法拉利跑车,恩,你没听错,是假如,不是真的!那你要怎么来驾驶她?没错,要通过踩油门来加速,要通过打方向盘来转弯。而油门,方向盘就是所谓的接口,对于法拉利来说,它们就是API函数。
4)关于CALL指令
Call有以下几种方式:
方式一:call404000h;直接跳到函数或过程的地址
方式二:calleax;函数或过程地址存放在eax
方式三:calldwordptr[eax]
方式四:calldwordptr[eax+5]
方式五:calldwordptr[&API];执行一个系统API
5)关于mov指令
mov指令格式:movdest,src
这是一个很容易理解的指令,mov指令将src的内容拷贝到dest,mov指令总共有以下几种扩展。
第1种:movs/movsb/movsw/movsdedi,esi:这些变体按串/字节/字/双字为单位将esi寄存器指向的数据复制到edi寄存器指向的空间。
第2种:movsx符号位扩展,byte-word,word-dword(扩展后高位全用符号位填充),然后实现mov。
第3种:movzx零扩展,byte-word,word-dword(扩展后高位全用0填充),然后实现mov。
6)关于cmp指令
cmp指令格式:cmpdest,src
cmp指令比较dest和src两个操作数,并通过比较结果设置C/O/Z标志位。
cmp指令大概有以下几种格式:
第1种:cmpeax,ebx;如果相等,Z标志位置1,否则0.
第2种:cmpeax,[404000];将eax和404000地址处的dword型数据相比较并同上置位。
第3种:cmp[404000],eax;同上。
7)标志位
这个概念在破解中起到的作用是至关重要的。事实上所有的标志位归并与一个32位的标志位寄存器,也就是说有32个不同的标志位。每个标志位有两个属性:置1或置0,就相当于我们平时说的OK或不OK。在逆向中,你真正需要关心的标志位只有三个,也就是cmp指令能修改的那三个:Z/O/C。
第一:Z标志位(0标志),这个标志位是最常用的,运算结果为0时候,Z标志位置1,否则置0。
第二:O标志位(溢出标志),在运行过程中,如操作数超出了机器能表示的范围则称为溢出,此时OF位置1,否则置0。
第三:C标志位(进位标志),记录运算时从最高有效位产生的进位值。例如执行加法指令时,最高有效位有进位时置1,否则置0。
8)关于test指令
test指令格式:testdest,src这个指令和and指令一样,对两个操作数进行按位的“与”运算,唯一不同之处是不将
“与”的结果保存到dest。即本指令对两个操作数的内容均不进行修改,仅是在逻辑与操作后,对标志位重新置位。
9)关于条件跳转指令
条件跳转指令,就是根据各种不同标志位的条件判断是否成立,条件成立则跳转。
10)patch
patch也就是我们平时所说的补丁。所谓给程序打补丁就是我们对程序破解所进行的修改。OllyDBG的“/”可以查看所有打过的补丁。
11)PE文件头
为什么需要了解PE结构?大家想象一下,某天在班上,我突然想知道小明同学今天穿什么颜色的裤子,要怎么办呢?点名让小明同学站起来?不行,因为老师在上课呢。那我就只好掏出班级里的座位名单,然后找到小明的名字,看是在第几行第几列就找到了,然后在看她的裤子是什么颜色,对啵?其实如果把PE结构比作我们刚才提到的班级,那么座位名单就是PE文件头了。
PE(PortableExecutable)可执行文件结构是一样规范,发明这个主要用来指导系统如何执行你所设计的程序。编译器已经为你将代码按照PE结构的形式编译链接为可执行文件,这过程只是它默默的完成,所以我们没有察觉。但是我们现在学习的是逆向,所以连一条毛我们都不能放过。
PE文件结构有一个非常优势的地方就是它在硬盘上的存储结构跟载入内存时候的存储结构是一样的。所以,只要你了解如何在PE文件结构里边找出某样你想要的东西,那么当这个文件映射到内存后,你也可以很容易的找到它(因为OD是动态调试,程序需要先载入内存嘛)。内存中的一个模块代表一个可执行文件进程所需要的所有代码、数据、资源的集合。
牛刀小试:修改标题和破解验证程序
1.初试牛刀:修改软件标题
任务要求:通过OD将程序的标题“Ilovefishc.com”改为“IamJiaYuntian”。如图4所示。
具体操作步骤如下:
第1步:打开OD。按F3载入程序hello.exe。粗略浏览汇编代码,发现是一些乱七八糟的东西。Ctrl+F2重新载入程序回到入口点OEP。一直按F8单步步过,注意观察窗口各处信息的变化,一直按到出现对话框。此时停在下图的这个call上。
第2步:找到标志行,按F2设下断点(或者双击该行)。Ctrl+F2重新载入,直接按F9运行到断点处,按F7单步步入这个call里。如图5所示。
第3步:查找修改内容。进入到这里后,继续按F8单步往下执行。在“0040102C”处就找到了我们要修改的地方。在左下方的数据窗口里按Ctrl+G,键入地址00422030,确认:
第4步:修改内容。在第一行的地方按空格,修改标题内容。此处应注意,16进制数字末尾处应加上00(因为字符串是以0结尾的,C语言编程里有学到。)如图6所示。
图6
第5步:修改并执行程序。点击确定,修改完成。按F9继续执行程序。修改到此成功,如图7所示。
图7
2.调试案例:破解序列号验证程序
在Windows中,只要API函数被使用,想对寻找蛛丝马迹的人隐藏一些东西是比较困难的。因此,分析一个程序时,用什么API函数作为切入点就显得比较关键了。先把TraceMe这个序列号验证程序流程图给大家展示出来,如图8所示。
图8
第1步:运行源文件。如图9所示。
图9
第2步:加载目标文件调试。设置OllyDbg中断在程序的入口点,如图10所示。
图10
加载之前,我们先看看以下名词。
Systembreakpoint:系统断点,OllyDbg用CreateProcessA加载DEBUG_ONLY_THIS_PROCESS参数执行,程序运行之后会触发一个INT13,在系统空间里。
Entrypointofmainmodule:主模块的入口点,即文件的入口点。
WinMain:程序的WinMain()函数入口点。
第3步:找到API函数。
本例中是GetDlgItemTextA或GetDlgItemTextW,在它下方的调用处及以下会出现之前写入的用户名和密码。通过设置Z标志位(本例为Je处),将je修为nop,保存、备份,就完成了修改TraceMe。步骤如图11所示。
调试成功后,下面用相应指令修改,生成可执行文件,如图12所示。
图12
(1)F2下断点,按【Alt+b】打开断点编辑器,可编辑所有下过的断点,空格键可快速切换断点状态。
(2)当位于某个CALL中,这时想返回到调用这个CALL的地方时,可以按【Ctrl+F9】快捷键执行返回功能。这样OD就会停在遇到的第一个返回命令(如RET、RETF或IRET)。
(3)如果跟进系统DLL提供的API函数中,此时想返回到应用程序领空里,可以按快捷键【Alt+F9】执行返回到用户代码命令。
(4)所谓领空,实际上就是指在某一时刻,CPU执行的指令所在的某段代码的所有者。
(5)如004013F7这类地址一般是可执行文件领空,7C8114AB这类大地址一般是系统DLL所在的地址空间。
(6)程序通常读取文本框内容的字符串用的是以下两个函数:GetDlgItemTextA(GetDlgItemTextW),GetWindowTextA(GetWindowTextW)。
(7)一般我们要结合经验通过猜测的方式多尝试几遍设陷阱,找出相关的函数。
(8)按【Ctrl+G】键打开跟随表达式的窗口。也可以通过“Ctrl+N”键打开应用程序的导入表(输入表),然后查看应用程序总共导入了哪些函数来以此推断需要在哪里挖坑下陷阱!
(9)关于返回值,汇编代码的返回值约定是存放在eax这个寄存器里边的,如果32位的eax不够存放返回值,系统会将返回值放在内存某个位置并把该位置的地址放在eax返回。
实战案例:软件破解完全接触
1.破解逆向分析软件
reverse就是逆向的意思,软件运行效果如图13所示。
图13
第1步:进入之后,按F8定位到这个jnz位置。经过试验,发现如果跳转未实现的话,会直接弹出失败信息的messagebox,如图14所示。
图14
第2步:通过设置,将此处的jnz跳转实现。(方法:将零标志位“Z”改为0)。接着往下走,此处的jnz同理也改为跳转实现,如图15所示。
图15
凡是跳转到此地“keyfileisnotvalid.sorry”的跳转都要使之相反,否则依然失败。碰到JL的跳转。即是S标志位和O标志位不同,jl指令会跳转。不让它跳转的话,就将二者修改为相同,任意改其中一个都行,如图16所示。
图16
第3步:现在来到此处jmp,发现已经连接到了跳转成功之处了!如图17所示。
图17
第4步:下面添上我们需要的补丁,然后保存。需要改为跳转的,用jmp汇编进去;需要改为不跳转的,直接用nop汇编。保存修改后的文件,运行如图18所示。
图18
2.去除讨厌的NAG窗口
nag本意是烦人的意思,nag窗口是软件设计者用来时不时提醒用户购买正版的警告窗口。软件设计者可能认为当用户忍受不了试用版中的这些烦人的窗口时,就会考虑购买正式版本。一般nag在程序启动或退出的时候弹出来,或者在程序运行的某个时刻突然蹦出来吓你一跳。今天的任务是用不同的几种方法来去除烦人的NAG窗口。一般情况下,一个注册后的软件,他是不会弹出NAG窗口的。所以,一般在程序启动的时候,他会有一段代码检查改程序是否已经被注册,我们可以先把这个程序的注册破解掉,NAG窗口即会自动消失。
试验软件:RegisterMe.exe。
把程序运行一遍之后我们发现程序有两个NAG,一个是在程序界面启动前出现,另一个是在程序关闭后出现的。如图19所示。
图19
步骤1:打开OD载入该文件,跳过第一个提示框的4种方法。如图20所示。
图20
(1)je处汇编为jmp,如图21所示。
图21
( 2 )选中鼠标右键,在弹出的菜单中选择【二进制】→【用nop填充】,如图22所示。
图22
(3)将push0改为push1(因为1是一个不存在的句柄,从而导致下面的messagebox也不存在。也就是句柄无意义,子进程就消失),如图23所示。
图23
(4)修改程序入口点。
进入内存分布图,找到PE文件头,双击进入并找到AddressOfEntryPoint。它在内存中的对应地址为4000E8。回到cpu中,在数据模块中按下【ctrl+g】,并填入4000E8,将其本来的入口点值1000修改为1024,如图24所示。
图24
步骤2:回到cpu窗口中,在数据部分找到跟随地址00400E8,如图25所示。
图25
步骤3:对此处进行修改,将00改为24。这样,程序的入口位置就由1000变为1024,就跳过了第一个NAG弹出窗口messagebox,如图26所示。
图26
步骤4:再处理之后的另一个NAG弹出窗口。可以使用nop汇编掉,也可以将push0改为push1进行修改。在这里,GetModuleHandleA这个API函数用于获取程序的ImageBase(基址)。这个程序的MessageBox的OwnerHandle(父窗口句柄)为0(NULL),我们可以将这个值改为一个不存在的值,例如1,这样它就找不到,就不会被显示出来。
通过上面的操作,我们可以非常方便地达到调试目的。尤其是掌握相关指令后,多多实践、灵活运用,就可以达到灵活观察和控制目标软件的目的。
(完)
本文内容所提及均为本地测试或经过目标授权同意,旨在提供教育和研究信息,内容已去除关键敏感信息和代码,以防止被恶意利用。文章内提及的漏洞均已修复,作者不鼓励或支持任何形式的非法破解行为。