黑客入门,逆向工程反编译从Crack Me #1开始
在大数据时代,网络安全一直备受重视。黑客一词也成为网络安全的反向代表词,黑客,听起来很酷很拽,他们掌握着很多“神秘”的技术,反编译分析、渗透攻击......简单的黑客技术入门,其实你也可以!
身边的技术大牛常说“我来OD一下看看”,当初天真无知的小编,OD?欧迪?欧弟?下面小编将带你从crackme#1开始完成一次小逆向,并快速掌握OD的一些简单用法,从小白到新手的小逆袭~
所以,什么是crackme?
“Crack me”其实浅显易懂,字面意思google翻译就能贴切表达。本质是一些公开给别人练习逆向分析的小程序,供黑客技术爱好者分析它的加密原理,写成注册机,也是一种学习逆向思维和逆向技术的工具,运行起来后,程序都很小,一般模式是输入serial等信息进行验证。这样讲有点抽象,举个例子,serial就类似于软件注册码,没有注册码就无法使用软件,那么如何独立获取注册码呢?分析它的保护程序算法,这样找到正确serial的过程就称为逆向。
从Crack Me #1 Acid burn开始,按照下面的步骤一步一步走进逆向的大门吧!
Ready!
- 一个辅助工具——OllyDbg(下面简称OD),小编推荐大家使用吾爱版的。
- 一个Crack Me #1 Acid burn.exe小程序,网上有很多可供下载的。
Go!
首先,直接运行Acid burn.exe,观察一下它的模式:
有两种“Serial/Name”和“Serial”,先从简单一点的Serial开始。
Serial模式:
点击“Serial”按钮进入,需要输入一些东西后进行Check验证,一开始当然不知道应该输入什么,那就输入一些任意字符提交看看会出现什么:
出现了弹框,但很遗憾,它提示我们“Try Again!!”,这意味我们的输入是错误的。接下来需要思考,如何获取正确的serial呢?
1.分析程序验证serial的思路
弹框和其中的内容是程序给用户的反馈行为,反馈至少有两种,一种是输入正确的,一种是输入错误的,这样看来,弹框之前,程序一定需要对用户的输入进行验证,从而决定反馈的内容,如果我们能知道程序是怎样决定反馈内容的,就能改变它的判断。
在高级语言中,验证判断会通过if/else条件语句来实现,汇编指令中,相应的则是通过寄存器的值结合相应的跳转指令来实现条件语句的功能。
那么,关键来了,程序在调用这个弹框的函数的附近一定存在跳转,输入正确与否决定了程序的跳转方向:用户输入正确跳转执行什么,输入错误跳转执行什么。
OK,理清思路,首先定位弹框函数位置,通过弹框函数的调用定位关键跳转,在关键跳转附件获取与正确serial相关的信息。
2.获取正确的serial
2.1 定位弹框函数及其调用位置
首先打开OD,把Acid burn.exe放进去,F9运行起来,这时可以看到主界面,同样地,先随便输入一些什么然后Check,出现弹框“Try Again!!”,不要点击“确定”按钮,回到OD中,按F12暂停一下
上图中指令地址为766xxxxx,可以判断不在代码段,先不做分析,用Alt+k查看堆栈段:
MessageBoxA、MessageBoxTimeoutA、WaitMessage等等,这些都是和弹框相关的函数,暂时不需要知道这些函数具体细节,结合函数的名字和实际操作,猜想一下这些函数的效果:弹出对话框、显示对话框的内容,响应对话框的时间,等待用户操作、收到用户反馈后的操作等等。
关注最后一行,“Procedure”标明MessageBoxA函数的起始位置为0042A170,“Called from”标明在哪调用了这个函数MessageBoxA,即可以理解为call MessageBoxA这条指令的位置是0042F504。
下一步,双击进入函数所在位置。在0042A170的位置F2下一个断点,然后F9重新运行,输入任意serial(“1111”)然后Check,程序会暂停在弹框之前。进入OD查看。
下一步,ctrl+G搜索0042F504,调用MessageBoxA的位置:
2.2定位关键跳转位置
下一步,在这个call指令的附近找条件跳转,附近会有验证用户输入的关键操作。
0042F4D5处:jnz short Acid_bur.0042F4F1,意思是结果不为0跳转(ZF=0则跳转),那么接着往上,应该就是决定ZF寄存器值的部分。
继续往上继续分析代码,能够发现下图的内容:
从上图中可知edx中存入了“Hello Dude!”,用户输入的serial“1111”被放进了eax中。可以判断正确的Serial是“Hello Dude!”,那么就可以把它作为serial输入啦,试一试吧!
分析到这里,对serial模式的逆向分析可以算成功了。
3.分析程序验证用户输入的算法
然而,一个有野心的黑客是不会止步于此的,能不能实现不论输入什么都能成功呢?
继续分析程序验证用户输入的算法是什么的:给寄存器eax和edx赋值之后,紧接着有一个call指令,猜测这里就是一个判断用户输入和正确的serial是否一致的函数。
F12下断点,然后重新运行至程序暂停,F8步入跟进:
图中从阴影部分开始:
cmp eax,edx:先对eax和edx进行判断,即判断用户输入和正确Serial是否相等;
je Acid_bur.00403A9A:相等就跳转到结尾处,不相等继续判断。
在右边寄存器窗口将ZF的值改成1,然后F9直接执行,弹窗成功验证通过。最后把修改好的程序dump出来即可。
Serial/Name模式
同样地,先尝试一下,发现也是弹框。
1.定位弹框函数的位置
在OD中F12暂停一下,Alt+k查看一下堆栈段:
MessageBoxA函数的起始位置还是0042A170,调用位置为0042FB32,一样地我们还是在0042A170的位置下断点,然后重新运行,输入一对任意的Serial/Name(1234/2222)提交验证,程序在弹框之前暂停下来,在OD中观察一下:
结合各窗口信息,大胆假设小心验证!
右下方堆栈窗口中,可以看见输入的1234和2222,下面有一个字符串CW-4018-CRACKED,猜测我们输入的name:1234对应的Serial是CW-4018-CRACKED,可以试一试(当然是成功通过了)。
一个合格的hacker还需要继续走下去!
2.分析serial的算法
继续分析程序是如何通过输入的name是如何算出Serial的,那么我们输入任何一个name就都可以自己计算出正确的Serial。
3.定位弹框函数的调用位置
ctrl+G输入0042FB32,跳转到调用MessageBoxA的位置,如下图:
4.定位关键跳转的位置
从call指令位置向上查看,寻找关键跳转的位置,在关键跳转前面,一般就是验证输入的相关函数,如下图:
上图中,eax和edx中分别存入了"CW-4018-CRACKED"和我输入的serial"2222",下面0042FAFE:call Acid_bur.004039FC应该就是验证用户输入和正确的serial是否一致的函数,和serial模式中的验证函数一样,也可以通过修改寄存器的值来通过验证,不做赘述。
那么问题来了,eax中的正确serial"CW-4018-CRACKED"是通过什么算法计算的?继续向上查找指令,如下图:
上图中,程序进行了很多push操作,意味着在利用栈空间保存后续所需的参数和变量,结合右侧部分注释,存在连接符“-”,这是包含在正确serial里的符号,那么下一步查看连接符的附近出现的push [local.6]、Acid_bur.0042FBB8、0042FBAC中是否是serial中的其他字符:
如上图,可判断出这部分代码是将serial的各个部分连接起来组成“CW-4018-CRACKED”,在实验时,多用几个不同的name试几次会发现CW和CRACKED的部分是不变的,变化的只有中间的数字部分。那么中间数字部分的计算代码应该在前面,我们继续往上分析:
如上图,将用户输入的name“1234”存进了eax,紧接着后续是imul,add等数学运算指令,判断这里就是计算serial的指令,下一个断点,然后单步观察一下更清晰,小编将这部分算法加上注释供大家理解,如下图:
编写注册机
最后,我们就可以根据以上的分析写出kengen注册机,就可以任意输入name,自己计算相应的serial啦~
下面是小编用C语言写的kengen,仅供参考:
#include<stdio.h> #include<stdlib.h> #include<string.h> void main(){ char name[20]; scanf("%s",name); int len; len=strlen(name); if(len>=4) { int num; char str1[4]="CW-"; char str2[20]; char str3[10]="-CRACKED"; char serial[50]; num=name[0]*0x29*2; sprintf(str2,"%d",num); sprintf(serial,"%s%s%s",str1,str2,str3); printf("%s ",serial); } else { printf("ERROR!The length of the name can't less then 4 "); } }
Congratulation!
至此你已经完成了一个CrackMe的全过程,逆向的大门已经叩开~