loveasm的crackme算法分析-----CRC32算法的妙用
【作者】:onlyu[FCG][DFCG]
【软件介绍】:loveasm[YCG][DFCG]兄弟的crackme,主要锻炼算法分析,要求破解成功后出现显示"恭喜您!您已经成功的注册了本软件!"的对话框。
【软件下载】:点击此处本地下载
【软件限制】:注册码
【作者声明】:初学Crack,只是感兴趣,没有其它目的。失误之处敬请诸位大侠赐教!
【破解工具】:Ollydbg1.09
【破解过程】:
运行程序,输入
用户名:onlyu[FCG][DFCG]
注册码:78787878787878787878787878787878
在OD命令行插件里下断点:bpx getdlgitemtexta
点注册,停在如下:
004014A9 . 68 A4374000 PUSH CRACKME.004037A4
004014AE . 68 91010000 PUSH 191
004014B3 . FF75 08 PUSH DWORD PTR SS:[EBP+8]
004014B6 . E8 27020000 CALL <JMP.&user32.GetDlgItemTextA><-----获得输入的注册名
004014BB . 8BC8 MOV ECX,EAX
004014BD . 83F8 00 CMP EAX,0<-------------------------输入的注册名是否为空
004014C0 . 77 0E JA SHORT CRACKME.004014D0<---------不空往下跳
004014C2 . B8 00000000 MOV EAX,0
004014C7 . 59 POP ECX
004014C8 . 5A POP EDX
跳转到这里:
004014D0 > 33C0 XOR EAX,EAX
004014D2 . 8D35 A4374000 LEA ESI,DWORD PTR DS:[4037A4]<----使ESI指向注册名"onlyu[FCG][DFCG]"
004014D8 > 33DB XOR EBX,EBX--------------------
004014DA . 8A1E MOV BL,BYTE PTR DS:[ESI] |
004014DC . 03C3 ADD EAX,EBX |小循环
004014DE . 46 INC ESI |
004014DF .^ E2 F7 LOOPD SHORT CRACKME.004014D8---
上面这段小循环的功能是把输入的用户名的字符的ASCII码累加起来保存到EAX中,我的为58B
004014E1 . 8845 FF &nbs
p;MOV BYTE PTR SS:[EBP-1],AL<----把上面得到的值取后两位存到ss:[ebp-1]处
004014E4 . 68 FF000000 PUSH 0FF
004014E9 . 68 24364000 PUSH CRACKME.00403624
004014EE . 68 92010000 PUSH 192
004014F3 . FF75 08 PUSH DWORD PTR SS:[EBP+8]
004014F6 . E8 E7010000 CALL <JMP.&user32.GetDlgItemTextA><-----获得输入的注册码
004014FB . BE 24364000 MOV ESI,CRACKME.00403624<--------ESI->输入的注册码"78787878..."
00401500 . 8D3D 70394000 LEA EDI,DWORD PTR DS:[403970]
00401506 . B9 10000000 MOV ECX,10<---------------------置循环次数
0040150B > 33DB XOR EBX,EBX<--------------------把EBX清0
0040150D . 33C0 XOR EAX,EAX<--------------------把EAX清0
0040150F . AC LODS BYTE PTR DS:[ESI]<---------取注册码的字符到EAX中
00401510 . 83F8 39 CMP EAX,39<---------------------输入字符ASCII码是否大于39
00401513 . 7E 03 JLE SHORT CRACKME.00401518<-----小于或等于就跳
00401515 . 83E8 07 SUB EAX,7<----------------------EAX=EAX-7
00401518 > 83E8 30 SUB EAX,30<---------------------EAX=EAX-30
0040151B . 0BD8 OR EBX,EAX<---------------------EBX=EBX or EAX
0040151D . C1E3 04 SHL EBX,4<----------------------EBX=EBX shl 4
00401520 . 33C0 XOR EAX,EAX<--------------------EAX清0
00401522 . AC LODS BYTE PTR DS:[ESI]<---------取注册码的下一个字符到EAX中
00401523 . 83F8 39 CMP EAX,39<---------------------输入字符ASCII码是否大于39
00401526 . 7E 03 JLE SHORT CRACKME.0040152B<-----小于或等于就跳
00401528 . 83E8 07 SUB EAX,7<----------------------EAX=EAX-7
0040152B > 83E8 30 SUB EAX,30<---------------------EAX=EAX-30
0040152E . 0BD8 OR EBX,EAX<---------------------EBX=EBX or EAX
00401530 . 881F MOV BYTE PTR DS:[EDI],BL<-------把BL中数值存到DS:[EDI]处
00401532 . 47 INC EDI<------------------------EDI=EDI+1
00401533 .^ E2 D6 LOOPD SHORT CRACKME.0040150B<---循环到40150B处
上面这一段循环16次,输入的注册码按两个字符一组处理,字符若为小于或等于39,就把它的ASCII值减去30H,若大于39就减去37H,不妨设两个字符为a,b,则c=(((a-常数) shl 4) or (b-常数))and FFH,如我输入的注册码运算后在内存中如下:
00403970 78 78 78 78 78 78 78 78 xxxxxxxx
00403978 78 78 78 78 78 78 78 78 xxxxxxxx
这里就可以猜测它的注册码可能为32位的。
00401535 . B9 10000000 MOV ECX,10<------------------------置循环次数10H
0040153A . 8D3D 80394000 LEA EDI,DWORD PTR DS:[403980]
00401540 . 8D35 70394000 LEA ESI,DWORD PTR DS:[403970]<-----ESI指向上面运行完的结果
00401546 > 8A06 MOV AL,BYTE PTR DS:[ESI]<----------把ESI指向的数赋给AL
00401548 . 3245 FF XOR AL,BYTE PTR SS:[EBP-1]<--------AL=AL xor SS:[EBP-1]
0040154B . 8807 MOV BYTE PTR DS:[EDI],AL<----------把AL的值保存到DS:[EDI]中
0040154D . 46 INC ESI<---------------------------ESI++
0040154E . 47 INC EDI<---------------------------EDI++
0040154F .^ E2 F5 LOOPD SHORT CRACKME.00401546<------循环到401546处
SS:[EBP-1]中保存的是对用户名运算后得到的结果,上面的循环的功能就是把SS:[EBP-1]和上面对注册码处理得到的结果按字节异或保存到DS:[EDI]中,结果在内存中如下:
00403980 F3 F3 F3 F3 F3 F3 F3 F3 篌篌篌篌
00403988 F3 F3 F3 F3 F3 F3 F3 F3 篌篌篌篌
00403990 76 71 32 7A 79 62 6D 6D vq2zybmm
00403998 74 63 54 58 6F 72 4C 68 tcTXorLh
004039A0 77 63 75 78 76 73 6A 74 wcuxvsjt
004039A8 76 50 36 6A 6F 53 30 67 vP6joS0g
004039B0 54 47 39 32 5A 57 46 7A TG92ZWFz
004039B8 62 56 74 5A 51 30 64 64 bVtZQ0dd
004039C0 57 30 52 47 51 30 64 64 W0RGQ0dd
00401551 . B9 48000000 MOV ECX,48<-----------------------置循环次数48H
00401556 . 8D35 A7384000 LEA ESI,DWORD PTR DS:[4038A7]
ESI->"I Love Asm!I Love Crack!I Love Kathy!My Email:loveasm@sohu.com QQ:127095"
0040155C . 8D3D 80394000 LEA EDI,DWORD PTR DS:[403980]<----EDI指向上面运算后得到的结果
00401562 > 8A07 MOV AL,BYTE PTR DS:[EDI]<---------AL=DS:[EDI]
00401564 . 3206 XOR AL,BYTE PTR DS:[ESI]<---------AL=AL xor DS:[ESI]
00401566 . 8807 MOV BYTE PTR DS:[EDI],AL<---------DS:[EDI]=AL
00401568 . 46 INC ESI<--------------------------ESI++
00401569 . 47 INC EDI<--------------------------EDI++
0040156A .^ E2 F6 LOOPD SHORT CRACKME.00401562<-----循环到401562处
这一段循环的功能是把上面运算得到的结果与常串"vq2zybmmtcTXorLhwcuxvsjtvP6joS0gTG92ZWFzbVtZQ0ddW0RGQ0dd"连起来和字符串"I Love Asm!I Love Crack!I Love Kathy!My Email:loveasm@sohu.com QQ:127095"进行异或运算,结果还保存在DS:[403980]处。
0040156C . 68 F0384000 PUSH CRACKME.004038F0
00401571 . 68 80394000 PUSH CRACKME.00403980
00401576 . E8 2CFBFFFF CALL CRACKME.004010A7<-------F7进去看看
F7进入CALL CRACKME.004010A7,如下:
004010A7 /$Content$nbsp; 55 PUSH EBP
004010A8 |. 8BEC MOV EBP,ESP
004010AA |. 83C4 FC ADD ESP,-4
004010AD |. 53 PUSH EBX
004010AE |. 57 PUSH EDI
004010AF |. 56 PUSH ESI
004010B0 |. FF75 08 PUSH DWORD PTR SS:[EBP+8]
004010B3 |. E8 90060000 CALL <JMP.&kernel32.lstrlenA>
004010B8 |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX<--------EAX=48H
004010BB |. 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8]<--------ESI指向上面得到的结果
004010BE |. 8B7D 0C MOV EDI,DWORD PTR SS:[EBP+C]
004010C1 |. 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]<--------ECX=48H
004010C4 |. C1E9 02 SHR ECX,2<---------------------------ECX=ECX shr 2=12H
004010C7 |. FC CLD
004010C8 |> 51 /PUSH ECX
004010C9 |. B9 04000000 |MOV ECX,4<--------------------------置大循环次数4
004010CE |. 33DB |XOR EBX,EBX<------------------------EBX清0
004010D0 |. AD |LODS DWORD PTR DS:[ESI]<------------装入32位整数到EAX
004010D1 |> 50 |/PUSH EAX<--------------------------EAX压栈
004010D2 |. 25 FF000000 ||AND EAX,0FF<-----------------------取AL
004010D7 |. 8A80 41344000 ||MOV AL,BYTE PTR DS:[EAX+403441]<---把DS:[EAX+403441]处数据赋给AL
004010DD |. 3C FF ||CMP AL,0FF<------------------------比较AL是否和FF相等
004010DF |. 74 22 ||JE SHORT CRACKME.00401103<---------相等就跳
004010E1 |. C1E3 06 ||SHL EBX,6<-------------------------EBX=EBX shl 6,EBX初值为0
004010E4 |. 0AD8 ||OR BL,AL<--------------------------BL=BL or AL
004010E6 |. 58 ||POP EAX<---------------------------重新装入32位整数
004010E7 |. C1E8 08 ||SHR EAX,8<-------------------------EAX=EAX shr 8
004010EA |. 49 ||DEC ECX<---------------------------ECX=ECX-1
004010EB |.^ 75 E4 |JNZ SHORT CRACKME.004010D1<--------不等就跳到4010D1处
004010ED |. 8BC3 |MOV EAX,EBX<------------------------EAX=EBX
004010EF |. C1E0 08 |SHL EAX,8<--------------------------EAX=EAX shl 8
004010F2 |. 86E0 |XCHG AL,AH<-------------------------交换AL和AH的值
004010F4 |. C1C8 10 |ROR EAX,10<-------------------------EAX=EAX ror 10
004010F7 |. 86E0 |XCHG AL,AH<-------------------------再交换AL和AH的值
004010F9 |. AB |STOS DWORD PTR ES:[EDI]<------------把EAX的值保存到ES[EDI]中
004010FA |. 4F |DEC EDI<----------------------------EDI--
004010FB |. 59 |POP ECX<----------------------------ECX出栈
004010FC |. 49 |DEC ECX<----------------------------ECX--
004010FD |.^ 75 C9 JNZ SHORT CRACKME.004010C8<---------不等于0就跳到4010C8处
004010FF |. 33C0 XOR EAX,EAX<-------------------------EAX清0
00401101 |. EB 05 JMP SHORT CRACKME.00401108<----------跳
00401103 |> B8 FFFFFFFF MOV EAX,-1
00401108 |> 5E POP ESI
00401109 |. 5F POP EDI
0040110A |. 5B POP EBX
0040110B |. C9 LEAVE
0040110C . C2 0800 RETN 8
这段函数好像没有用,最后总是使EAX=0xFFFFFFFF,这是由于我们输入的注册码不正确的原因。
从403441开始的常数表如下:
00403440 3D FF FF FF FF FF FF FF
00403448 FF FF FF FF FF FF FF FF
00403450 FF FF FF FF FF FF FF FF
00403458 FF FF FF FF FF FF FF FF
00403460 FF FF FF FF FF FF FF FF
00403468 FF FF FF FF 3E FF FF FF
00403470 3F 34 35 36 37 38 39 3A
00403478 3B 3C 3D FF FF FF 00 FF
00403480 FF FF 00 01 02 03 04 05
00403488 06 07 08 09 0A 0B 0C 0D
00403490 0E 0F 10 11 12 13 14 15
00403498 16 17 18 19 FF FF FF FF
004034A0 FF FF 1A 1B 1C 1D 1E 1F
004034A8 20 21 22 23 24 25 26 27
004034B0 28 29 2A 2B 2C 2D 2E 2F
004034B8 30 31 32 33 FF FF FF FF
004034C0 FF FF FF FF FF FF FF FF
004034C8 FF FF FF FF FF FF FF FF
004034D0 FF FF FF FF FF FF FF FF
004034D8 FF FF FF FF FF FF FF FF
004034E0 FF FF FF FF FF FF FF FF
004034E8 FF FF FF FF FF FF FF FF
004034F0 FF FF FF FF FF FF FF FF
004034F8 FF FF FF FF FF FF FF FF
00403500 FF FF FF FF FF FF FF FF
00403508 FF FF FF FF FF FF FF FF
00403510 FF FF FF FF FF FF FF FF
00403518 FF FF FF FF FF FF FF FF
00403520 FF FF FF FF FF FF FF FF
00403528 FF FF FF FF FF FF FF FF
00403530 FF FF FF FF FF FF FF FF
00403538 FF FF FF FF FF FF FF FF
0040157B . 68 A4384000 PUSH CRACKME.004038A4
00401580 . 68 F0384000 PUSH CRACKME.004038F0
00401585 . E8 B8010000 CALL <JMP.&kernel32.lstrcatA>
这个函数的功能是把上面运算得到的结果接在字符串"I Love Asm!I Love Crack!I Love Kathy!My Email:loveasm@sohu.com QQ:127095"的后面返回字符串地址到EAX中。
0040158A . E8 CCFAFFFF CALL CRACKME.0040105B<--------------按F7进去看看
进入CALL CRACKME.0040105B后如下:
0040105B /$Content$nbsp; B9 00010000 MOV ECX,100<------------------------ECX=100
00401060 |. BA 2083B8ED MOV EDX,EDB88320<-------------------EDX=EDB88320
00401065 |> 8D41 FF /LEA EAX,DWORD PTR DS:[ECX-1]
00401068 |. 51 |PUSH ECX<--------------------------保存ECX到堆栈中
00401069 |. B9 08000000 |MOV ECX,8<-------------------------置小循环次数8
0040106E |> D1E8 |/SHR EAX,1<------------------------EAX=EAX shr 1
00401070 |. 73 02 ||JNB SHORT CRACKME.00401074
00401072 |. 33C2 ||XOR EAX,EDX<----------------------EAX=EAX xor EDX
00401074 |> 49 ||DEC ECX<--------------------------ECX--
00401075 |.^ 75 F7 |JNZ SHORT CRACKME.0040106E<-------不等于0就跳到40106E处
00401077 |. 59 |POP ECX<---------------------------恢复ECX
00401078 |. 89048D FC2F40>|MOV DWORD PTR DS:[ECX*4+402FFC],EAX<---把EAX的值放到[ECX*4+402FFC]中
0040107F |. 49 |DEC ECX<-------------------------------ECX--
00401080 |.^ 75 E3 JNZ SHORT CRACKME.00401065<--------不等于0就跳到00401065处
00401082 . C3 RETN
这一段的功能实际上是生成一个常数表,表中元素的个数为FFH。表的起始地址为403004。在内存中如下:
00403000 00000000 77073096 EE0E612C 990951BA
00403010 076DC419 706AF48F E963A535 9E6495A3
00403020 0EDB8832 79DCB8A4 E0D5E91E 97D2D988
00403030 09B64C2B 7EB17CBD E7B82D07 90BF1D91
00403040 1DB71064 6AB020F2 F3B97148 84BE41DE
00403050 1ADAD47D 6DDDE4EB F4D4B551 83D385C7
00403060 136C9856 646BA8C0 FD62F97A 8A65C9EC
00403070 14015C4F 63066CD9 FA0F3D63 8D080DF5
00403080 3B6E20C8 4C69105E D56041E4 A2677172
00403090 3C03E4D1 4B04D447 D20D85FD A50AB56B
004030A0 35B5A8FA 42B2986C DBBBC9D6 ACBCF940
004030B0 32D86CE3 45DF5C75 DCD60DCF ABD13D59
004030C0 26D930AC 51DE003A C8D75180 BFD06116
004030D0 21B4F4B5 56B3C423 CFBA9599 B8BDA50F
004030E0 2802B89E 5F058808 C60CD9B2 B10BE924
004030F0 2F6F7C87 58684C11 C1611DAB B6662D3D
00403100 76DC4190 01DB7106 98D220BC EFD5102A
00403110 71B18589 06B6B51F 9FBFE4A5 E8B8D433
00403120 7807C9A2 0F00F934 9609A88E E10E9818
00403130 7F6A0DBB 086D3D2D 91646C97 E6635C01
00403140 6B6B51F4 1C6C6162 856530D8 F262004E
00403150 6C0695ED 1B01A57B 8208F4C1 F50FC457
00403160 65B0D9C6 12B7E950 8BBEB8EA FCB9887C
00403170 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65
00403180 4DB26158 3AB551CE A3BC0074 D4BB30E2
00403190 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB
004031A0 4369E96A 346ED9FC AD678846 DA60B8D0
004031B0 44042D73 33031DE5 AA0A4C5F DD0D7CC9
004031C0 5005713C 270241AA BE0B1010 C90C2086
004031D0 5768B525 206F85B3 B966D409 CE61E49F
004031E0 5EDEF90E 29D9C998 B0D09822 C7D7A8B4
004031F0 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD
00403200 EDB88320 9ABFB3B6 03B6E20C 74B1D29A
00403210 EAD54739 9DD277AF 04DB2615 73DC1683
00403220 E3630B12 94643B84 0D6D6A3E 7A6A5AA8
00403230 E40ECF0B 9309FF9D 0A00AE27 7D079EB1
00403240 F00F9344 8708A3D2 1E01F268 6906C2FE
00403250 F762575D 806567CB 196C3671 6E6B06E7
00403260 FED41B76 89D32BE0 10DA7A5A 67DD4ACC
00403270 F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5
00403280 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252
00403290 D1BB67F1 A6BC5767 3FB506DD 48B2364B
004032A0 D80D2BDA AF0A1B4C 36034AF6 41047A60
004032B0 DF60EFC3 A867DF55 316E8EEF 4669BE79
004032C0 CB61B38C BC66831A 256FD2A0 5268E236
004032D0 CC0C7795 BB0B4703 220216B9 5505262F
004032E0 C5BA3BBE B2BD0B28 2BB45A92 5CB36A04
004032F0 C2D7FFA7 B5D0CF31 2CD99E8B 5BDEAE1D
00403300 9B64C2B0 EC63F226 756AA39C 026D930A
00403310 9C0906A9 EB0E363F 72076785 05005713
00403320 95BF4A82 E2B87A14 7BB12BAE 0CB61B38
00403330 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21
00403340 86D3D2D4 F1D4E242 68DDB3F8 1FDA836E
00403350 81BE16CD F6B9265B 6FB077E1 18B74777
00403360 88085AE6 FF0F6A70 66063BCA 11010B5C
00403370 8F659EFF F862AE69 616BFFD3 166CCF45
00403380 A00AE278 D70DD2EE 4E048354 3903B3C2
00403390 A7672661 D06016F7 4969474D 3E6E77DB
004033A0 AED16A4A D9D65ADC 40DF0B66 37D83BF0
004033B0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9
004033C0 BDBDF21C CABAC28A 53B39330 24B4A3A6
004033D0 BAD03605 CDD70693 54DE5729 23D967BF
004033E0 B3667A2E C4614AB8 5D681B02 2A6F2B94
004033F0 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D
此时内存如下:
004038F0 20 2D 20 49 20 4C 6F 76 - I Lov
004038F8 65 20 41 73 6D 21 49 20 e Asm!I
00403900 4C 6F 76 65 20 43 72 61 Love Cra
00403908 63 6B 21 49 20 4C 6F 76 ck!I Lov
00403910 65 20 4B 61 74 68 79 21 e Kathy!
00403918 4D 79 20 45 6D 61 69 6C My Email
00403920 3A 6C 6F 76 65 61 73 6D :loveasm
00403928 40 73 6F 68 75 2E 63 6F @sohu.co
00403930 6D 20 51 51 3A 31 32 37 m QQ:127
00403938 30 39 35 20 2D 20 49 20 095 - I
00403940 4C 6F 76 65 20 41 73 6D Love Asm
00403948 21 49 20 4C 6F 76 65 20 !I Love
00403950 43 72 61 63 6B 21 49 20 Crack!I
00403958 4C 6F 76 65 20 4B 61 74 Love Kat
00403960 68 79 21 4D 79 20 45 6D hy!My Em
00403968 61 69 6C 3A 6C 6F 76 65 ail:love
00403970 78 78 78 78 78 78 78 78 xxxxxxxx
00403978 78 78 78 78&, nbsp;78 78 78 78 xxxxxxxx
00403980 BA D3 BF 9C 85 96 D3 B2 河繙厲硬
00403988 80 9E D2 BA D3 BF 9C 85 €炓河0渽
00403990 13 51 71 08 18 01 06 4C QqL
00403998 3D 43 18 37 19 17 6C 23 =C7l#
004039A0 16 17 1D 01 57 3E 13 54 W>T
004039A8 33 3D 57 03 03 69 5C 08 3=Wi
004039B0 22 22 58 41 37 17 35 15 ""XA75
004039B8 0A 23 5A 39 3E 5D 44 35 .#Z9>]D5
004039C0 06 0A 63 75 66 20 2D 20 .cuf -
004039C8 49 20 4C 6F 76 65 20 41 I Love A
004039D0 73 6D 21 49 20 4C 6F 76 sm!I Lov
004039D8 65 20 43 72 61 63 6B 21 e Crack!
004039E0 49 20 4C 6F 76 65 20 4B I Love K
004039E8 61 74 68 79 21 4D 79 20 athy!My
004039F0 45 6D 61 69 6C 3A 6C 6F Email:lo
004039F8 76 65 61 73 6D 40 73 6F veasm@so
00403A00 68 75 2E 63 6F 6D 20 51 hu.com Q
00403A08 51 3A 31 32 37 30 39 35 Q:127095
继续往下分析:
0040158F . 8D1D F0384000 LEA EBX,DWORD PTR DS:[4038F0]<------EBX指向上面计算得到的串
00401595 . E8 E9FAFFFF CALL CRACKME.00401083<--------------按F7进去看看
进入CALL CRACKME.00401083后如下:
00401083 /$Content$nbsp; B8 FFFFFFFF MOV EAX,-1<----------------------------EAX=-1
00401088 |. 0BDB OR EBX,EBX
0040108A |. 74 18 JE SHORT CRACKME.004010A4<-------------EBX若为0就跳
0040108C |> 8A13 /MOV DL,BYTE PTR DS:[EBX]<-------------DL=DS:[EBX]
0040108E |. 0AD2 |OR DL,DL
00401090 |. 74 12 |JE SHORT CRACKME.004010A4<------------为0就跳
00401092 |. 32D0 |XOR DL,AL<----------------------------DL=AL xor DL
00401094 |. 0FB6D2 |MOVZX EDX,DL<-------------------------EDX=DL
00401097 |. C1E8 08 |SHR EAX,8<----------------------------EAX=EAX shr 8
0040109A |. 330495 003040>|XOR EAX,DWORD PTR DS:[EDX*4+403000]<--EAX=EAX xor DS:[EDX*4+403000]
004010A1 |. 43 |INC EBX<------------------------------EBX++
004010A2 |.^ EB E8 JMP SHORT CRACKME.0040108C<-----------跳到40108C
004010A4 |> F7D0 NOT EAX<-------------------------------EAX=NOT EAX
004010A6 . C3 RETN
又是一个循环,这个循环就是把刚刚生成的表和上面计算得到的串进行运算,运算规则见注释,最后把结果保存到EAX中。
0040159A . 3D CA86B0C4 CMP EAX,C4B086CA<-------------比较EAX的值是否和C4B086CA相等
0040159F .75 3E JNZ SHORT CRACKME.004015DF<---对比点,不相等就跳
通过以上的分析,我们可以知道,这个CrackMe的算法用到了一个有着FF个元素的32位整数表,还用了一个有着FF个元素的8位整数表。算法看起来比较复杂,但是仔细分析一下,我们知道,把JNZ SHORT CRACKME.004015DF改成JZ SHORT CRACKME.004015DF,出来的提示是"I Love Asm!..."这样的提示,说明程序会把上面的字符变成"恭喜您!您已经成功的注册了本软件!",这里为什么没有变呢,原因就在CALL CRACKME.004010A7里面,这个函数的功能就是读[403980]处开始的16个字节的数据,然后进行运算,运算结果保存到ES:[EDI]即内存[4038F0]开始的地方,若注册成功,则对话框的提示字符串就是从这儿取的。那么到底是哪16个字节经过CALL CRACKME.004010A7能得到"恭喜您!您已经成功的注册了本软件!"这样正确的提示信息呢?这里作者帮了一个大忙,感谢Loveasm了^_^,通过跟踪,我发现是如下的16个字节运算后能得到正确的提示信息:
3C 41 2A 3F 05 16 74 77 1C 5B 69 0C 0B 38 23 24
当然你可以分析CALL CRACKME.004010A7利用"恭喜您!您已经成功的注册了本软件!"算出这16个字节来,这是此CrackMe的核心。这么一分析,我们就可以看出,这个CrackMe给我们设置了一个超级陷阱,正确的注册码的获得只与上面16个字节有关,与那个一个长整数表无关,作者算法设计得很巧妙,把这个掩盖得很好,只是作者给了一个正确的注册码给了我们以可乘之机。看来以后谁发布CrackMe时,最好先别把正确的注册码公布,或者把算法设计得更好些。
给出我的注册码:
用户名:onlyu[FCG][DFCG]
注册码:B7CAA1B48E9DFFFC97D0E28780B3A8AF
用VC 6.0编写注册机,单击按钮的代码如下:
void CKeygenDlg::OnOK()
{
// TODO: Add extra validation here
int i;
unsigned char num=0;
unsigned char str[17]={0x3C,0x41,0x2A,0x3F,0x05,0x16,0x74,0x77,
0x1C,0x5B,0x69,0x0C,0x0B,0x38,0x23,0x24,0x0};
char str1[33];
str1[33]=0;
UpdateData(TRUE);
if(m_name=="") AfxMessageBox("请输入用户名!");
else
{
for(i=0;i<m_name.GetLength();i++)
num+=m_name[i];
for(i=0;i<16;i++) str[i]=num^str[i];
for(i=0;i<16;i++) sprintf(str1+2*i,"%0x",str[i]);
m_sn=str1;
m_sn.MakeUpper();
}
UpdateData(FALSE);
}
补充一下,对于破解中遇到的那个长度为FFh的32位整数表,好像在那里见过,拿看雪的书一查看,才发现是CRC32校验的常数表,这下我对这个Crackme的整个判断过程就清晰多了。重新总结一下,作者计算如下数据的CRC校验值:
004038F0 B9 A7 CF B2 C4 FA A3 A1 恭喜您!
004038F8 C4 FA D2 D1 BE AD B3 C9 您已经成
00403900 B9 A6 B5 C4 D7 A2 B2 E1 功的注册
00403908 C1 CB B1 BE C8 ED BC FE 了本软件
00403910 A3 A1 2D 20 4C 6F 76 65 !- Love
00403918 61 73 6D 5B 59 43 47 5D asm[YCG]
00403920 5B 44 46 43 47 5D 20 2D [DFCG] -
00403928 20 49 20 4C 6F 76 65 20 I Love
00403930 41 73 6D 21 49 20 4C 6F Asm!I Lo
00403938 76 65 20 43 72 61 63 6B ve Crack
00403940 21 49 20 4C 6F 76 65 20 !I Love
00403948 4B 61 74 68 79 21 4D 79 Kathy!My
00403950 20 45 6D 61 69 6C 3A 6C Email:l
00403958 6F 76 65 61 73 6D 40 73 oveasm@s
00403960 6F 68 75 2E 63 6F 6D 20 ohu.com
00403968 51 51 3A 31 32 37 30 39 QQ:12709
00403970 35 5
若校验值为C4B086CA,则正确,若不相等,则错误,而这个串的获得是由用户输入的正确的注册码运算出来的,若输入的注册码不正确,则得不到正确的提示信息,爆破也没有用。
一般CRC校验算法是把注册名和注册码按某种运算之后的值进行校验,而这个Crackme还把要显示的正确提示信息进行了校验,算法很巧妙,故题目加上CRC32算法的妙用。真是佩服Loveasm[YCG][DFCG],能用纯汇编实现这么好的Crackme,真是厉害,再次感谢!