- UID
- 1481
注册时间2005-5-8
阅读权限20
最后登录1970-1-1
以武会友
TA的每日心情 | 衰 2024-4-11 22:10 |
---|
签到天数: 53 天 [LV.5]常住居民I
|
【破文作者】 rdsnow[BCG][PYG][D.4s]
【作者主页】 http://rdsnow.ys168.com
【 E-mail 】 [email protected]
【 作者QQ 】 83757177
【文章题目】 Crackme1 by qxtianlong 的算法分析
【软件名称】 Crackme1 by qxtianlong
【下载地址】 https://www.chinapyg.com/attachm ... a1e2&download=1
【破解平台】 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[ i]=SBox[i-1]-0x61C88647
004011C9 |. 8911 |MOV DWORD PTR DS:[ECX],EDX ; 保存SBox[ i]
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[ i]
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[ i]
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[ i],这个结果准备下面的换位
0040121E |. 8D1C31 |LEA EBX,DWORD PTR DS:[ECX+ESI] ; 上轮结果+SBox[ i]
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文档吧!
----------------------------------------------------------------------------------------------
【破解声明】 我是一只小菜鸟,偶得一点心得,愿与大家分享:)
【版权声明】 本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢!
----------------------------------------------------------------------------------------------
文章写于2005-10-25 22:56:34
[ Last edited by rdsnow on 2005-10-26 at 08:20 AM ] |
|