160个CrackMe之001

160个CrackMe之001

环境和工具

Win10+OD+PEID

程序分析

  • 想要破解一个程序,首先我们要了解它,知道它的执行流程,这要我们才好反向跟踪
  • 怎么搜集信息呢?程序本身和外部工具
  • PEID查壳后发现没有壳,是一个Delphi的程序
  • 打开程序Acid burn.exe运行,我么发现这个程序破解分两部分:
  1. 一个是Serial/Name,需要输入正确的用户名和密码才能通过
    160个CrackMe之001_第1张图片
  2. 一个Serial只需要输入一个序列号就可以了
    160个CrackMe之001_第2张图片

第一部分

我们开始第一个,先随意输入一个用户名密码:
Name:15pb
Password:123456
点击Check It Baby! 会弹出一个对话框提示信息: Sorry, The Serial is incorrect !
这说明作者检测我们输入错误会弹出提示信息,我们只需要定位到弹出对话框或者字符串位置,往上找到判断代码Nop掉就爆破成功

分析过程

  • 程序拖到OD
  • 搜索字符串 Sorry, The Serial is incorrect !
  • 发现有两处,在两个地方分别下断点
    在这里插入图片描述
    OD运行程序,输入用户名密码:
    Name:15pb
    Password:123456
    点击Check It Baby!
    程序会断在这个地方
    160个CrackMe之001_第3张图片
    提示信息的字符串我们找到了,但是对话框还没弹出来,可能有人会担心会不会找错了,毕竟搜索出来了两个字符串.记住位置,F9继续运行
    会弹出一个对话框提示信息: Sorry, The Serial is incorrect !
    这时不要急着点确定,按F12暂停,打开调用堆栈
    160个CrackMe之001_第4张图片
    发现了弹出对话框MessageBox,惊喜有木有,两个主模块调用分别过去看一看,发现一个是函数MessageBox调用的位置,一个就是我们字符串下面的CALL,这就说明我们找对位置了.
    OK,分析一下得到的信息:
  • 一个CALL对我们输入的用户名密码做了验证,根据返回值跳转(JNZ)
  • 返回值不等于0说明用户名密码错误,跳转调用MessageBox弹出错误提示信息

我猜测流程可能是这样的,对不对?需要验证一下:

  • 在JNZ上的CALL下断点,重新运行
  • 到达断点后,我们直接把跳转Nop掉,运行一下看看,发现成功了,这说明我们的猜想没错,到这其实就爆破成功了。

想写注册机的话我们还是要详细分析一下,重新运行程序
程序断下来后,我们先观察参数(Delphi是寄存器传参)

  • 参数一:EAX=Local4=“CW-4018-CRACKED”
  • 参数二:EDX=Local3=“123456”(是不是很熟悉,这不就是我们输入的密码吗?)
    160个CrackMe之001_第5张图片
    我猜这个CW-4018-CRACKED应该就是真正的密码了,是不是呢?试一下,成功了!!!换个名字试一下,又不行了!!!
    总结一下:动态密码,并且这个密码和用户名相关(应该是根据算法计算出来的)
    到现在我们还没看见用户名,往上找,发现一个有意思的地方,这个字符串是不是有点眼熟,然而它并没有执行,那JGE和JMP两个跳转就很关键了,jmp直接就跳过了我们弹出对话框的地方,它肯定不是,在JGE下断点,先看看
    160个CrackMe之001_第6张图片
    分析参数发现:跳转后第一个CALL的参数EDX就是用户名,F8走一遍:
    注意观察指针参数的传入传出变化以及返回值
0042FA79  |> \8D55 F0       LEA EDX,[LOCAL.4]                  ; |跳转位置,EDX=username
0042FA7C  |.  8B83 DC010000 MOV EAX,DWORD PTR DS:[EBX+0x1DC]   ; |
0042FA82  |.  E8 D1AFFEFF   CALL              ; \用户名长度
0042FA87  |.  8B45 F0       MOV EAX,[LOCAL.4]                  ;  eax=name
0042FA8A  |.  0FB600        MOVZX EAX,BYTE PTR DS:[EAX]        ;  AL=name[0]
0042FA8D  |.  F72D 50174300 IMUL DWORD PTR DS:[0x431750]       ;  eax=name[0]*0x29
0042FA93  |.  A3 50174300   MOV DWORD PTR DS:[0x431750],EAX    ;  temp=name[0]*0x29
0042FA98  |.  A1 50174300   MOV EAX,DWORD PTR DS:[0x431750]
0042FA9D  |.  0105 50174300 ADD DWORD PTR DS:[0x431750],EAX    ;  temp=(name[0]*0x29)*2
0042FAA3  |.  8D45 FC       LEA EAX,[LOCAL.1]
0042FAA6  |.  BA ACFB4200   MOV EDX,Acid_bur.0042FBAC          ;  edx=CW
0042FAAB  |.  E8 583CFDFF   CALL Acid_bur.00403708             ;  local1=CW
0042FAB0  |.  8D45 F8       LEA EAX,[LOCAL.2]
0042FAB3  |.  BA B8FB4200   MOV EDX,Acid_bur.0042FBB8          ;  edx=CRACKED
0042FAB8  |.  E8 4B3CFDFF   CALL Acid_bur.00403708             ;  local2=CRACKED
0042FABD  |.  FF75 FC       PUSH [LOCAL.1]                     ;  CW
0042FAC0  |.  68 C8FB4200   PUSH Acid_bur.0042FBC8             ;  看了下可能是个字符串
0042FAC5  |.  8D55 E8       LEA EDX,[LOCAL.6]                  ;  edx=local6=0
0042FAC8  |.  A1 50174300   MOV EAX,DWORD PTR DS:[0x431750]    ;  咦?这不是我们的首字母加密值吗?
0042FACD  |.  E8 466CFDFF   CALL Acid_bur.00406718             ;  Local6=4018
0042FAD2  |.  FF75 E8       PUSH [LOCAL.6]                     ;  4018
0042FAD5  |.  68 C8FB4200   PUSH Acid_bur.0042FBC8             ;  算法相关字符串
0042FADA  |.  FF75 F8       PUSH [LOCAL.2]                     ;  local2=CRACKED
0042FADD  |.  8D45 F4       LEA EAX,[LOCAL.3]                  ;  local3=0 是不是该注意了
0042FAE0  |.  BA 05000000   MOV EDX,0x5                        ;  ??? 没看懂继续走
0042FAE5  |.  E8 C23EFDFF   CALL Acid_bur.004039AC             ;  local3=CW-4018-CRACKED 密码出现了
0042FAEA  |.  8D55 F0       LEA EDX,[LOCAL.4]                  ; |
0042FAED  |.  8B83 E0010000 MOV EAX,DWORD PTR DS:[EBX+0x1E0]   ; |
0042FAF3  |.  E8 60AFFEFF   CALL              ; \strlen
0042FAF8  |.  8B55 F0       MOV EDX,[LOCAL.4]                  ;  EDX=密码
0042FAFB  |.  8B45 F4       MOV EAX,[LOCAL.3]                  ;  CW-4018-CRACKED
0042FAFE  |.  E8 F93EFDFF   CALL Acid_bur.004039FC             ;  比较密码和计算出来的值
0042FB03  |.  75 1A         JNZ SHORT Acid_bur.0042FB1F

可以发现从用户名到密码出现中间有很多CALL,能F8坚决不F7,不可能每个CALL都进去看的,如果你见CALL就进,大概率分析一会你都不知道你在哪了,想一想是不是呢?
分析方法总结:

  • 观察参数,注意参数传入传出的变化,一旦有变化,地址?ASCII码?Unicode?每种格式都看一看,实在看不出来(可能确实没有意义,可能没有联想到一些东西,不要紧打个?看看别的例如返回值或者继续往下走)不可能全部看懂的(我说的是我,大佬除外)
  • 观察返回值,方法同上

多走几次就会发现,CW和CRACKED是固定不变的,我唯一变得就是中间的数字(如4018)关键函数很明显了对不对,搞明白它是怎么计算的就可以完美破解了

0042FABD  |.  FF75 FC       PUSH [LOCAL.1]                     ;  CW
0042FAC0  |.  68 C8FB4200   PUSH Acid_bur.0042FBC8             ;  看了下可能是个字符串
0042FAC5  |.  8D55 E8       LEA EDX,[LOCAL.6]                  ;  edx=local6=0
0042FAC8  |.  A1 50174300   MOV EAX,DWORD PTR DS:[0x431750]    ;  咦?这不是我们的首字母加密值吗?
0042FACD  |.  E8 466CFDFF   CALL Acid_bur.00406718             ;  Local6=4018

仔细分析,首字母加密值0xFB2换为10进制就是4018,一开始犯错误见CALL就进,分析了老半天,搞了半天才发现其实这个CALL也不用分析的,我们一开始就算出来了

00406718  /$  83C4 F8       ADD ESP,-0x8
0040671B  |.  6A 00         PUSH 0x0
0040671D  |.  894424 04     MOV DWORD PTR SS:[ESP+0x4],EAX     ;  首字母加密值
00406721  |.  C64424 08 00  MOV BYTE PTR SS:[ESP+0x8],0x0
00406726  |.  8D4C24 04     LEA ECX,DWORD PTR SS:[ESP+0x4]     ;  ecx=首字母加密值
0040672A  |.  8BC2          MOV EAX,EDX                        ;  local6=0
0040672C  |.  BA 44674000   MOV EDX,Acid_bur.00406744          ;  %d
00406731  |.  E8 8A080000   CALL Acid_bur.00406FC0             ;一开始我跟进去了,哈哈,不用进去
00406736  |.  59            POP ECX
00406737  |.  5A            POP EDX
00406738  \.  C3            RETN

注册机算法

总结:根据用户名首字母算出一个数,在获得两个固定字符串CW和CRACKED,拼接起来,密码格式:CW-用户名首字母加密值(十进制)-CRACKED
我们用C/C++代码还原一下

int mian()
{
	printf("输入用户名(不能小于4位):\r\n");
    // 取第一个字符值
    int cName = getchar();
    cName *= 0x29*2;
    printf("密码: CW-%4d-CRACKED\r\n",cName);
    system("pause");
    return 0;
}

到此第一部分就算破解完成了。

第二部分

我们开始第二个,先随意输入一个序列号:123456,弹出对话框:Try Again!!
老方法搜索字符串下断点,OD提示我们字符串在数据区,下内存访问断点,重新运行OD,停下后查看调用堆栈
160个CrackMe之001_第7张图片
看了下这里调用MessageBox弹出提示信息,说明已经判断完了,这应该不是我们要找的地方,在两个地方下断点后重新运行,继续看调用堆栈,找上一层
160个CrackMe之001_第8张图片
我们发现调用只有一处地方,应该就是我们要找的地方了,看一看
在这里插入图片描述
160个CrackMe之001_第9张图片
JNZ很关键,在它上面的CALL下断点(这个CALL应该就是验证函数)
在这里插入图片描述
参数很明显可以看到真正的序列号,试了试,确实是真的
往上翻了翻,F8走一遍,序列号是固定的就是:Hello Dude!

你可能感兴趣的:(逆向分析)