【文章作者】: aalloverred
【软件名称】: crackme.8.other-rev
【下载地址】: http://lord-Phoenix.com/crackme.8.other-rev.zip
或见附件。
【使用工具】: Ollydbg,ollydump插件,PEiD,win计算器,RadASM
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!Keygen可能有什么漏洞,若大家发现请指出!
--------------------------------------------------------------------------------
【详细过程】
1。查壳
使用Peid:UPX 0.89.6 - 1.02 / 1.05 - 1.24 -> Markus & Laszlo。
2。脱壳
脱壳很简单,我只知道方法,载入Olly,拉动滚动条到这里:
00428E9F .-E9 FB8AFDFF JMP crackme.0040199F
运行到40199F使用ollydump脱壳,经试验,使用修复方法2重建输入表,存为crackme1.exe,能够正常运行。
不再多说,进入正题。
3。算法分析
将脱好的crackme1.exe载入PEiD:MASM32 / TASM32,使用KANAL插件看到:base64,crc32,tean,OK,下面使用OllyDbg
分析。按DialogProc->WM_COMMAND->BTN_ID的路线找到注册码的验证过程:
...
0040212C 83F8 01 CMP EAX,1
0040212F 73 1F JNB SHORT Crackme1.00402150
00402131 68 EB734000 PUSH Crackme1.004073EB ; ASCII "I need ur name :P"
...
00402150 83F8 32 CMP EAX,32
00402153 76 13 JBE SHORT Crackme1.00402168
00402155 68 FD734000 PUSH Crackme1.004073FD ; ASCII "Name too long!"
...
所以用户名应该是1-50个字符。
...
00402174 E8 AB050000 CALL <JMP.&user32.GetDlgItemTextA> ; 获得输入的序列号.
00402179 A1 D87A4000 MOV EAX,DWORD PTR DS:[407AD8] ; 用户名存储地址.
0040217E 35 37130000 XOR EAX,1337
00402183 C1C8 0D ROR EAX,0D
00402186 05 EFBE0000 ADD EAX,0BEEF
0040218B 35 02600620 XOR EAX,20066002
00402190 A3 787B4000 MOV DWORD PTR DS:[407B78],EAX ; 根据前四个字符计算出一个值(fname),后面使用.
00402195 68 0A7B4000 PUSH Crackme1.00407B0A
0040219A E8 C3010000 CALL Crackme1.00402362 ; 序列号的长度须是40且只能包好0-9,A-F.
0040219F 83F8 FF CMP EAX,-1
004021A2 0F84 83000000 JE Crackme1.0040222B ; 跳就不是好孩子:D
004021A8 83F8 00 CMP EAX,0
004021AB 0F84 99000000 JE Crackme1.0040224A ; 跳就不是好孩子:D
跟入00402362,说说序列号长度验证的地方:
...
00402368 E8 8F040000 CALL <JMP.&KERNEL32.lstrlenA>
0040236D A3 907B4000 MOV DWORD PTR DS:[407B90],EAX ; 序列号长度x
00402372 50 PUSH EAX
00402373 59 POP ECX
00402374 F7E0 MUL EAX ; x*x
00402376 69C0 37130300 IMUL EAX,EAX,31337 ; 31337*x*x
0040237C 69C9 0AD60000 IMUL ECX,ECX,0D60A ; 0D60*x
00402382 03C1 ADD EAX,ECX
00402384 2D 50895913 SUB EAX,13598950 ; 31337*x*x+0D60A*x-13598950=0?
00402389 74 07 JE SHORT Crackme1.00402392 ; x=40.
...
一元二次方程,晕,按了半天计算器,终于按出来x=40.呵呵。
继续吧:
...
004021C4 A3 8C7B4000 MOV DWORD PTR DS:[407B8C],EAX
004021C9 50 PUSH EAX
004021CA 68 0A7B4000 PUSH Crackme1.00407B0A ;
004021CF E8 F7010000 CALL Crackme1.004023CB ; 又一个验证
004021D4 83F8 01 CMP EAX,1
004021D7 0F85 8C000000 JNZ Crackme1.00402269 ; 别跳!
004021DD A1 8C7B4000 MOV EAX,DWORD PTR DS:[407B8C]
004021E2 8B50 08 MOV EDX,DWORD PTR DS:[EAX+8] ; serial.part3
004021E5 8B40 04 MOV EAX,DWORD PTR DS:[EAX+4] ; teadecrypt.part2
004021E8 33C2 XOR EAX,EDX
004021EA 8B15 8C7B4000 MOV EDX,DWORD PTR DS:[407B8C]
004021F0 C702 2D000000 MOV DWORD PTR DS:[EDX],2D ; sub eax,XXXXXXXX指令
004021F6 8942 01 MOV DWORD PTR DS:[EDX+1],EAX
004021F9 C742 05 C3000000 MOV DWORD PTR DS:[EDX+5],0C3 ; ret指令
00402200 A1 787B4000 MOV EAX,DWORD PTR DS:[407B78] ; 见00402190
00402205 FFD2 CALL EDX
00402207 8B52 0C MOV EDX,DWORD PTR DS:[EDX+C] ; serial.part4
0040220A 33C2 XOR EAX,EDX
0040220C 83F8 00 CMP EAX,0
0040220F 75 77 JNZ SHORT Crackme1.00402288
这里call验证后面的部分总结起来就是:if(fnam-serial.part3^teadecrypt.part2==serial.part4)good;
然后再跟进004023CB ,看看eax怎么才能等于1:
...
004023E9 E8 0E040000 CALL <JMP.&KERNEL32.lstrlenA> ; 序列号长度.
004023EE 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+8]
004023F1 8B55 0C MOV EDX,DWORD PTR SS:[EBP+C]
004023F4 55 PUSH EBP ; 保存ebp
004023F5 33ED XOR EBP,EBP
004023F7 83E8 08 SUB EAX,8
004023FA 74 14 JE SHORT Crackme1.00402410
004023FC 50 PUSH EAX ; 保存eax
004023FD 51 PUSH ECX
004023FE E8 E8000000 CALL <Crackme1.str2int> ; 将传入地址起始处的八个字节转化为数字
00402403 894415 00 MOV DWORD PTR SS:[EBP+EDX],EAX
00402407 58 POP EAX ; 恢复eax
00402408 83C5 04 ADD EBP,4
0040240B 83C1 08 ADD ECX,8
0040240E ^EB E7 JMP SHORT Crackme1.004023F7
00402410 5D POP EBP ; 恢复ebp
...
00402422 68 7C7B4000 PUSH Crackme1.00407B7C ; 看00402190处.这是tea算法的key
00402427 E8 38010000 CALL <Crackme1.tea_init>
0040242C FF35 947B4000 PUSH DWORD PTR DS:[407B94]
00402432 FF75 0C PUSH DWORD PTR SS:[EBP+C]
00402435 E8 62010000 CALL Crackme1.0040259C ; tea_decrypt
0040243A 6A 08 PUSH 8
0040243C FF35 947B4000 PUSH DWORD PTR DS:[407B94]
00402442 FF75 0C PUSH DWORD PTR SS:[EBP+C]
00402445 E8 87000000 CALL Crackme1.004024D1 ; 存储结果
0040244A 68 00400000 PUSH 4000
0040244F 68 E8030000 PUSH 3E8
00402454 FF35 947B4000 PUSH DWORD PTR DS:[407B94]
0040245A E8 97030000 CALL <JMP.&KERNEL32.VirtualFree>
0040245F 6A 40 PUSH 40
00402461 68 00100000 PUSH 1000
00402466 68 E8030000 PUSH 3E8
0040246B 6A 00 PUSH 0
0040246D E8 7E030000 CALL <JMP.&KERNEL32.VirtualAlloc>
00402472 A3 987B4000 MOV DWORD PTR DS:[407B98],EAX
00402477 68 D87A4000 PUSH Crackme1.00407AD8
0040247C E8 7B030000 CALL <JMP.&KERNEL32.lstrlenA>
00402481 FF35 987B4000 PUSH DWORD PTR DS:[407B98]
00402487 50 PUSH EAX
00402488 68 D87A4000 PUSH Crackme1.00407AD8
0040248D E8 C2010000 CALL <Crackme1.base64> ; 用户名base64
00402492 6A 00 PUSH 0
00402494 50 PUSH EAX
00402495 FF35 987B4000 PUSH DWORD PTR DS:[407B98]
0040249B E8 90000000 CALL <Crackme1.CRC32> ; 再取crc32
004024A0 8B55 0C MOV EDX,DWORD PTR SS:[EBP+C]
004024A3 2902 SUB DWORD PTR DS:[EDX],EAX ; 与teadecrypt的结果比较 ...
这里总结起来就是if(crc32(base64(name))==teadecrypt(key).part1)good;
4。keygen。不知道怎么回事,有时总能生成正确的serial,有时确总是不能生成正确的serial。这是为什么呢?郁闷。
使用了drizz的cryptolib。thx to him. and to lord as well.;)
压缩包里有我的keygen和原crackme。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)