您的位置:首页 > 其它

菜鸟逆袭 CrackMe第一弹

2012-12-28 21:56 429 查看
小弟最近初学破解,这次我第一次破解成功。尽管是在riijj大神的神文的指导下完成(神文出处),但还是很开心。

特发此文。

Ps:可能因为排版问题,中间的分析看上去有点乱,大家可以重点看最后面的分析哦。或者把它复制到txt文本中会看上去会舒服点。。

=============================================================

这是我们要破解的目标:

ncrackme.exe

1.先用peid看了下,没有壳,用VC6.0编写的

2.用插件-超级字符串找到了关键代码位置

3.发现了一个很重要的EAX,Test EAX,EAX 如果EAX是0,则跳转
00401050   .  817C24 08 110>CMP DWORD PTR SS:[ESP+8],111
00401058   .  75 74         JNZ SHORT 2.004010CE
0040105A   .  8B4424 0C     MOV EAX,DWORD PTR SS:[ESP+C]
0040105E   .  66:3D EA03    CMP AX,3EA
00401062   .  75 42         JNZ SHORT 2.004010A6
00401064   .  E8 C7010000   CALL 2.00401230                          ; 注意这里哦!它返回值EAX很关键哦~~
00401069   .  85C0          TEST EAX,EAX                             ; 如果返回值EAX是0,那么Test EAX,EAX ZF肯定是1,否则为0
0040106B   .  6A 00         PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
0040106D   .  68 80504000   PUSH 2.00405080                          ; |Title = "ncrackme"
00401072   .  75 1B         JNZ SHORT 2.0040108F                     ; |  如果ZF是1那么就不会跳走了,就成功了~~
00401074   .  A1 B8564000   MOV EAX,DWORD PTR DS:[4056B8]            ; |  如果ZF是0那么就跳走了,就失败了~~
00401079   .  68 64504000   PUSH 2.00405064                          ; |Text = "Registration successful."
0040107E   .  50            PUSH EAX                                 ; |hOwner => 000906E4 ('Newbie smallsize crackme - v1',class='myWindowClass')
0040107F   .  FF15 C0404000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA
00401085   .  E8 A6020000   CALL 2.00401330
0040108A   .  33C0          XOR EAX,EAX
0040108C   .  C2 1000       RETN 10
0040108F   >  8B0D B8564000 MOV ECX,DWORD PTR DS:[4056B8]            ; |
00401095   .  68 50504000   PUSH 2.00405050                          ; |Text = "Registration fail."
0040109A   .  51            PUSH ECX                                 ; |hOwner => 000906E4 ('Newbie smallsize crackme - v1',class='myWindowClass')
0040109B   .  FF15 C0404000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA
004010A1   .  33C0          XOR EAX,EAX
004010A3   .  C2 1000       RETN 10
004010A6   >  66:3D EB03    CMP AX,3EB
004010AA   .  75 22         JNZ SHORT 2.004010CE
004010AC   .  A1 C0564000   MOV EAX,DWORD PTR DS:[4056C0]
004010B1   .  85C0          TEST EAX,EAX
004010B3   .  74 19         JE SHORT 2.004010CE
004010B5   .  8B15 B8564000 MOV EDX,DWORD PTR DS:[4056B8]
004010BB   .  6A 00         PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
004010BD   .  68 80504000   PUSH 2.00405080                          ; |Title = "ncrackme"
004010C2   .  68 30504000   PUSH 2.00405030                          ; |Text = "good function, i was cracked"
004010C7   .  52            PUSH EDX                                 ; |hOwner => 000906E4 ('Newbie smallsize crackme - v1',class='myWindowClass')
004010C8   .  FF15 C0404000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA
004010CE   >  33C0          XOR EAX,EAX
004010D0   .  C2 1000       RETN 10

4.而EAX是它前面一个call的返回值,顺着这个返回值,我来到了call,要怎么样才能让返回值不会0呢

00401230  /$  8B0D BC564000 MOV ECX,DWORD PTR DS:[4056BC]
00401236  |.  83EC 30       SUB ESP,30
00401239  |.  8D4424 00     LEA EAX,DWORD PTR SS:[ESP]
0040123D  |.  53            PUSH EBX
0040123E  |.  56            PUSH ESI
0040123F  |.  8B35 94404000 MOV ESI,DWORD PTR DS:[<&USER32.GetDlgIte>;  USER32.GetDlgItemTextA
00401245  |.  6A 10         PUSH 10                                  ; /Count = 10 (16.)
00401247  |.  50            PUSH EAX                                 ; |Buffer    存放用户名字的地方
00401248  |.  68 E8030000   PUSH 3E8                                 ; |ControlID = 3E8 (1000.)
0040124D  |.  51            PUSH ECX                                 ; |hWnd => 00160674 (class='#32770',parent=001B065C)
0040124E  |.  33DB          XOR EBX,EBX                              ; |
00401250  |.  FFD6          CALL ESI                                 ; \GetDlgItemTextA 这个函数会把返回值放到EAX吧。。返回值是字符串长度
00401252  |.  83F8 03       CMP EAX,3                                ; 这个地方是比较EAX(值为6)与3的大小,是这个用户名的长度
00401255  |.  73 0B         JNB SHORT ncrackme.00401262
00401257  |.  5E            POP ESI
00401258  |.  B8 01000000   MOV EAX,1
0040125D  |.  5B            POP EBX
0040125E  |.  83C4 30       ADD ESP,30
00401261  |.  C3            RETN
00401262  |>  A1 BC564000   MOV EAX,DWORD PTR DS:[4056BC]            ; 从 JNB 来了这里
00401267  |.  8D5424 28     LEA EDX,DWORD PTR SS:[ESP+28]
0040126B  |.  6A 10         PUSH 10                                  ; 把10压入栈,10是参数1
0040126D  |.  52            PUSH EDX                                 ; 把这个地址0012FAF8压入栈了,这个应该是字符串的地址了,参数2
0040126E  |.  68 E9030000   PUSH 3E9                                 ; 3e9转过来就是1001。。参数3
00401273  |.  50            PUSH EAX                                 ;
00401274  |.  FFD6          CALL ESI
00401276  |.  0FBE4424 08   MOVSX EAX,BYTE PTR SS:[ESP+8]            ; name[0],这里ESP是0012FAD0,用户名所在地址是0012FAD8,ESP+8 后就是“ouyang”的第一个字符,也就是把第一个字符放到EAX
0040127B  |.  0FBE4C24 09   MOVSX ECX,BYTE PTR SS:[ESP+9]            ; 第二个字符放到ECX,name[1]
00401280  |.  99            CDQ                                      ; 把EDX拓展成EAX的高位。。成64位。。也就是********位
00401281  |.  F7F9          IDIV ECX                                 ; 把 EDX:EAX 除以 ECX,余数放在 EDX
00401283  |.  8BCA          MOV ECX,EDX                              ;
00401285  |.  83C8 FF       OR EAX,FFFFFFFF                          ; 把EAX 置为 FFFFFFFF
00401288  |.  0FBE5424 0A   MOVSX EDX,BYTE PTR SS:[ESP+A]            ; 把name[2]放到EDX
0040128D  |.  0FAFCA        IMUL ECX,EDX                             ; ECX和EDX相乘,余数和name[2]相乘
00401290  |.  41            INC ECX                                  ; ECX 自增1,结果增1
00401291  |.  33D2          XOR EDX,EDX                              ; EDX 清0
00401293  |.  F7F1          DIV ECX                                  ; EAX (ffffffff)除以ECX。。
00401295  |.  50            PUSH EAX                                 ; 计算完毕。。0xFFFFFFFF / (1+(name[0] % name[1] * name[2])
00401296  |.  E8 A5000000   CALL ncrackme.00401340                  ; 进去看看

进去后的代码:
00401340  /$  8B4424 04     MOV EAX,DWORD PTR SS:[ESP+4]             ;EAX 赋值给了[4050AC]这个东东啊
00401344  |.  A3 AC504000   MOV DWORD PTR DS:[4050AC],EAX            ;虽然不太明白,但是这个4050AC在后面出现很多哦~
00401349  \.  C3            RETN

出来外面的代码继续: 
0040129B  |.  83C4 04       ADD ESP,4                                ; 清理stack
0040129E  |.  33F6          XOR ESI,ESI                              ; ESI清零
004012A0  |>  E8 A5000000   /CALL ncrackme.0040134A                  ; 进去后

进去后的代码:
0040134A  /$  A1 AC504000   MOV EAX,DWORD PTR DS:[4050AC]     ;刚刚把4050AC的内容也就是刚刚计算完的结果赋值给EAX
0040134F  |.  69C0 FD430300 IMUL EAX,EAX,343FD                ; EAX * EAX * 343FD(十进制 214013)
00401355  |.  05 C39E2600   ADD EAX,269EC3                    ; 上一条指令运算结果后加上269EC3
0040135A  |.  A3 AC504000   MOV DWORD PTR DS:[4050AC],EAX     ; 然后再把这个最终结果放到4050AC的地方去
0040135F  |.  C1F8 10       SAR EAX,10                        ; EAX 右移 10位
00401362  |.  25 FF7F0000   AND EAX,7FFF                      ; EAX 加上 7FFF
00401367  \.  C3            RETN

回到外面的代码继续:
004012A5  |.  99            |CDQ                                     ; 将EDX 由双字拓展到8字节 成 EDX;EAX
004012A6  |.  B9 1A000000   |MOV ECX,1A                              ; 把1A 赋值给 ECX
004012AB  |.  F7F9          |IDIV ECX                                ; EDX;EAX 除以ECX,然后余数放到EDX
004012AD  |.  80C2 41       |ADD DL,41                               ; EDX 的低16位 加上 41
004012B0  |.  885434 18     |MOV BYTE PTR SS:[ESP+ESI+18],DL         ; 把DL赋值给这里面的地址[ESP+ESI+18]
004012B4  |.  46            |INC ESI                                 ; ESI 自增1
004012B5  |.  83FE 0F       |CMP ESI,0F                              ;
004012B8  |.^ 72 E6         \JB SHORT ncrackme.004012A0              ; 结合上一句指令,这应该是要循环16次吧,直到ESI从0变成15
004012BA  |.  57            PUSH EDI                                 ; 循环后的EDI压栈,给用户名腾出了位置啊。。
004012BB  |.  8D7C24 0C     LEA EDI,DWORD PTR SS:[ESP+C]             ; 把用户名"ouyang"放到EDI中
004012BF  |.  83C9 FF       OR ECX,FFFFFFFF                          ; ECX 置为 FFFFFFFF
004012C2  |.  33C0          XOR EAX,EAX                              ; EAX 清零
004012C4  |.  33F6          XOR ESI,ESI                              ; ESI 清零
004012C6  |.  F2:AE         REPNE SCAS BYTE PTR ES:[EDI]             ; 扫描es:edi指向的一系列字节数据,扫描长度由ecx指定,当遇到与al中的数据相等时停止扫描。
004012C8  |.  F7D1          NOT ECX                                  ; 取反
004012CA  |.  49            DEC ECX                                  ; 自减1,到这里才明白,原来是要求 "ouyang"的长度啊。。
004012CB  |.  74 59         JE SHORT ncrackme.00401326               ; 这个应该是如果字符串长度为0 就 。。完蛋,幸好我们的用户名不是0
004012CD  |>  8A4434 0C     /MOV AL,BYTE PTR SS:[ESP+ESI+C]          ; 把 [ESP+ESI+18]的内容还给AL,在往前14条指令中这个[ESP+ESI+18]应该是EDX当时做的运算吧。。
004012D1  |.  C0F8 05       |SAR AL,5                                ; AL 右移 5 位
004012D4  |.  0FBEC0        |MOVSX EAX,AL                            ;
004012D7  |.  8D1480        |LEA EDX,DWORD PTR DS:[EAX+EAX*4]        ; 这以下三段运算。。不知道想表达什么意思
004012DA  |.  8D04D0        |LEA EAX,DWORD PTR DS:[EAX+EDX*8]
004012DD  |.  8D0440        |LEA EAX,DWORD PTR DS:[EAX+EAX*2]
004012E0  |.  85C0          |TEST EAX,EAX
004012E2  |.  7E 0A         |JLE SHORT ncrackme.004012EE             ; EAX 为0 就跳
004012E4  |.  8BF8          |MOV EDI,EAX                             ; 把运算结果赋值给 EDI ,结果是170.。后面要循环170次。。好可怜
004012E6  |>  E8 5F000000   |/CALL ncrackme.0040134A                 ; 进去看看

进去后的代码:
0040134A  /$  A1 AC504000   MOV EAX,DWORD PTR DS:[4050AC]            ; 这是把[4050AC]的那个最终结果赋值给EAX
0040134F  |.  69C0 FD430300 IMUL EAX,EAX,343FD                       ; EAX * EAX * 343FD
00401355  |.  05 C39E2600   ADD EAX,269EC3                           ; EAX + 269EC3
0040135A  |.  A3 AC504000   MOV DWORD PTR DS:[4050AC],EAX            ; 再次把运算结果还给[4050AC]
0040135F  |.  C1F8 10       SAR EAX,10                               ; 右移16位
00401362  |.  25 FF7F0000   AND EAX,7FFF                             ; 加上7FFF
00401367  \.  C3            RETN

出来外面的代码继续;
004012EB  |.  4F            ||DEC EDI                                ; EDI自减1,循环直到为0
004012EC  |.^ 75 F8         |\JNZ SHORT ncrackme.004012E6            ; 循环
004012EE  |>  E8 57000000   |CALL ncrackme.0040134A                  ; 进去看看

进去后的代码(这一段懒得解释了。。和前面的一样):
0040134A  /$  A1 AC504000   MOV EAX,DWORD PTR DS:[4050AC]
0040134F  |.  69C0 FD430300 IMUL EAX,EAX,343FD
00401355  |.  05 C39E2600   ADD EAX,269EC3
0040135A  |.  A3 AC504000   MOV DWORD PTR DS:[4050AC],EAX
0040135F  |.  C1F8 10       SAR EAX,10
00401362  |.  25 FF7F0000   AND EAX,7FFF
00401367  \.  C3            RETN

出来后的继续代码:
004012F3  |.  99            |CDQ                                     ; 又是 EDX;EAX
004012F4  |.  B9 1A000000   |MOV ECX,1A                              ;
004012F9  |.  8D7C24 0C     |LEA EDI,DWORD PTR SS:[ESP+C]            ; 用户名”ouyang“
004012FD  |.  F7F9          |IDIV ECX                                ; 余数还放在EDX哦。。
004012FF  |.  0FBE4C34 2C   |MOVSX ECX,BYTE PTR SS:[ESP+ESI+2C]      ;
00401304  |.  80C2 41       |ADD DL,41
00401307  |.  0FBEC2        |MOVSX EAX,DL
0040130A  |.  2BC1          |SUB EAX,ECX
0040130C  |.  885434 1C     |MOV BYTE PTR SS:[ESP+ESI+1C],DL
00401310  |.  99            |CDQ
00401311  |.  33C2          |XOR EAX,EDX
00401313  |.  83C9 FF       |OR ECX,FFFFFFFF
00401316  |.  2BC2          |SUB EAX,EDX
00401318  |.  03D8          |ADD EBX,EAX
0040131A  |.  33C0          |XOR EAX,EAX
0040131C  |.  46            |INC ESI
0040131D  |.  F2:AE         |REPNE SCAS BYTE PTR ES:[EDI]
0040131F  |.  F7D1          |NOT ECX
00401321  |.  49            |DEC ECX
00401322  |.  3BF1          |CMP ESI,ECX
00401324  |.^ 72 A7         \JB SHORT ncrackme.004012CD
00401326  |>  5F            POP EDI
00401327  |.  8BC3          MOV EAX,EBX                              ; 这里把EBX赋值给EAX了。。这个酱油EBX
00401329  |.  5E            POP ESI
0040132A  |.  5B            POP EBX
0040132B  |.  83C4 30       ADD ESP,30
0040132E  \.  C3            RETN
0040132F      90            NOP
00401330  /$  C705 C0564000>MOV DWORD PTR DS:[4056C0],1
0040133A  \.  C3            RETN                                     ; 前面的指令差不多就不分析了,出来后的结果是EAX为B7 ...要怎么样才能为0呢?

没错。。我们的注册机就是要把EAX(也就是那个酱油EBX)变成0。。
我们把这么一大段中和EBX有关系的指令全部揪出来。。
共有:
0040123D  |.  53            PUSH EBX
0040124E  |.  33DB          XOR EBX,EBX                              ; |
0040125D  |.  5B            POP EBX
00401318  |.  03D8          |ADD EBX,EAX
00401327  |.  8BC3          MOV EAX,EBX                              ; 这里把EBX赋值给EAX了。。这个酱油EBX
其中有用的就是这一句:
00401318  |.  03D8          |ADD EBX,EAX
而这条指令的前一句:
00401316  |.  2BC2          |SUB EAX,EDX
告诉我们。。只要EAX能够和EDX相等,那么EAX就是0,那么EBX也就是0。。
那么要怎么样才能让EAX和EDX相等呢?
找到和EAX以及EDX有关系的指令,啊,往上可以看到这么两句:
00401310  |.  99            |CDQ
00401311  |.  33C2          |XOR EAX,EDX
这两句的意思是,把EDX拓展成EAX的高位,如EAX是FFFFFFF9(-6),那么拓展后EDX;EAX = FFFFFFFF;FFFFFFF9(还是-6)
没错,EDX的每一位都变成了EAX的最高位
然后XOR EAX ,EDX = FFFFFFFF XOR FFFFFFF9  导致了 变成了0000,0006(正6)
很明显,如果本来是+6,那么结果还是正。没错。。这两句是取EAX的绝对值的操作
那么我们应该让EAX为0,导致它的绝对值为0即可,EAX怎么为0呢?
往前看了看:
00401304  |.  80C2 41       |ADD DL,41
00401307  |.  0FBEC2        |MOVSX EAX,DL
0040130A  |.  2BC1          |SUB EAX,ECX
这个是取出DL+‘A’的内容赋值给EAX,然后EAX减去ECX。。
那么这个ECX是什么呢?    MOVSX ECX,BYTE PTR SS:[ESP+ESI+2C] 而这个   SS:[ESP+ESI+2C] 发现了是我们输入的序列号的每一位字符。。。
呵呵,很明显了,知道每一位的DL+'A'(A就是41啊,傻孩子),然后合起来连成一串str就是我们要的序列号了。。
在0040130A 下断点,然后每次记录这个DL+'A'
合起来就是KTKOLB
哈!注册成功!


==================================================================

小弟也是新手一只,有哪里错了,欢迎大神们提出来,一定虚心改正。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  crackme 新手 破解