针对这次要破解的小程序,熟悉一下OllyDbg调试器的用法。
工作前的准备
OllyDbg调试器的下载:
http://www.pediy.com/tools/Debuggers/ollydbg/OllyICE.rar
本次需要用到的软件:
http://pickup.mofile.com/2970871204857600
OllyDbg调试器界面
将下载的压缩包解压,打开目录,执行OllyICE.exe,这个是汉化修改版的,前人栽树后人凉,希望多了解的,可以看帮助文件或是在《看雪论坛》找相关的资料。
选择“文件”,打开我们这次用到的软件TraceMe.exe。然后先了解一下OllyDbg调试器的界面。

1. 代码窗口
代码窗口显示的是被调试程序的代码,现在我们看到的有三列,第一列是虚拟地址,第二列是机器码,第三列是汇编代码。
2. 信息窗口
调试时,会显示相关的信息提示,如寄存器的值,函数调用等。
3. 数据窗口
以十六进制显示的文件在内存中的数据。
4. 寄存器窗口
显示各寄存器的值。
5. 堆栈窗口
堆栈,一般函数或子程序都会用它来传递参数,变量,如果传递的参数是字符串,在这里可以直接显示出来。
操作基本快捷键
F2 设置断点
F9 运行程序
F7 单步跟踪,遇到CALL等跟进
F8 单步跟踪,遇到CALL等跳过,不跟进
CTRL+F9 直到出现RET指定时中断
ALT+F9 若进入系统领空,可回到应用程序领空
破解小程序
我们先来运行一下TraceMe.exe程序,看看它的注册方式:

输入用户名和假的序列号,提示“序列号错误,再来一次!”,转到我们刚才执行的OllyICE.exe界面。
按F9,在OllyDBG调试器的监视下执行程序,不巧的是OllyDbg调试器不支持中文字符串,否则我们可以在代码窗口点右键→查找→所有参考文本字串,查找刚才我们看到错误提示,直接在相应的虚拟地址上下断点(你可以用W32dsm先查找,记下关键的地址,再在OllyDbg调试器用CTRL+G快捷键转到相应地址下断点)。
这里我们再学习针对API函数下断点的方法:
GetDlgItemTextA 是一个常用的API函数,它的作用是获得对话框文本,此函数在USER32.DLL用户模块,如果成功返回的是文本长度;失败返回0。
为什么这次要用它来下断点?我们执行小程序,在用户名和序列号输入完毕后,点“CHECK”按钮,WINDOWS系统会利用该函数获得我们输入的文本字符串,然后去运算,最后把运算结果送回来,即注册成功或是失败。在这里下断点,就是在注册运算前拦截了程序,用F8一步一步执行程序就可以找到关键点了~
在OllyDbg调试器中按下快捷键CTRL+N,找到USER32.GetDlgItemTextA,选中后按回车键。

打开参考对话窗口:

双击,来到代码窗口的该地址处,按F2下断点(红色背景显示)。断点下好了,也就是说我们找到了很快让我们解决掉该软件的地点喽,剩下的就是在刚才运行的程序里输入用户名和序列号,点“CHECK”按钮,OllyDbg调试器拦截,我们一步步的观察了。

点“CHECK”按钮后,软件拦截成功,这时我们看到了代码窗口的第四列,那是注释列。我们按F8,让程序一步一步地运行,同时注意观察:
004011D7 . 8D5424 4C lea edx, dword ptr [esp+4C] 程序执行到这一步,在信息窗口会出现我们输入的用户名:
堆栈地址=0012F930, (ASCII "76512")
edx=7C92EB94 (ntdll.KiFastSystemCallRet)
004011DC . 8D8424 A00000>lea eax, dword ptr [esp+A0] 程序执行到这一步,在信息窗口会出现我们输入的注册码:
堆栈地址=0012F980, (ASCII "987654321")
eax=00000037
我们还能注意到,在寄存器窗口中,也会适时地显示两组数据放置在了哪个寄存器内。
004011E5 . E8 56010000 call 00401340
经过这个CALL后,我们会在堆栈窗口看到下面的图:

程序在用我们输入的序列号与“1088”做了对比,按F9执行完后面的程式,果然提示我们输入错误。这时候我们用户名不要改,可以再用“1088”输入试试?这个小程序用用户名计算出序列号,然后比较,但比较时序列号是明码的。
我们再从头看一下关键部分:
004011A3 . 8B3D A0404000 mov edi, dword ptr [<&USER32.GetDlgI>; 调用USER32.GetDlgItemTextA函数
004011A9 . 53 push ebx
004011AA . 8D4424 4C lea eax, dword ptr [esp+4C]
004011AE . 6A 51 push 51
004011B0 . 50 push eax
004011B1 . 6A 6E push 6E
004011B3 . 56 push esi
004011B4 . FFD7 call edi ; 返回输入的用户名长度
004011B6 . 8D8C24 9C0000>lea ecx, dword ptr [esp+9C]
004011BD . 6A 65 push 65
004011BF . 51 push ecx
004011C0 . 68 E8030000 push 3E8
004011C5 . 56 push esi
004011C6 . 8BD8 mov ebx, eax
004011C8 . FFD7 call edi ;返回输入的序列号长度
004011CA . 8A4424 4C mov al, byte ptr [esp+4C] 把输入的用户名头一字节拿出来
004011CE . 84C0 test al, al 测试看用户名是不是空的
004011D0 . 74 76 je short 00401248 空的就转到相应提示上
004011D2 . 83FB 05 cmp ebx, 5 不是空的,再测试是否小于5位
004011D5 . 7C 71 jl short 00401248 小于的话就转到相应提示上
004011D7 . 8D5424 4C lea edx, dword ptr [esp+4C] 将符合的用户名放入寄存器中
004011DB . 53 push ebx
004011DC . 8D8424 A00000>lea eax, dword ptr [esp+A0] 将输入的序列号放入寄存器中
004011E3 . 52 push edx
004011E4 . 50 push eax
004011E5 . E8 56010000 call 00401340 这里是计算部分,我们略过,喜欢研究算法的可以进入
004011EA . 8B3D BC404000 mov edi, dword ptr [<&USER32.GetDlgI> 获得对话框的句柄
004011F0 . 83C4 0C add esp, 0C 平衡堆栈(特有的调用约定)
004011F3 . 85C0 test eax, eax 测试EAX中数值
004011F5 . 74 37 je short 0040122E 等于0注册失败,跳到相应提示
我们了解了这段关键的代码,费了半天劲,有嘛用呢?把它改成输入什么都注册成功,然后资源共享……罪过。
我们重点看这一句:
004011F5 . 74 37 je short 0040122E 等于0注册失败,跳到相应提示
如果将汇编代码的je改成nop(空指令,也就是程序执行到这一步什么都不做),或是jne(不等于0注册失败,也就是任意序列号都成),这两种方法都可以实现程序的“暴破”。
OllyDbg调试器很容易修改,在这句代码的汇编语句上双击或是按空格,就打开了汇编窗口。
在文本框中输入nop,点汇编按钮,OllyDbg调试器自动补充指令代码。在代码窗口中点右键,选择复制到可执行文件→所有修改,确定复制。


关闭弹出的的对话框时,确定保存到磁盘,自己取个新的文件名就好了~再执行TraceMe.exe文件,试试注册?