天天看點

菜鳥逆襲 CrackMe第一彈

小弟最近初學破解,這次我第一次破解成功。盡管是在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
哈!注冊成功!









           

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

小弟也是新手一隻,有哪裡錯了,歡迎大神們提出來,一定虛心改正。