发新话题
打印

[转载]Crackme1 by qxtianlong 的算法分析

[转载]Crackme1 by qxtianlong 的算法分析

文章作者:  rdsnow[BCG][PYG][D.4s]


【作者主页】  http://rdsnow.ys168.com

【 E-mail 】  rdsnow@163.com

【 作者QQ 】  83757177

【文章题目】  Crackme1 by qxtianlong 的算法分析

【软件名称】  Crackme1 by qxtianlong

【下载地址】  附件:crackme1.rar

【破解平台】  Microsoft Windows XP Professional --SP2

----------------------------------------------------------------------------------------------
【文章简介】

最近被Asprotect 2.11壳的Stolen Code搞的头疼,看来偶在脱壳上前途渺茫啊,只能精力集中到算法上了,发现在硬盘上竟然还有个Crackme,打开提示“难度高”,于是就跟进看看。发现这个Crackme爆破难度不大,很容易找到爆破点,看来作者是要找到真注册码,跟出算法。

程序采用了MD5(Usename)=F_En(code)的非明码比较方式。

MD5( )是标准的MD5加密算法没有变形。

F_En( )是作者自己设计的一个加密算法。

F_En( )算法中使用了固定的密钥,给算法注册机制作带来方便,因为密钥的固定,导致在任何机器上密钥初始化过程完全相同。

F_En( )算法中使用的SBox[44]是有44个DWORD元素。

----------------------------------------------------------------------------------------------
【破解过程】

OD插件和W32DASM都没有找到字符串,看来字符加密了。

但是有错误对话框弹出,命令行下断:bp MessageBoxA返回程序领空后向上来到这里:

00401B40  .  6A FF        PUSH -1
00401B42  .  68 3B5A4200    PUSH Crackme1.00425A3B             ;  SE 句柄安装
00401B47  .  64:A1 00000000  MOV EAX,DWORD PTR FS:[0]
00401B4D  .  50          PUSH EAX
00401B4E  .  64:8925 0000000>MOV DWORD PTR FS:[0],ESP
00401B55  .  81EC D4010000  SUB ESP,1D4
00401B5B  .  A1 EC204300    MOV EAX,DWORD PTR DS:[4320EC]
00401B60  .  898424 D0010000 MOV DWORD PTR SS:[ESP+1D0],EAX
00401B67  .  53          PUSH EBX
00401B68  .  B0 5C        MOV AL,5C                      ;  以下给密钥Key赋初值,固定密钥
00401B6A  .  8BD9        MOV EBX,ECX                    ;  Key共128位,分16个byte赋值
00401B6C  .  B1 47        MOV CL,47
00401B6E  .  884424 07     MOV BYTE PTR SS:[ESP+7],AL          ;  byte3=0x5C
00401B72  .  884424 11     MOV BYTE PTR SS:[ESP+11],AL          ;  byte13=0x5C
00401B76  .  68 04010000    PUSH 104
00401B7B  .  8D8424 D4000000 LEA EAX,DWORD PTR SS:[ESP+D4]
00401B82  .  884C24 09     MOV BYTE PTR SS:[ESP+9],CL          ;  byte1=0x47
00401B86  .  884C24 17     MOV BYTE PTR SS:[ESP+17],CL          ;  byte15=0x47
00401B8A  .  50          PUSH EAX
00401B8B  .  8D8B C4000000  LEA ECX,DWORD PTR DS:[EBX+C4]
00401B91  .  C64424 0C 35   MOV BYTE PTR SS:[ESP+C],35          ;  byte0=0x35
00401B96  .  C64424 0E 82   MOV BYTE PTR SS:[ESP+E],82          ;  byte2=0x82
00401B9B  .  C64424 10 33   MOV BYTE PTR SS:[ESP+10],33          ;  byte4=0x33
00401BA0  .  C64424 11 8C   MOV BYTE PTR SS:[ESP+11],8C          ;  byte5=0x8C
00401BA5  .  C64424 12 85   MOV BYTE PTR SS:[ESP+12],85          ;  byte6=0x85
00401BAA  .  C64424 13 77   MOV BYTE PTR SS:[ESP+13],77          ;  byte7=0x77
00401BAF  .  C64424 14 9A   MOV BYTE PTR SS:[ESP+14],9A          ;  byte8=0x9A
00401BB4  .  C64424 15 67   MOV BYTE PTR SS:[ESP+15],67          ;  byte9=0x67
00401BB9  .  C64424 16 45   MOV BYTE PTR SS:[ESP+16],45          ;  byte10=0x45
00401BBE  .  C64424 17 7A   MOV BYTE PTR SS:[ESP+17],7A          ;  byte11=0x7A
00401BC3  .  C64424 18 6D   MOV BYTE PTR SS:[ESP+18],6D          ;  byte12=0x6D
00401BC8  .  C64424 1A 16   MOV BYTE PTR SS:[ESP+1A],16          ;  byte14=0x16
00401BCD  .  E8 D9C30100    CALL Crackme1.0041DFAB             ;  读取用户名"rdsnow[BCG][PYG][D.4s]"
00401BD2  .  8D4C24 34     LEA ECX,DWORD PTR SS:[ESP+34]
00401BD6  .  E8 350D0000    CALL Crackme1.00402910             ;  MD5( )初始化

--> 00402910  /$  8BD1        MOV EDX,ECX
--> 00402912  |.  56          PUSH ESI
--> 00402913  |.  57          PUSH EDI
--> 00402914  |.  33C0        XOR EAX,EAX
--> 00402916  |.  8D72 5C      LEA ESI,DWORD PTR DS:[EDX+5C]
--> 00402919  |.  8BFE        MOV EDI,ESI
--> 0040291B  |.  8942 18      MOV DWORD PTR DS:[EDX+18],EAX
--> 0040291E  |.  8942 14      MOV DWORD PTR DS:[EDX+14],EAX
--> 00402921  |.  B9 10000000    MOV ECX,10
--> 00402926  |.  C702 1C7A4200  MOV DWORD PTR DS:[EDX],Crackme1.00427A1C
--> 0040292C  |.  C742 04 0123456>MOV DWORD PTR DS:[EDX+4],67452301   ;这里看到MD5的四个基本常数了
--> 00402933  |.  C742 08 89ABCDE>MOV DWORD PTR DS:[EDX+8],EFCDAB89
--> 0040293A  |.  C742 0C FEDCBA9>MOV DWORD PTR DS:[EDX+C],98BADCFE
--> 00402941  |.  C742 10 7654321>MOV DWORD PTR DS:[EDX+10],10325476
--> 00402948  |.  F3:AB        REP STOS DWORD PTR ES:[EDI]
--> 0040294A  |.  5F          POP EDI
--> 0040294B  |.  C606 80      MOV BYTE PTR DS:[ESI],80
--> 0040294E  |.  8BC2        MOV EAX,EDX
--> 00402950  |.  5E          POP ESI
--> 00402951  \.  C3          RETN

00401BDB  .  8D8424 D0000000 LEA EAX,DWORD PTR SS:[ESP+D0]
00401BE2  .  C78424 E0010000>MOV DWORD PTR SS:[ESP+1E0],0
00401BED  .  8D50 01      LEA EDX,DWORD PTR DS:[EAX+1]
00401BF0  >  8A08        MOV CL,BYTE PTR DS:[EAX]
00401BF2  .  40          INC EAX
00401BF3  .  84C9        TEST CL,CL
00401BF5  .^ 75 F9        JNZ SHORT Crackme1.00401BF0
00401BF7  .  2BC2        SUB EAX,EDX                    ;  相减得到用户名的长度 22
00401BF9  .  50          PUSH EAX
00401BFA  .  8D8C24 D4000000 LEA ECX,DWORD PTR SS:[ESP+D4]
00401C01  .  51          PUSH ECX
00401C02  .  8D4C24 3C     LEA ECX,DWORD PTR SS:[ESP+3C]
00401C06  .  E8 550D0000    CALL Crackme1.00402960             ;  转存用户名
00401C0B  .  8D5424 24     LEA EDX,DWORD PTR SS:[ESP+24]
00401C0F  .  52          PUSH EDX                      ; /MD5结果保存地址
00401C10  .  8D4C24 38     LEA ECX,DWORD PTR SS:[ESP+38]        ; |
00401C14  .  E8 170E0000    CALL Crackme1.00402A30             ; \MD5(用户名)
00401C19  .  68 04010000    PUSH 104
00401C1E  .  8D8424 D4000000 LEA EAX,DWORD PTR SS:[ESP+D4]
00401C25  .  50          PUSH EAX
00401C26  .  8D4B 74      LEA ECX,DWORD PTR DS:[EBX+74]
00401C29  .  E8 7DC30100    CALL Crackme1.0041DFAB             ;  读取假码
00401C2E  .  8D8C24 D0000000 LEA ECX,DWORD PTR SS:[ESP+D0]
00401C35  .  51          PUSH ECX
00401C36  .  8BCB        MOV ECX,EBX
00401C38  .  E8 73F7FFFF    CALL Crackme1.004013B0             ;  检查注册码的长度和格式,跟进
00401C3D  .  85C0        TEST EAX,EAX
00401C3F  .  74 54        JE SHORT Crackme1.00401C95          ;  上面的call检查假码是否由数字和大写A-F组成
00401C41  .  56          PUSH ESI
00401C42  .  57          PUSH EDI
00401C43  .  8D5424 1C     LEA EDX,DWORD PTR SS:[ESP+1C]
00401C47  .  52          PUSH EDX
00401C48  .  8D8424 DC000000 LEA EAX,DWORD PTR SS:[ESP+DC]
00401C4F  .  50          PUSH EAX
00401C50  .  8BCB        MOV ECX,EBX
00401C52  .  E8 F9F7FFFF    CALL Crackme1.00401450             ;  将假码分成四组Sn0,Sn1,Sn2,Sn3
00401C57  .  8D4C24 0C     LEA ECX,DWORD PTR SS:[ESP+C]
00401C5B  .  6A 10        PUSH 10
00401C5D  .  51          PUSH ECX
00401C5E  .  E8 FDF4FFFF    CALL Crackme1.00401160             ;  F_En( )初始化,跟进
00401C63  .  8D5424 24     LEA EDX,DWORD PTR SS:[ESP+24]
00401C67  .  52          PUSH EDX
00401C68  .  8BC2        MOV EAX,EDX
00401C6A  .  50          PUSH EAX
00401C6B  .  E8 F0F5FFFF    CALL Crackme1.00401260             ;  F_En(假码),跟进
00401C70  .  83C4 10      ADD ESP,10
00401C73  .  B9 04000000    MOV ECX,4
00401C78  .  8D7C24 1C     LEA EDI,DWORD PTR SS:[ESP+1C]
00401C7C  .  8D7424 2C     LEA ESI,DWORD PTR SS:[ESP+2C]
00401C80  .  33D2        XOR EDX,EDX
00401C82  .  F3:A7        REPE CMPS DWORD PTR ES:[EDI],DWORD PTR D>;  MD5(用户名)和F_En(假码)循环比较
00401C84  .  5F          POP EDI
00401C85  .  5E          POP ESI
00401C86  .  75 0D        JNZ SHORT Crackme1.00401C95          ;  关键跳(爆点)
00401C88  .  52          PUSH EDX
00401C89  .  68 147A4200    PUSH Crackme1.00427A14             ;  恭喜
00401C8E  .  68 087A4200    PUSH Crackme1.00427A08             ;  注册成功!
00401C93  .  EB 0C        JMP SHORT Crackme1.00401CA1          ;  F_En( )初始化,跟进
00401C95  >  6A 10        PUSH 10
00401C97  .  68 007A4200    PUSH Crackme1.00427A00
00401C9C  .  68 F0794200    PUSH Crackme1.004279F0             ;  注册码错误!
00401CA1  >  8BCB        MOV ECX,EBX
00401CA3  .  E8 2C950100    CALL Crackme1.0041B1D4             ;  跳出对话框
00401CA8  .  8D4C24 34     LEA ECX,DWORD PTR SS:[ESP+34]
00401CAC  .  C78424 E0010000>MOV DWORD PTR SS:[ESP+1E0],-1
00401CB7  .  E8 34030000    CALL Crackme1.00401FF0
00401CBC  .  8B8C24 D8010000 MOV ECX,DWORD PTR SS:[ESP+1D8]
00401CC3  .  64:890D 0000000>MOV DWORD PTR FS:[0],ECX
00401CCA  .  8B8C24 D4010000 MOV ECX,DWORD PTR SS:[ESP+1D4]
00401CD1  .  5B          POP EBX
00401CD2  .  E8 1AAE0000    CALL Crackme1.0040CAF1
00401CD7  .  81C4 E0010000  ADD ESP,1E0
00401CDD  .  C3          RETN

小结:

程序采用MD5(Usename)=F_En(Code)的非明码验证方式。

求注册码的过程应该是:code=F_De( MD5( usename ) )

看来要找出F_En( )的解密函数F_De( )了。

----------------------------------------------------------------------------------------------

跟进00401C38 CALL Crackme1.004013B0这一行,看看注册码的构成:

004013B0  /$  56          PUSH ESI
004013B1  |.  8B7424 08     MOV ESI,DWORD PTR SS:[ESP+8]
004013B5  |.  8BC6        MOV EAX,ESI
004013B7  |.  8D50 01      LEA EDX,DWORD PTR DS:[EAX+1]
004013BA  |.  8D9B 00000000  LEA EBX,DWORD PTR DS:[EBX]
004013C0  |>  8A08        /MOV CL,BYTE PTR DS:[EAX]
004013C2  |.  40          |INC EAX
004013C3  |.  84C9        |TEST CL,CL
004013C5  |.^ 75 F9        \JNZ SHORT Crackme1.004013C0
004013C7  |.  2BC2        SUB EAX,EDX                    ;  相减得到假码的长度
004013C9  |.  83F8 20      CMP EAX,20                     ;  比较假码的长度是否是32
004013CC  |.  75 74        JNZ SHORT Crackme1.00401442
004013CE  |.  33C9        XOR ECX,ECX
004013D0  |>  8A0431       /MOV AL,BYTE PTR DS:[ECX+ESI]
004013D3  |.  3C 30        |CMP AL,30
004013D5  |.  7C 04        |JL SHORT Crackme1.004013DB
004013D7  |.  3C 39        |CMP AL,39
004013D9  |.  7E 08        |JLE SHORT Crackme1.004013E3         ;  是不是数字
004013DB  |>  3C 41        |CMP AL,41
004013DD  |.  7C 55        |JL SHORT Crackme1.00401434
004013DF  |.  3C 46        |CMP AL,46
004013E1  |.  7F 51        |JG SHORT Crackme1.00401434          ;  是不是大写字母A-F
004013E3  |>  8A4431 01     |MOV AL,BYTE PTR DS:[ECX+ESI+1]
004013E7  |.  3C 30        |CMP AL,30
004013E9  |.  7C 04        |JL SHORT Crackme1.004013EF
004013EB  |.  3C 39        |CMP AL,39
004013ED  |.  7E 08        |JLE SHORT Crackme1.004013F7         ;  是不是数字
004013EF  |>  3C 41        |CMP AL,41
004013F1  |.  7C 36        |JL SHORT Crackme1.00401429
004013F3  |.  3C 46        |CMP AL,46
004013F5  |.  7F 32        |JG SHORT Crackme1.00401429          ;  是不是大写字母A-F
004013F7  |>  8A4431 02     |MOV AL,BYTE PTR DS:[ECX+ESI+2]
004013FB  |.  3C 30        |CMP AL,30
004013FD  |.  7C 04        |JL SHORT Crackme1.00401403
004013FF  |.  3C 39        |CMP AL,39
00401401  |.  7E 08        |JLE SHORT Crackme1.0040140B         ;  是不是数字
00401403  |>  3C 41        |CMP AL,41
00401405  |.  7C 25        |JL SHORT Crackme1.0040142C
00401407  |.  3C 46        |CMP AL,46
00401409  |.  7F 21        |JG SHORT Crackme1.0040142C          ;  是不是大写字母A-F
0040140B  |>  8A4431 03     |MOV AL,BYTE PTR DS:[ECX+ESI+3]
0040140F  |.  3C 30        |CMP AL,30
00401411  |.  7C 04        |JL SHORT Crackme1.00401417
00401413  |.  3C 39        |CMP AL,39
00401415  |.  7E 08        |JLE SHORT Crackme1.0040141F         ;  是不是数字
00401417  |>  3C 41        |CMP AL,41
00401419  |.  7C 16        |JL SHORT Crackme1.00401431
0040141B  |.  3C 46        |CMP AL,46
0040141D  |.  7F 12        |JG SHORT Crackme1.00401431          ;  是不是大写字母A-F
0040141F  |>  83C1 04      |ADD ECX,4
00401422  |.  83F9 20      |CMP ECX,20                    ;  每次校验4个字符
00401425  |.^ 7C A9        \JL SHORT Crackme1.004013D0          ;  循环检查假码
00401427  |.  EB 0B        JMP SHORT Crackme1.00401434
00401429  |>  41          INC ECX
0040142A  |.  EB 08        JMP SHORT Crackme1.00401434
0040142C  |>  83C1 02      ADD ECX,2
0040142F  |.  EB 03        JMP SHORT Crackme1.00401434
00401431  |>  83C1 03      ADD ECX,3
00401434  |>  83F9 20      CMP ECX,20
00401437  |.  75 09        JNZ SHORT Crackme1.00401442
00401439  |.  B8 01000000    MOV EAX,1                      ;  通过检查,返回1
0040143E  |.  5E          POP ESI
0040143F  |.  C2 0400      RETN 4
00401442  |>  33C0        XOR EAX,EAX                    ;  不通过检查,返回0
00401444  |.  5E          POP ESI
00401445  \.  C2 0400      RETN 4

小结:

注册码是有数字和大写字母A-F组成,一共32个字符

----------------------------------------------------------------------------------------------

跟进00401C5E CALL Crackme1.00401160看看SBox[44]的初始化。

00401160  /$  83EC 24      SUB ESP,24
00401163  |.  8B4C24 2C     MOV ECX,DWORD PTR SS:[ESP+2C]
00401167  |.  8D41 03      LEA EAX,DWORD PTR DS:[ECX+3]
0040116A  |.  99          CDQ
0040116B  |.  83E2 03      AND EDX,3
0040116E  |.  53          PUSH EBX
0040116F  |.  03C2        ADD EAX,EDX
00401171  |.  55          PUSH EBP
00401172  |.  C1F8 02      SAR EAX,2
00401175  |.  33ED        XOR EBP,EBP
00401177  |.  49          DEC ECX
00401178  |.  3BCD        CMP ECX,EBP
0040117A  |.  56          PUSH ESI
0040117B  |.  57          PUSH EDI
0040117C  |.  894424 10     MOV DWORD PTR SS:[ESP+10],EAX
00401180  |.  896C84 10     MOV DWORD PTR SS:[ESP+EAX*4+10],EBP
00401184  |.  7C 25        JL SHORT Crackme1.004011AB
00401186  |.  8B7424 38     MOV ESI,DWORD PTR SS:[ESP+38]
0040118A  |.  8D9B 00000000  LEA EBX,DWORD PTR DS:[EBX]
00401190  |>  0FB63C31      /MOVZX EDI,BYTE PTR DS:[ECX+ESI]
00401194  |.  8BD1        |MOV EDX,ECX
00401196  |.  C1EA 02      |SHR EDX,2
00401199  |.  8B5C94 14     |MOV EBX,DWORD PTR SS:[ESP+EDX*4+14]
0040119D  |.  8D5494 14     |LEA EDX,DWORD PTR SS:[ESP+EDX*4+14]
004011A1  |.  C1E3 08      |SHL EBX,8
004011A4  |.  03FB        |ADD EDI,EBX
004011A6  |.  49          |DEC ECX
004011A7  |.  893A        |MOV DWORD PTR DS:[EDX],EDI
004011A9  |.^ 79 E5        \JNS SHORT Crackme1.00401190         ;  128位Key分成Key0、Key1、Key3、Key3
004011AB  |>  C705 40304300 6>MOV DWORD PTR DS:[433040],B7E15163     ;  SBox[0]
004011B5  |.  B9 44304300    MOV ECX,Crackme1.00433044
004011BA  |.  8D9B 00000000  LEA EBX,DWORD PTR DS:[EBX]
004011C0  |>  8B51 FC      /MOV EDX,DWORD PTR DS:[ECX-4]
004011C3  |.  81EA 4786C861  |SUB EDX,61C88647                ;  SBox=SBox[i-1]-0x61C88647
004011C9  |.  8911        |MOV DWORD PTR DS:[ECX],EDX          ;  保存SBox
004011CB  |.  83C1 04      |ADD ECX,4
004011CE  |.  81F9 EC304300  |CMP ECX,Crackme1.004330EC          ;  从SBox[0]填充到SBox[43]
004011D4  |.^ 7E EA        \JLE SHORT Crackme1.004011C0
004011D6  |.  BA 2C000000    MOV EDX,2C
004011DB  |.  33FF        XOR EDI,EDI
004011DD  |.  33C9        XOR ECX,ECX
004011DF  |.  33F6        XOR ESI,ESI
004011E1  |.  3BC2        CMP EAX,EDX
004011E3  |.  7E 02        JLE SHORT Crackme1.004011E7
004011E5  |.  8BD0        MOV EDX,EAX
004011E7  |>  8D0452       LEA EAX,DWORD PTR DS:[EDX+EDX*2]
004011EA  |.  83F8 01      CMP EAX,1
004011ED  |.  7C 69        JL SHORT Crackme1.00401258
004011EF  |.  894424 3C     MOV DWORD PTR SS:[ESP+3C],EAX
004011F3  |>  8B04BD 40304300 /MOV EAX,DWORD PTR DS:[EDI*4+433040]    ;  取SBox
004011FA  |.  03C1        |ADD EAX,ECX                    ;  + 上一轮循环的结果,第一次加0
004011FC  |.  03F0        |ADD ESI,EAX                    ;  + SBox[i-1],第一次加0
004011FE  |.  8BC6        |MOV EAX,ESI
00401200  |.  C1E8 1D      |SHR EAX,1D
00401203  |.  8D14F5 00000000 |LEA EDX,DWORD PTR DS:[ESI*8]
0040120A  |.  0BC2        |OR EAX,EDX                    ;  交换相加结果的前3位和后29位
0040120C  |.  8904BD 40304300 |MOV DWORD PTR DS:[EDI*4+433040],EAX    ;  存回SBox
00401213  |.  8BF0        |MOV ESI,EAX
00401215  |.  8B44AC 14     |MOV EAX,DWORD PTR SS:[ESP+EBP*4+14]    ;  取Key(i%4)
00401219  |.  03C1        |ADD EAX,ECX                    ;  加上上一轮循环的结果
0040121B  |.  8D1430       |LEA EDX,DWORD PTR DS:[EAX+ESI]       ;  Key[i%4]+SBox,这个结果准备下面的换位
0040121E  |.  8D1C31       |LEA EBX,DWORD PTR DS:[ECX+ESI]       ;  上轮结果+SBox
00401221  |.  8BC2        |MOV EAX,EDX
00401223  |.  83E3 1F      |AND EBX,1F                    ;  取相加结果的后五位
00401226  |.  B9 20000000    |MOV ECX,20                    ;  0x20-后五位=cl
0040122B  |.  2BCB        |SUB ECX,EBX
0040122D  |.  D3E8        |SHR EAX,CL
0040122F  |.  8BCB        |MOV ECX,EBX
00401231  |.  D3E2        |SHL EDX,CL
00401233  |.  0BC2        |OR EAX,EDX                    ;  交换相加结果的前(32-cl)位和后cl位
00401235  |.  8944AC 14     |MOV DWORD PTR SS:[ESP+EBP*4+14],EAX    ;  将结果保存回去
00401239  |.  8BC8        |MOV ECX,EAX
0040123B  |.  8D47 01      |LEA EAX,DWORD PTR DS:[EDI+1]
0040123E  |.  99          |CDQ
0040123F  |.  BF 2C000000    |MOV EDI,2C
00401244  |.  F7FF        |IDIV EDI
00401246  |.  8D45 01      |LEA EAX,DWORD PTR SS:[EBP+1]
00401249  |.  8BFA        |MOV EDI,EDX
0040124B  |.  99          |CDQ
0040124C  |.  F77C24 10     |IDIV DWORD PTR SS:[ESP+10]
00401250  |.  FF4C24 3C     |DEC DWORD PTR SS:[ESP+3C]
00401254  |.  8BEA        |MOV EBP,EDX
00401256  |.^ 75 9B        \JNZ SHORT Crackme1.004011F3
00401258  |>  5F          POP EDI
00401259  |.  5E          POP ESI
0040125A  |.  5D          POP EBP
0040125B  |.  5B          POP EBX
0040125C  |.  83C4 24      ADD ESP,24
0040125F  \.  C3          RETN

小结:

因为作者采用的是固定的Key,没有把Key跟电脑的硬件关联,所以SBox的初始化在任何电脑上都一样,所以这个过程就不铺开了。看注释吧。

初始化后内存中的SBox[44]

00433040 -->  63D4757A   EE7A3CB4   6D00027A   8831B70F
00433050 -->  7728D975   E7BA4156   DC92BFAD   CB17967B
00433060 -->  1F8B0D7A   8E0B0D4F   431C9651   22293C7F
00433070 -->  0D243845   C23C7BA6   4CAD232E   B35D36FF
00433080 -->  551BC015   0BF3CF67   DDAF2D46   A72AA80D
00433090 -->  EC1C33D4   896B736B   189D7F20   E46D20BE
004330A0 -->  C4DDD5CC   3DBBA1A7   8A692DB8   EEB598C4
004330B0 -->  0AA88B0C   F506A11A   ADC68F57   1739E928
004330C0 -->  577803DA   958F416A   DF1C7CA7   0BBAD3FE
004330D0 -->  AB6DB39C   B8048075   92628ABB   5CEB9507
004330E0 -->  64CCA67C   D00B10A6   D4181073   9E147749

----------------------------------------------------------------------------------------------

最后当然跟进00401C6B CALL Crackme1.00401260这一行了。这是整个Crackme最核心的部分。

00401260  /$  83EC 08      SUB ESP,8
00401263  |.  8B4424 0C     MOV EAX,DWORD PTR SS:[ESP+C]
00401267  |.  8B50 08      MOV EDX,DWORD PTR DS:[EAX+8]         ;  Sn2
0040126A  |.  8B08        MOV ECX,DWORD PTR DS:[EAX]          ;  Sn0
0040126C  |.  53          PUSH EBX
0040126D  |.  8B58 04      MOV EBX,DWORD PTR DS:[EAX+4]         ;  Sn1
00401270  |.  55          PUSH EBP
00401271  |.  8B68 0C      MOV EBP,DWORD PTR DS:[EAX+C]         ;  Sn3
00401274  |.  A1 44304300    MOV EAX,DWORD PTR DS:[433044]        ;  SBox[1]
00401279  |.  895424 14     MOV DWORD PTR SS:[ESP+14],EDX
0040127D  |.  8B15 40304300  MOV EDX,DWORD PTR DS:[433040]        ;  SBox[0]
00401283  |.  56          PUSH ESI
00401284  |.  03DA        ADD EBX,EDX                    ;  Sn1=Sn1+SBox[0]
00401286  |.  57          PUSH EDI
00401287  |.  03E8        ADD EBP,EAX                    ;  Sn2=Sn3+SBox[1]
00401289  |.  C74424 10 4C304>MOV DWORD PTR SS:[ESP+10],Crackme1.00433>
00401291  |.  EB 04        JMP SHORT Crackme1.00401297
00401293  |>  8B4C24 14     /MOV ECX,DWORD PTR SS:[ESP+14]
00401297  |>  8D441B 01      LEA EAX,DWORD PTR DS:[EBX+EBX+1]
0040129B  |.  0FAFC3       |IMUL EAX,EBX                   ;  D1=(Sn1*2+1)*Sn1
0040129E  |.  8BD0        |MOV EDX,EAX
004012A0  |.  C1E0 05      |SHL EAX,5
004012A3  |.  C1EA 1B      |SHR EDX,1B
004012A6  |.  0BD0        |OR EDX,EAX                    ;  交换D1的前5位和后27位
004012A8  |.  8D442D 01     |LEA EAX,DWORD PTR SS:[EBP+EBP+1]
004012AC  |.  0FAFC5       |IMUL EAX,EBP                   ;  D3=(Sn3*2+1)*Sn3
004012AF  |.  8BF0        |MOV ESI,EAX
004012B1  |.  C1E0 05      |SHL EAX,5
004012B4  |.  C1EE 1B      |SHR ESI,1B
004012B7  |.  0BF0        |OR ESI,EAX                    ;  交换D3的前5位和后27位
004012B9  |.  8BC6        |MOV EAX,ESI
004012BB  |.  83E0 1F      |AND EAX,1F                    ;  a=D3的后5位
004012BE  |.  8BFA        |MOV EDI,EDX
004012C0  |.  33F9        |XOR EDI,ECX                    ;  D1=D1^Sn0 (Sn0是上轮循环结果中未被处理的Sn0)
004012C2  |.  894424 14     |MOV DWORD PTR SS:[ESP+14],EAX
004012C6  |.  B9 20000000    |MOV ECX,20
004012CB  |.  2BC8        |SUB ECX,EAX
004012CD  |.  8BC7        |MOV EAX,EDI
004012CF  |.  D3E8        |SHR EAX,CL
004012D1  |.  8B4C24 14     |MOV ECX,DWORD PTR SS:[ESP+14]
004012D5  |.  D3E7        |SHL EDI,CL
004012D7  |.  895C24 14     |MOV DWORD PTR SS:[ESP+14],EBX        ;  保存:Sn0=Sn1
004012DB  |.  83E2 1F      |AND EDX,1F                    ;  b=D1的后5位
004012DE  |.  0BC7        |OR EAX,EDI                    ;  交换D3的前a位和后(32-a)位
004012E0  |.  8B7C24 10     |MOV EDI,DWORD PTR SS:[ESP+10]
004012E4  |.  0347 FC      |ADD EAX,DWORD PTR DS:[EDI-4]        ;  保存:Sn3=D1+SBox[2]
004012E7  |.  337424 1C     |XOR ESI,DWORD PTR SS:[ESP+1C]        ;  D3=D3^Sn2 (Sn2是上轮循环结果中未被处理的Sn2)
004012EB  |.  B9 20000000    |MOV ECX,20
004012F0  |.  2BCA        |SUB ECX,EDX
004012F2  |.  8BDE        |MOV EBX,ESI
004012F4  |.  D3EB        |SHR EBX,CL
004012F6  |.  8BCA        |MOV ECX,EDX
004012F8  |.  D3E6        |SHL ESI,CL
004012FA  |.  83C7 08      |ADD EDI,8
004012FD  |.  896C24 1C     |MOV DWORD PTR SS:[ESP+1C],EBP        ;  保存:Sn2=Sn3(未保存前的Sn3)
00401301  |.  8BE8        |MOV EBP,EAX
00401303  |.  0BDE        |OR EBX,ESI                    ;  交换D3的前b位和后(32-b)位
00401305  |.  8B77 F8      |MOV ESI,DWORD PTR DS:[EDI-8]
00401308  |.  03DE        |ADD EBX,ESI                    ;  保存:Sn1=D3+SBox[3]
0040130A  |.  81FF E4304300  |CMP EDI,Crackme1.004330E4
00401310  |.  897C24 10     |MOV DWORD PTR SS:[ESP+10],EDI        ;  循环20轮
00401314  |.^ 0F8E 79FFFFFF  \JLE Crackme1.00401293
0040131A  |.  8B0D EC304300  MOV ECX,DWORD PTR DS:[4330EC]        ;  取SBox[43]
00401320  |.  8B5424 1C     MOV EDX,DWORD PTR SS:[ESP+1C]        ;  取出Sn2
00401324  |.  8B7424 14     MOV ESI,DWORD PTR SS:[ESP+14]        ;  取出Sn0
00401328  |.  03D1        ADD EDX,ECX                    ;  Sn2+SBox[43]
0040132A  |.  8B0D E8304300  MOV ECX,DWORD PTR DS:[4330E8]        ;  取出SBox[42]
00401330  |.  03F1        ADD ESI,ECX                    ;  Sn0+SBox[42]
00401332  |.  8B4C24 20     MOV ECX,DWORD PTR SS:[ESP+20]
00401336  |.  5F          POP EDI
00401337  |.  8931        MOV DWORD PTR DS:[ECX],ESI          ;  保存Sn0
00401339  |.  5E          POP ESI
0040133A  |.  5D          POP EBP
0040133B  |.  8959 04      MOV DWORD PTR DS:[ECX+4],EBX         ;  保存Sn1
0040133E  |.  8951 08      MOV DWORD PTR DS:[ECX+8],EDX         ;  保存Sn2
00401341  |.  8941 0C      MOV DWORD PTR DS:[ECX+C],EAX         ;  保存Sn3
00401344  |.  5B          POP EBX
00401345  |.  83C4 08      ADD ESP,8
00401348  \.  C3          RETN

小结:

算法中用到一个函数f( )

f(a)就是 (a*2+1)*a,然后将32位结果的前5位和后27位换位。

上面的注释说得不够清楚,用图表示吧:

加密过程:

将待加密的128数据分成四组:Sn0、Sn1、Sn2、Sn3

_____Sn0__________Sn1__________Sn2__________Sn3_____
             |                 |
           +SBox[0]            +SBox[1]
             |                 |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 简单处理后进入循环(循环开始)
    |      /  |        |      /  |
    |      / f( )        |      / f( )
    |     /   |        |     /   |
    |______/____Xor        |______/____Xor
        /    |            /    |
        /    换位a          /    换位b
       /      |           /      |
      /    +SBox[2]        /    +SBox[3]
      /       |______________/___     |
     /                 /  |     |
    |        _____________|____|_______|
    |        |        |   |________
    |        |        |        |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 第一轮循环的结果
    |      /  |        |      /  |
    |      / f( )        |      / f( )
    |     /   |        |     /   |
    |______/____Xor        |______/____Xor
        /    |            /    |
        /    换位a          /    换位b
       /      |           /      |
      /    +SBox[4]        /    +SBox[5]
      /       |______________/___     |
     /                 /  |     |
    |        _____________|____|_______|
    |        |        |   |________
    |        |        |        |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 第二轮循环的结果

……………………………………………………………………

_____Sn0__________Sn1__________Sn2__________Sn3_____ 第十九轮循环的结果
    |      /  |        |      /  |
    |      / f( )        |      / f( )
    |     /   |        |     /   |
    |______/____Xor        |______/____Xor
        /    |            /    |
        /    换位a          /    换位b
       /      |           /      |
      /    +SBox[40]       /    +SBox[41]
      /       |______________/___     |
     /                 /  |     |
    |        _____________|____|_______|
    |        |        |   |________
    |        |        |        |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 第二十轮循环的结果(循环结束)
    |                 |
  +SBox[42]            +SBox[43]
    |                 |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 最终结果

说明:

F_En( )的处理过程分20轮循环完成。

每一轮循环中都有换位,对上表中的换位做一个说明:

换位a:就是将32位结果的前a位和后(32-a)位换位,a取每一轮中f(Sn3)的后五位

换位b:就是将32位结果的前b位和后(32-b)位换位,b取每一轮中f(Sn1)的后五位

----------------------------------------------------------------------------------------------

最后分析一下 F_En( ) 的逆过程:

解密过程:

_____Sn0__________Sn1__________Sn2__________Sn3_____
    |                 |
  -SBox[42]            -SBox[43]
    |                 |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 简单处理后进入循环(循环开始)
    | \       |____________|_\________  |
    |  \      _____________|__\______|__|
    |  \      |        |  \    |___
    |   \     |        |   \     |
   f( )   \  -SBox[40]    f( )   \  -SBox[41]
    |    |    |        |    |    |
    |    |    换位c      |    |    换位d
    |    |    |        |    |    |
    XOR____|______|        XOR____|______|
    |    |_______        |    |_______
    |        |        |        |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 第一轮循环的结果
    | \       |____________|_\________  |
    |  \      _____________|__\______|__|
    |  \      |        |  \    |___
    |   \     |        |   \     |
   f( )   \  -SBox[38]    f( )   \  -SBox[39]
    |    |    |        |    |    |
    |    |    换位c      |    |    换位d
    |    |    |        |    |    |
    XOR____|______|        XOR____|______|
    |    |_______        |    |_______
    |        |        |        |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 第二轮循环的结果

……………………………………………………………………

_____Sn0__________Sn1__________Sn2__________Sn3_____ 第十九轮循环的结果
    | \       |____________|_\________  |
    |  \      _____________|__\______|__|
    |  \      |        |  \    |___
    |   \     |        |   \     |
   f( )   \  -SBox[2]    f( )   \  -SBox[3]
    |    |    |        |    |    |
    |    |    换位c      |    |    换位d
    |    |    |        |    |    |
    XOR____|______|        XOR____|______|
    |    |_______        |    |_______
    |        |        |        |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 第二十轮循环的结果
             |                 |
           -SBox[0]            -SBox[1]
             |                 |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 最终结果

F_De( )也分20轮循环完成:

每一轮循环中都有换位,对上表中的换位做一个说明:

换位c:就是将32位结果的前c位和后(32-c)位换位,a取每一轮中f(Sn2)的后五位

换位d:就是将32位结果的前d位和后(32-d)位换位,b取每一轮中f(Sn0)的后五位

----------------------------------------------------------------------------------------------
【注册机源码】

Microsoft Visual C++ 6.0 编写的MFC,变量的命名跟上面注释相同,不过代码写得太烂了,大家不要笑我。

/////////////////////////////////////////////////////////////////
//
//  FileName  :  CrackMe1_qxtianlongDlg.cpp
//  Author  :  rdsnow[BCG][PYG][D.4s]
//  Date  :  2005-10-25
//  Comment  :  keygen for crackme1 by qxtianlong(关键代码)
//
/////////////////////////////////////////////////////////////////

void CCrackMe1_qxtianlongDlg::OnOK()
{
  // TODO: Add extra validation here
  
  //CDialog::OnOK();

  DWORD Sn0,Sn1,Sn2,Sn3;
  unsigned char inbuff[512],outbuff[16];
  int i;
  
  UpdateData(true);
  
  //对UseName进行MD5编码,这里使用不同的MD5类,代码也不相同
  i=m_Edit1.GetLength ();
  memcpy(inbuff,m_Edit1,i+1);
  MD5_CTX context;
  context.MD5Update (inbuff,i);
  context.MD5Final (outbuff);

  //将MD5的结果分成四个DWORD
  Sn0=outbuff[0]+(outbuff[1]<<8)+(outbuff[2]<<16)+(outbuff[3]<<24);
  Sn1=outbuff[4]+(outbuff[5]<<8)+(outbuff[6]<<16)+(outbuff[7]<<24);
  Sn2=outbuff[8]+(outbuff[9]<<8)+(outbuff[10]<<16)+(outbuff[11]<<24);
  Sn3=outbuff[12]+(outbuff[13]<<8)+(outbuff[14]<<16)+(outbuff[15]<<24);

  //用四个分组解密
  m_Edit2=F_De(Sn0,Sn1,Sn2,Sn3);
  
  //输出结果
  UpdateData(false);  
  
}


DWORD CCrackMe1_qxtianlongDlg::Exchange(DWORD Sn, int i)
{  
  //将32位的Sn的前i位和后(32-i)位交换

  DWORD TempData=Sn;
  Sn=Sn << i;
  i=32-i;
  TempData=TempData>>i;
  Sn |=TempData;

  return Sn;
}

DWORD CCrackMe1_qxtianlongDlg::Function1(DWORD Sn)
{
  //算法中用到的一个函数,即f( )

  //Sn=(Sn×2+1)×Sn,然后交换结果的前5位和后27位

  Sn=(Sn*2+1)*Sn;
  Sn=Exchange(Sn,5);

  return Sn;
}

CString CCrackMe1_qxtianlongDlg::F_De(DWORD Sn0, DWORD Sn1, DWORD Sn2, DWORD Sn3)
{

  //解密函数

  CString Code="",TempChar;

  //因为作者使用的是固定的key,所以偶偷懒
  //直接将SBox[44]复制过来了,省掉SBox初始化编程

  DWORD SBox[44]={
   0x63D4757A , 0xEE7A3CB4 , 0x6D00027A , 0x8831B70F,
   0x7728D975 , 0xE7BA4156 , 0xDC92BFAD , 0xCB17967B,
   0x1F8B0D7A , 0x8E0B0D4F , 0x431C9651 , 0x22293C7F,
   0x0D243845 , 0xC23C7BA6 , 0x4CAD232E , 0xB35D36FF,
   0x551BC015 , 0x0BF3CF67 , 0xDDAF2D46 , 0xA72AA80D,
   0xEC1C33D4 , 0x896B736B , 0x189D7F20 , 0xE46D20BE,
   0xC4DDD5CC , 0x3DBBA1A7 , 0x8A692DB8 , 0xEEB598C4,
   0x0AA88B0C , 0xF506A11A , 0xADC68F57 , 0x1739E928,
   0x577803DA , 0x958F416A , 0xDF1C7CA7 , 0x0BBAD3FE,
   0xAB6DB39C , 0xB8048075 , 0x92628ABB , 0x5CEB9507,
   0x64CCA67C , 0xD00B10A6 , 0xD4181073 , 0x9E147749
  };
  
  DWORD TempData1,TempData2;
  int i;

  Sn0-=SBox[42];
  Sn2-=SBox[43];

  for (i=0;i<20;i++){

   TempData1=Sn0;
   TempData2=Sn2;

   Sn0=Function1(Sn0);
   Sn2=Function1(Sn2);

   Sn1-=SBox[41-2*i];
   Sn3-=SBox[40-2*i];

   Sn3=Exchange(Sn3,32-(Sn2 & 0x1F));
   Sn1=Exchange(Sn1,32-(Sn0 & 0x1F));

   Sn0 ^= Sn3;
   Sn2 ^= Sn1;

   Sn1=TempData1;
   Sn3=TempData2;

  }
  
  Sn1-=SBox[0];
  Sn3-=SBox[1];

  TempChar.Format ("%02X%02X%02X%02X",Sn0&0xFF,Sn0>>8&0xFF,Sn0>>16&0xFF,Sn0>>24&0xFF);
  Code+=TempChar;
  TempChar.Format ("%02X%02X%02X%02X",Sn1&0xFF,Sn1>>8&0xFF,Sn1>>16&0xFF,Sn1>>24&0xFF);
  Code+=TempChar;
  TempChar.Format ("%02X%02X%02X%02X",Sn2&0xFF,Sn2>>8&0xFF,Sn2>>16&0xFF,Sn2>>24&0xFF);
  Code+=TempChar;
  TempChar.Format ("%02X%02X%02X%02X",Sn3&0xFF,Sn3>>8&0xFF,Sn3>>16&0xFF,Sn3>>24&0xFF);
  Code+=TempChar;
  
  return Code;  

}

----------------------------------------------------------------------------------------------
【破解心得】

这是个对称算法,加密和解密使用同一密钥,建议作者密钥跟机器码关联,不要使用固定的密钥。

现在的软件更加倾向于使用强壳阻止程序不被调试,所以要向工作在脱壳第一线的大侠致敬,现在感觉到脱壳真是一件辛苦的事情。

附件:

Crackme1.exe --> crackme1 by qxtianlong

keygen.exe --> 算法注册机

Crackme1 by qxtianlong.txt --> 破文,如果由于流程图显示错位,看txt文档吧!

----------------------------------------------------------------------------------------------
【破解声明】  我是一只小菜鸟,偶得一点心得,愿与大家分享:)

【版权声明】  本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢!
----------------------------------------------------------------------------------------------

TOP

发新话题