Crackme1 by qxtianlong 的算法分析
【破文作者】 rdsnow【作者主页】 http://rdsnow.ys168.com
【 E-mail 】 [email protected]
【 作者QQ 】 83757177
【文章题目】 Crackme1 by qxtianlong 的算法分析
【软件名称】 Crackme1 by qxtianlong
【下载地址】 https://www.chinapyg.com/attachment.php?aid=378&checkid=9a1e2&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个DWORD元素。
----------------------------------------------------------------------------------------------
【破解过程】
OD插件和W32DASM都没有找到字符串,看来字符加密了。
但是有错误对话框弹出,命令行下断:bp MessageBoxA返回程序领空后向上来到这里:
00401B40 .6A FF PUSH -1
00401B42 .68 3B5A4200 PUSH Crackme1.00425A3B ;SE 句柄安装
00401B47 .64:A1 00000000MOV EAX,DWORD PTR FS:
00401B4D .50 PUSH EAX
00401B4E .64:8925 0000000>MOV DWORD PTR FS:,ESP
00401B55 .81EC D4010000 SUB ESP,1D4
00401B5B .A1 EC204300 MOV EAX,DWORD PTR DS:
00401B60 .898424 D0010000 MOV DWORD PTR SS:,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:,AL ;byte3=0x5C
00401B72 .884424 11 MOV BYTE PTR SS:,AL ;byte13=0x5C
00401B76 .68 04010000 PUSH 104
00401B7B .8D8424 D4000000 LEA EAX,DWORD PTR SS:
00401B82 .884C24 09 MOV BYTE PTR SS:,CL ;byte1=0x47
00401B86 .884C24 17 MOV BYTE PTR SS:,CL ;byte15=0x47
00401B8A .50 PUSH EAX
00401B8B .8D8B C4000000 LEA ECX,DWORD PTR DS:
00401B91 .C64424 0C 35 MOV BYTE PTR SS:,35 ;byte0=0x35
00401B96 .C64424 0E 82 MOV BYTE PTR SS:,82 ;byte2=0x82
00401B9B .C64424 10 33 MOV BYTE PTR SS:,33 ;byte4=0x33
00401BA0 .C64424 11 8C MOV BYTE PTR SS:,8C ;byte5=0x8C
00401BA5 .C64424 12 85 MOV BYTE PTR SS:,85 ;byte6=0x85
00401BAA .C64424 13 77 MOV BYTE PTR SS:,77 ;byte7=0x77
00401BAF .C64424 14 9A MOV BYTE PTR SS:,9A ;byte8=0x9A
00401BB4 .C64424 15 67 MOV BYTE PTR SS:,67 ;byte9=0x67
00401BB9 .C64424 16 45 MOV BYTE PTR SS:,45 ;byte10=0x45
00401BBE .C64424 17 7A MOV BYTE PTR SS:,7A ;byte11=0x7A
00401BC3 .C64424 18 6D MOV BYTE PTR SS:,6D ;byte12=0x6D
00401BC8 .C64424 1A 16 MOV BYTE PTR SS:,16 ;byte14=0x16
00401BCD .E8 D9C30100 CALL Crackme1.0041DFAB ;读取用户名"rdsnow"
00401BD2 .8D4C24 34 LEA ECX,DWORD PTR SS:
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:
--> 00402919|.8BFE MOV EDI,ESI
--> 0040291B|.8942 18 MOV DWORD PTR DS:,EAX
--> 0040291E|.8942 14 MOV DWORD PTR DS:,EAX
--> 00402921|.B9 10000000 MOV ECX,10
--> 00402926|.C702 1C7A4200 MOV DWORD PTR DS:,Crackme1.00427A1C
--> 0040292C|.C742 04 0123456>MOV DWORD PTR DS:,67452301 ;这里看到MD5的四个基本常数了
--> 00402933|.C742 08 89ABCDE>MOV DWORD PTR DS:,EFCDAB89
--> 0040293A|.C742 0C FEDCBA9>MOV DWORD PTR DS:,98BADCFE
--> 00402941|.C742 10 7654321>MOV DWORD PTR DS:,10325476
--> 00402948|.F3:AB REP STOS DWORD PTR ES:
--> 0040294A|.5F POP EDI
--> 0040294B|.C606 80 MOV BYTE PTR DS:,80
--> 0040294E|.8BC2 MOV EAX,EDX
--> 00402950|.5E POP ESI
--> 00402951\.C3 RETN
00401BDB .8D8424 D0000000 LEA EAX,DWORD PTR SS:
00401BE2 .C78424 E0010000>MOV DWORD PTR SS:,0
00401BED .8D50 01 LEA EDX,DWORD PTR DS:
00401BF0 >8A08 MOV CL,BYTE PTR DS:
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:
00401C01 .51 PUSH ECX
00401C02 .8D4C24 3C LEA ECX,DWORD PTR SS:
00401C06 .E8 550D0000 CALL Crackme1.00402960 ;转存用户名
00401C0B .8D5424 24 LEA EDX,DWORD PTR SS:
00401C0F .52 PUSH EDX ; /MD5结果保存地址
00401C10 .8D4C24 38 LEA ECX,DWORD PTR SS: ; |
00401C14 .E8 170E0000 CALL Crackme1.00402A30 ; \MD5(用户名)
00401C19 .68 04010000 PUSH 104
00401C1E .8D8424 D4000000 LEA EAX,DWORD PTR SS:
00401C25 .50 PUSH EAX
00401C26 .8D4B 74 LEA ECX,DWORD PTR DS:
00401C29 .E8 7DC30100 CALL Crackme1.0041DFAB ;读取假码
00401C2E .8D8C24 D0000000 LEA ECX,DWORD PTR SS:
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:
00401C47 .52 PUSH EDX
00401C48 .8D8424 DC000000 LEA EAX,DWORD PTR SS:
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:
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:
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:
00401C7C .8D7424 2C LEA ESI,DWORD PTR SS:
00401C80 .33D2 XOR EDX,EDX
00401C82 .F3:A7 REPE CMPS DWORD PTR ES:,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:
00401CAC .C78424 E0010000>MOV DWORD PTR SS:,-1
00401CB7 .E8 34030000 CALL Crackme1.00401FF0
00401CBC .8B8C24 D8010000 MOV ECX,DWORD PTR SS:
00401CC3 .64:890D 0000000>MOV DWORD PTR FS:,ECX
00401CCA .8B8C24 D4010000 MOV ECX,DWORD PTR SS:
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:
004013B5|.8BC6 MOV EAX,ESI
004013B7|.8D50 01 LEA EDX,DWORD PTR DS:
004013BA|.8D9B 00000000 LEA EBX,DWORD PTR DS:
004013C0|>8A08 /MOV CL,BYTE PTR DS:
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:
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:
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:
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:
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的初始化。
00401160/$83EC 24 SUB ESP,24
00401163|.8B4C24 2C MOV ECX,DWORD PTR SS:
00401167|.8D41 03 LEA EAX,DWORD PTR DS:
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:,EAX
00401180|.896C84 10 MOV DWORD PTR SS:,EBP
00401184|.7C 25 JL SHORT Crackme1.004011AB
00401186|.8B7424 38 MOV ESI,DWORD PTR SS:
0040118A|.8D9B 00000000 LEA EBX,DWORD PTR DS:
00401190|>0FB63C31 /MOVZX EDI,BYTE PTR DS:
00401194|.8BD1 |MOV EDX,ECX
00401196|.C1EA 02 |SHR EDX,2
00401199|.8B5C94 14 |MOV EBX,DWORD PTR SS:
0040119D|.8D5494 14 |LEA EDX,DWORD PTR SS:
004011A1|.C1E3 08 |SHL EBX,8
004011A4|.03FB |ADD EDI,EBX
004011A6|.49 |DEC ECX
004011A7|.893A |MOV DWORD PTR DS:,EDI
004011A9|.^ 79 E5 \JNS SHORT Crackme1.00401190 ;128位Key分成Key0、Key1、Key3、Key3
004011AB|>C705 40304300 6>MOV DWORD PTR DS:,B7E15163 ;SBox
004011B5|.B9 44304300 MOV ECX,Crackme1.00433044
004011BA|.8D9B 00000000 LEA EBX,DWORD PTR DS:
004011C0|>8B51 FC /MOV EDX,DWORD PTR DS:
004011C3|.81EA 4786C861 |SUB EDX,61C88647 ;SBox[ i]=SBox-0x61C88647
004011C9|.8911 |MOV DWORD PTR DS:,EDX ;保存SBox[ i]
004011CB|.83C1 04 |ADD ECX,4
004011CE|.81F9 EC304300 |CMP ECX,Crackme1.004330EC ;从SBox填充到SBox
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:
004011EA|.83F8 01 CMP EAX,1
004011ED|.7C 69 JL SHORT Crackme1.00401258
004011EF|.894424 3C MOV DWORD PTR SS:,EAX
004011F3|>8B04BD 40304300 /MOV EAX,DWORD PTR DS: ;取SBox[ i]
004011FA|.03C1 |ADD EAX,ECX ;+ 上一轮循环的结果,第一次加0
004011FC|.03F0 |ADD ESI,EAX ;+ SBox,第一次加0
004011FE|.8BC6 |MOV EAX,ESI
00401200|.C1E8 1D |SHR EAX,1D
00401203|.8D14F5 00000000 |LEA EDX,DWORD PTR DS:
0040120A|.0BC2 |OR EAX,EDX ;交换相加结果的前3位和后29位
0040120C|.8904BD 40304300 |MOV DWORD PTR DS:,EAX ;存回SBox[ i]
00401213|.8BF0 |MOV ESI,EAX
00401215|.8B44AC 14 |MOV EAX,DWORD PTR SS: ;取Key(i%4)
00401219|.03C1 |ADD EAX,ECX ;加上上一轮循环的结果
0040121B|.8D1430 |LEA EDX,DWORD PTR DS: ;Key+SBox[ i],这个结果准备下面的换位
0040121E|.8D1C31 |LEA EBX,DWORD PTR DS: ;上轮结果+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:,EAX ;将结果保存回去
00401239|.8BC8 |MOV ECX,EAX
0040123B|.8D47 01 |LEA EAX,DWORD PTR DS:
0040123E|.99 |CDQ
0040123F|.BF 2C000000 |MOV EDI,2C
00401244|.F7FF |IDIV EDI
00401246|.8D45 01 |LEA EAX,DWORD PTR SS:
00401249|.8BFA |MOV EDI,EDX
0040124B|.99 |CDQ
0040124C|.F77C24 10 |IDIV DWORD PTR SS:
00401250|.FF4C24 3C |DEC DWORD PTR SS:
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
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:
00401267|.8B50 08 MOV EDX,DWORD PTR DS: ;Sn2
0040126A|.8B08 MOV ECX,DWORD PTR DS: ;Sn0
0040126C|.53 PUSH EBX
0040126D|.8B58 04 MOV EBX,DWORD PTR DS: ;Sn1
00401270|.55 PUSH EBP
00401271|.8B68 0C MOV EBP,DWORD PTR DS: ;Sn3
00401274|.A1 44304300 MOV EAX,DWORD PTR DS: ;SBox
00401279|.895424 14 MOV DWORD PTR SS:,EDX
0040127D|.8B15 40304300 MOV EDX,DWORD PTR DS: ;SBox
00401283|.56 PUSH ESI
00401284|.03DA ADD EBX,EDX ;Sn1=Sn1+SBox
00401286|.57 PUSH EDI
00401287|.03E8 ADD EBP,EAX ;Sn2=Sn3+SBox
00401289|.C74424 10 4C304>MOV DWORD PTR SS:,Crackme1.00433>
00401291|.EB 04 JMP SHORT Crackme1.00401297
00401293|>8B4C24 14 /MOV ECX,DWORD PTR SS:
00401297|>8D441B 01 LEA EAX,DWORD PTR DS:
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:
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:,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:
004012D5|.D3E7 |SHL EDI,CL
004012D7|.895C24 14 |MOV DWORD PTR SS:,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:
004012E4|.0347 FC |ADD EAX,DWORD PTR DS: ;保存:Sn3=D1+SBox
004012E7|.337424 1C |XOR ESI,DWORD PTR SS: ;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:,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:
00401308|.03DE |ADD EBX,ESI ;保存:Sn1=D3+SBox
0040130A|.81FF E4304300 |CMP EDI,Crackme1.004330E4
00401310|.897C24 10 |MOV DWORD PTR SS:,EDI ;循环20轮
00401314|.^ 0F8E 79FFFFFF \JLE Crackme1.00401293
0040131A|.8B0D EC304300 MOV ECX,DWORD PTR DS: ;取SBox
00401320|.8B5424 1C MOV EDX,DWORD PTR SS: ;取出Sn2
00401324|.8B7424 14 MOV ESI,DWORD PTR SS: ;取出Sn0
00401328|.03D1 ADD EDX,ECX ;Sn2+SBox
0040132A|.8B0D E8304300 MOV ECX,DWORD PTR DS: ;取出SBox
00401330|.03F1 ADD ESI,ECX ;Sn0+SBox
00401332|.8B4C24 20 MOV ECX,DWORD PTR SS:
00401336|.5F POP EDI
00401337|.8931 MOV DWORD PTR DS:,ESI ;保存Sn0
00401339|.5E POP ESI
0040133A|.5D POP EBP
0040133B|.8959 04 MOV DWORD PTR DS:,EBX ;保存Sn1
0040133E|.8951 08 MOV DWORD PTR DS:,EDX ;保存Sn2
00401341|.8941 0C MOV DWORD PTR DS:,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 +SBox
| |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 简单处理后进入循环(循环开始)
| /| | /|
| / f( ) | / f( )
| / | | / |
|______/____Xor |______/____Xor
/ | / |
/ 换位a / 换位b
/ | / |
/ +SBox / +SBox
/ |______________/___ |
/ / | |
| _____________|____|_______|
| | | |________
| | | |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 第一轮循环的结果
| /| | /|
| / f( ) | / f( )
| / | | / |
|______/____Xor |______/____Xor
/ | / |
/ 换位a / 换位b
/ | / |
/ +SBox / +SBox
/ |______________/___ |
/ / | |
| _____________|____|_______|
| | | |________
| | | |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 第二轮循环的结果
……………………………………………………………………
_____Sn0__________Sn1__________Sn2__________Sn3_____ 第十九轮循环的结果
| /| | /|
| / f( ) | / f( )
| / | | / |
|______/____Xor |______/____Xor
/ | / |
/ 换位a / 换位b
/ | / |
/ +SBox / +SBox
/ |______________/___ |
/ / | |
| _____________|____|_______|
| | | |________
| | | |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 第二十轮循环的结果(循环结束)
| |
+SBox +SBox
| |
_____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 -SBox
| |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 简单处理后进入循环(循环开始)
| \ |____________|_\________|
|\ _____________|__\______|__|
| \ | | \ |___
| \ | | \ |
f( ) \ -SBox f( ) \ -SBox
| | | | | |
| | 换位c | | 换位d
| | | | | |
XOR____|______| XOR____|______|
| |_______ | |_______
| | | |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 第一轮循环的结果
| \ |____________|_\________|
|\ _____________|__\______|__|
| \ | | \ |___
| \ | | \ |
f( ) \ -SBox f( ) \ -SBox
| | | | | |
| | 换位c | | 换位d
| | | | | |
XOR____|______| XOR____|______|
| |_______ | |_______
| | | |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 第二轮循环的结果
……………………………………………………………………
_____Sn0__________Sn1__________Sn2__________Sn3_____ 第十九轮循环的结果
| \ |____________|_\________|
|\ _____________|__\______|__|
| \ | | \ |___
| \ | | \ |
f( ) \ -SBox f( ) \ -SBox
| | | | | |
| | 换位c | | 换位d
| | | | | |
XOR____|______| XOR____|______|
| |_______ | |_______
| | | |
_____Sn0__________Sn1__________Sn2__________Sn3_____ 第二十轮循环的结果
| |
-SBox -SBox
| |
_____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
//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,outbuff;
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+(outbuff<<8)+(outbuff<<16)+(outbuff<<24);
Sn1=outbuff+(outbuff<<8)+(outbuff<<16)+(outbuff<<24);
Sn2=outbuff+(outbuff<<8)+(outbuff<<16)+(outbuff<<24);
Sn3=outbuff+(outbuff<<8)+(outbuff<<16)+(outbuff<<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复制过来了,省掉SBox初始化编程
DWORD SBox={
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;
Sn2-=SBox;
for (i=0;i<20;i++){
TempData1=Sn0;
TempData2=Sn2;
Sn0=Function1(Sn0);
Sn2=Function1(Sn2);
Sn1-=SBox;
Sn3-=SBox;
Sn3=Exchange(Sn3,32-(Sn2 & 0x1F));
Sn1=Exchange(Sn1,32-(Sn0 & 0x1F));
Sn0 ^= Sn3;
Sn2 ^= Sn1;
Sn1=TempData1;
Sn3=TempData2;
}
Sn1-=SBox;
Sn3-=SBox;
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 ] qxtianlong 兄到这里做版主了,gxgx!!! 强,分析的这么透彻,一个Crackme1.0没有要关联机器码,当然在软件中肯定不会这么简单的,要加强壳的!!rdsnow!佩服佩服
我这个斑竹是临时的!!不过谢谢了!!
在职一天就做好自己的事!呵呵~ 分析的真详细,学习。 牛人啊~~~
看的心里痒痒的~~~
什么时候偶也能到达这个小平啊~~~ 详细……无语…… 同意5楼的看法.....
页:
[1]