本帖最后由 yysniper 于 2015-4-26 21:33 编辑
翻译说明:
1、本教程在 52 破解论坛 及 看雪论坛 全球同步首发!
2、本教程翻译自国外的The Legend of Random的系列教程,英文原文地址: http://thelegendofrandom.com/blog/sample-page。本翻译教程只是为了给不愿看英文教程以及英文水平不好的人提供方便,同时也是自己的学习过程。该教程对英文水平要求不是很高,不过个人水平有限,有些地方翻译不准的请批评指正。
3、本翻译教程请勿用于商业用途。另,转载请注明!!!
4、感谢The Legend of Random!
发帖说明:
根据译者的时间安排,快的话2-3天会上传一章,慢的话就不造了。如果有段时间没更新请勿怪,因为译者的工作性质,有时是接触不到网络的。
其他章节:
第五章:第一次破解(算是)
一、简介
此次教程通过预览一个crackme,我们会结束Olly使用方面剩下的内容。好吧,算是一个crackme。其实就是我们前面使用的程序,不过被修改成需要序列号注册了,如果输入正确序列号会显示一个好消息,否则显示一个坏消息。我选择这么做而不是用一个完全不同的crackme,是因为我想要你能够专注于序列号校验程序部分,而不是陷入其他的代码中。下一课我们会研究一个真正的crackme(我保证)。 此次教程你所需要的就是一个 OllyDbg(我的版本或者原始版本都可以),以及一个我改进了的crackme。顺便说一下,我把改进后的crackme叫做“First Assembly Kracking Engine”,或者是F.A.K.E。它包含在此次教程的文件下载中。(是的,Gdogg,我知道Kracking不是以字母“K”开头的。译者注:如果取crack首字母,最后缩写就是face了,还有那个Gdogg我不造啥意思) 我们开始吧。
如果你在Olly中载入了FAKE.exe的话,就会发现第一页代码和我们上一次学习用的程序一样。
运行下程序,看看它如何工作的是及其重要的。
点击注册弹出下面的对话框。
输入序列号。
5
在点了Enter Serial后,出现了下面这个坏消息。
6
真见鬼!我那么努力的尝试!!!
现在我向你介绍每个新手查找注册校验代码的第一个方法。
二、搜索所有的文本字符串
先说一下,有许多“老练”的逆向者(或破解者)觉得这个方法已经很少用了。因为这个方法太过于明显了,所以凡是想保护自己的软件不被逆向的人都会让这招失效。这些软件被压缩、保护、加密或修改,只要作者不是一个完完全全的傻子,就会加密字符串以让“Search for strings(搜索字符串)”方法失效。话虽如此,不过我还是发现有许多傻子,这个消息可别告诉任何老鸟,所以我做的第一件事就是检查这个(ps.这其实也是老鸟做的第一件事)。 基本上,该方法都会涉及到让Olly搜索你的程序的内存空间,搜索任何看起来像是ASCII或Unicode文本字符串。通常,可以立即发现该方法好不好用,会有大量的文本字符串,许多看起来很诱人(比如“Thank you for registering!!!(谢谢注册!!!)”)。或者是有很少的字符串,而且许多都像这样“F@7=”。 了解一个二进制文件中是否有合法字符串可以给你一些有价值的信息。比如二进制文件是否通过某种方法被压缩或保护,是否是一个恶意二进制文件(毕竟,“Send all user’s passwords to www.badguys.com”这样的句子不会是一个非常负责任的病毒所写吧),甚至二进制文件是用非常少见的语言所写。 咱们来看看具体怎么做。右键反汇编窗口,选择“Search for”->“All Referenced Text Strings”。
7
然后Olly就会搜索程序的内存空间,并显示文本字符串窗口(Text Strings Window):
8
嗯,看起来很有意思吧:)注意这个列表是真的短,因为这个程序确实非常短小。一般来说,会有数千行字符串。还有,你注意到我注意的了吗:
9
前途有望啊。咱们跳到代码那看看有什么:双击“That serial is correct!!!!!”那一行,Olly就会在反汇编窗口显示那一块代码:
10
是时候介绍第二条规则了
R4ndom’s Essential Truths About Reversing Data: R4ndom关于逆向数据的必备真理:
#2:大多数的保护机制是可以简单的通过修改一个跳转指令来绕过“坏”代码直接跳到“好”代码的。
意思是几乎每一次在坏消息显示之前,就会有某种检查(我们注册了吗?注册码对不对?试用时间过了吗?......),对比之后就有一个跳转,至于是跳到好消息还是坏消息则依赖于对比的结果。 我们自己来找找看啊...。好消息“This serial is correct!!!!”是从401222开始的,向上翻找跳转语句,尤其是它前面有某种比较(或CALL)的跳转语句。如果是一个CALL,可以猜测比较是在CALL内部进行的...。我们的例子中,第一个跳转是在401220的JNZ。我在图中加了一个箭头,向你演示了如果跳转成立的话,将会跳到哪去:
11
嗯。注意它刚好跳过了我们想要的消息,跳到了我们不想要的消息。不过,注意在JNZ指令的前面是一个CMP指令。意思是,这个是Olly决定显示我们想要还是不想要的消息的关键点。我们再向上翻翻:
12
在401212有另一对CMP/JNZ,在401207有最后一对。凑近点看,你会发现所有的三个跳转都跳过了好消息,跳到了坏消息那。逻辑上,这意味着有三件事被检查,触发任何一个都会命中坏消息。不过,如果我三个跳转都不跳会怎么样?好吧,你会看到我们将空降到好消息那。所以,真正的意思是,如果我们让这些跳转都不跳,程序会“空降”到好消息那里(译者注:这里作者用的是“fall through”,大概意思是如果将三个jmp指令当做一层层的阻碍的话,我们直接穿过这些阻碍到达显示好消息的代码,就是将这三个jmp无视掉当作透明的。有些东西可意会,不好言传,所以我将它翻成“空降”)。 我们运行下程序看看它做了什么,不过我先向大家介绍点别的。
三、如何添加注释
注释是很重要的,尤其是在你开始分析错综复杂的代码时。代码本来就很难读,不过有了注释后,我们就可以在非常重要的地方提醒自己。我准备为每个JNZ指令添加注释,以此来提醒我们自己什么需要被发生。 要添加注释,你可以双击要添加注释的那行的最后一列(那里,Olly已经放置了类似于“This is the correct serial!!!”这样的其他注释),也可以先选中要添加注释的那行,然后按一下“;”键。好,我们先选中40120A那行,然后按一下分号键,接着输入“We do NOT want to jump here!”。现在,给401215和401220添加同样的注释。这样就给每个JNZ指令添加了注释:
13
现在让我们在401201处设置一个断点(在跳转指令前面的其他地方设断点也行):
14
让程序跑起来。点击crackme上面的“Register”,输入序列号,再点一下“Enter serial”。Olly就会暂停在断点处:
15
现在,我们第一个要注意的是我们停止的那行:
MOV EBX, DWORD PTR DS:[403078]
从上一课中我们知道该如何查看该内存地址的内容,在指令上右键,选择“Follow in Dump”->"Memory Address"。然后我们就可以在Olly的数据窗口中看到该内存的内容:
16
好,好,好。这不就是我们刚刚输入的序列号嘛。所以,根据这条指令,我们知道了前面四个字节(因为EAX是32为寄存器)被载入EBX,也就是31 32 31 32,用ASCII码表示就是“1212”。按一下F8再检查EBX:
17
如果你想看看EBX中的ASCII字符,你可以双击EBX寄存器,就会显示几组不同格式的数据,其中一组就是ASCII:
18
*为了后面用到,如果你想对不同的寄存器尝试不同的值得话,记住这也是“即时”修改寄存器的一种方法。 我猜你已经从汇编语言的书中知道了这种方法(我的意思是,来吧!我甚至在工具区上传了一个!!!),我不需要讨论这个,只需要复习下。
四、小端序列
(至少你需要了解这方面内容) 处理器在内存中存储数据是不同的,这依赖于处理器的架构。内存中的数据存储有两种方法:一个叫大端(Big-Endian),另一个叫小端(Little-Endian)。Intel用的是小端,你必须要适应这个,否则你会晕头转向的。举个例子:假定一个地址7E04F172(是一个4字节,32位数)。将其按字节拆分,会得到7E、04、F1、72。现在,人们可能会认为将这些字节存储在内存(假定地址是1000)中时应该是这样的: 1000::7E 1001::04 1002::F1 1003::72 任何正常人都会这样想。但是Intel的开发人员比我们这些普通人更聪明,他们决定以一种更加符合逻辑的方法来存储: 1000::72 1001::F1 1002::04 1003::7E 上面的第一个例子是大端序列,意思是数字的最大的那端(以十进制序列形式)在内存中最先被存储。因为7E000000比040000大,所以第一个字节被存储在第一个位置,第二个字节被存储在第二个位置,以此类推。第二个例子(明显更加的聪明)叫做小端序列,意思是首选存储最小的字节(案例中是4号字节),后面依次是第三个字节、第二个字节、第一个字节。因为72小于F100,所以会被先存储。 当你在内存中从一边往另一边看的时候,就会发现用小端而不是它大哥真的很天才。在大端中,数字7E04F172看起来像这样:
7E04F172
明显很乱。感谢上帝,使用小端的话,同样的数字7E04F172看起来更具有逻辑性:
72F1047E
你说啥?蠢的太明显了吧,大端更合理吧。但话又说回来,你又不是Intel的半人半神的开发者,所以你甚至不具备弄明白为什么这要优越得多的脑力。无论如何,先不管各种讽刺,这意味着当你看代码时,无论是磁盘里的还是内存里的,你必须将4字节数字反过来。当然,Olly有时已经为你做了这些,这让情况变的更糟了,就像下面的图片这样:
19
到目前为止,这是我想要说的全部。不过,过会我就会告诉你字节序。 现在,回到我们的寄存器窗口:
20
注意,十六进制的是小端序列(应该是31323132),那个Char是向后的,因为我的序列号是以1212开头的,而不是2121。相信我,你会用到这些的。 现在看看下一条指令:
CMP BL, 61
这是一个很明显的比较语句,比较BL的值,也就是EBX寄存器的第一个字节与61(hex)进行比较。我们真的没什么线索来了解这是什么意思,所以我们单步步过它。最后我们来到了第一条JNZ指令:
JNZ SHORT FAKE.401236
这里我们回想一下,我们可以看到我们前面做的注释,就是我们不想让这个跳转实现。这里提醒一下,JNZ的意思是非0的时候跳转。所以,这两行的意思是“如果BL的值不等于61h,就跳转到坏消息”。我们可以清楚的看到EBX寄存器的右边的字节(BL)不是61h,而是31h。我们已经卡在这了,那个跳转会实现的,但是我们又非常的不想要它实现file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps9EB5.tmp.png。 等等!Olly是一个“动态”的调试器,我们应该可以动态的实现跳转!好吧,因为你很可能已经读了汇编语言书籍中关于标志位的整个章节,所以我不准备讨论这个。
五、CPU标志位
前面的章节中我们简要的讨论了标志位,我也确实不准备深入的探讨这个问题,因为我确信你的汇编语言书籍的目录中有一个“F”章节。标志位可以让处理器知道某条指令的输出是什么。在Intel库中有大量的指令可以影响到标志位,不过最重要(至少对于逆向来说)的是“compare(比较)”指令。基本上,CPU比较两个项目之后,会根据它们的相互关系属性(相同?一个大?一个小?)来设置标志位,再根据这些标志位来执行相应的跳转语句。这其实是表达IF THEN语句的非常奇特的方式。例如,在高级语言中有如下代码:
if( serialNumber == 3 ) dontShowNag(); else showNag();
用伪汇编语言来表示,同样的指令应该类似下面的代码:
compare serialNumber with 3 jump (if they are equal) to dontShowNag(); jump to showNag();
用真正的汇编表示有可能像这样:
MOV EAX, addressOfSerialNumber CMP EAX, 3 JE addressOfDontShowNag JMP adressOfShowNag
首先,EAX中存储着我们的序列号。下一步,它和“3”进行比较。如果等于3就跳到dontShowNag()。如果不等于3,就跳过JE(如果相等就跳转——jump if equal)指令,执行JMP(JuMP)指令。不管任何标志位,自动跳到showNag()。 重要的标志位(对于我们来说)有0标志位和进位标志位,在Olly中分别显示为“Z”和“C”。基本上,通过修改两个标志位中的一个,我们就可以阻止(或者强制)程序中的任何跳转,
21
就像我们下面要介绍的: 在暂停的那行(第一个JNZ),通过那个红色的箭头,我们可以看到Olly准备执行这个跳转。如果该跳转不会被执行,这条线就会显示灰色。如果你没有用我所用的Olly,就不会有这个箭头,这样的话你可以看反汇编窗口和数据窗口中间的那一块,Olly会告诉你跳转会不会被执行。本例中,会有如下显示:
22
现在我们知道了,如果不做点什么的话,Olly就会执行该跳转。那我们就干点什么吧。看看寄存器窗口,找到“Z”标志位:
23
注意那有个0。意思是,在61h和BL的内容(31h)之间的比较结果是0,或者叫false,所以它们不相等。现在我们明白了为什么 不是0就跳转 指令会跳转了,因为就目前来说,0标志位没有被置位,所以它是“非0”。现在,双击零标志位后面的那个0,它就会变成一个1:
。然后注意看那个箭头,变成灰色了(Olly也会提示跳转不成立):
24
我们已经修改了Olly的标志位,同时我们也修改了程序的行为file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3E21.tmp.png。大哥继续,按下F8(你已经学会了),我们不会执行该跳转:O。我们现在来到了看起来一样的代码段,除了EBX中存储的是我们序列号的第二个字符,它将会与62h进行比较而不是61h:
25
我们知道我们序列号的第二个数字并不是62h,现在知道该怎么做了吧。F8直到JNZ语句,双击零标志位,继续下去!!!你会跳过那个JNZ指令。快要成功了!!!最后一个是将我们序列号的第三个数字与63h进行比较。我们序列号的第三个数字是31h,所以该跳转正常来说是要执行的。继续,你知道该怎么做的。跳过了第三个跳转,我们来到了401222:
26
你的心是不是开始扑通扑通的了,因为我认为我们都知道接下来会发生什么。在我们和救世主之间再也没有跳转了,所以无论你是单步步过下面的指令(如果你喜欢留悬念的话)还是直接运行程序(如果你和我一样不能忍受悬念的话),我们终会到达天堂(译者注:这段比喻感觉好猥琐):
27
六、家庭作业
我知道你不喜欢,这一章已经让大家很兴奋了,不过我会以两件事来结束本章。第一个是:
R4ndom’s Essential Truths About Reversing Data: R4ndom关于逆向数据的必备真理:
#3:仅仅读教程,你是学不会逆向工程的。你必须亲自操作,而且必须大量的实践。
根据新规则,我会留一些作业。你的任务,你应该已经接受了,找出序列号。意思是,在让JNZ跳转不实现的情况下,你必须在序列号文本框输入的内容是什么?在不以任何方式修改应用程序的情况下,在输入正确的序列号以后,程序显示了“That Serial is Correct!!!!!!”,你就知道你找对了。
本文PDF文件下载(已排版):
教程五:第一次破解(算是).zip
(1.25 MB, 下载次数: 423)
本文相关附件下载地址(国外链接,不是一直好用):
包含FAKE.exe、英文视频教程、英文教程
|