【文章标题】: [破]CrackMe.REVENGE Crew.WinASM.2006
【文章作者】: HappyTown
【作者主页】: www.pediy.com
【软件名称】: crackme
【软件大小】: 133KB(zip)
【下载地址】: 附件内
【加壳方式】: UPX 0.89.6 - 1.02 / 1.05 - 1.24
【保护方式】: RSA-64 + Base64 + MD5(modified)
【编写语言】: Win32ASM
【使用工具】: OD,IDA,RSATool
【操作平台】: WinXP
【软件介绍】: REVENGE Crew 在2006年的 Official Trial CrackMe
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
因为这是REVENGE Crew在2006年的Official Trial CrackMe,所以,一直没有把这个分析贴出来,现在已经是2007年,应该没事了吧。
试练码:
Name: happy
Serial: 9876543210222222-222333333333!
输入成这种格式的原因在下面。
脱壳,运行来到解密后的关键代码处:
00401DCF >mov ebx, 00408E2A ; ASCII "9876543210222222-222333333333!"
00401DD4 >add ebx, 10
00401DD7 >xor eax, eax
00401DD9 >mov al, [ebx]
00401DDB >cmp eax, 2D ; sn第17个字符是否是'-'
00401DDE ^>jnz short 00401DBA
00401DE0 >mov ebx, 00408E2A ; ASCII "9876543210222222-222333333333!"
00401DE5 >mov ecx, [408FA4]
00401DEB >dec ecx
00401DEC >add ebx, ecx
00401DEE >mov al, [ebx]
00401DF0 >cmp eax, 21 ; sn最后一个字符是否是'!'
00401DF3 ^>jnz short 00401DBA
00401DF5 >push 11
00401DF7 >lea eax, [ebp-14]
00401DFA >push eax
00401DFB >call <jmp.&kernel32.RtlZeroMemory>
00401E00 >push 0D
00401E02 >lea eax, [ebp-28]
00401E05 >push eax
00401E06 >call <jmp.&kernel32.RtlZeroMemory>
00401E0B >push 32
00401E0D >push 00408F2A
00401E12 >call <jmp.&kernel32.RtlZeroMemory>
00401E17 >lea esi, [408E2A]
00401E1D >push 10
00401E1F >lea eax, [ebp-14]
00401E22 >push eax
00401E23 >push esi ; sn
00401E24 >call <lstrncpy> ;取得sn的前16个字符:sn_1
00401E29 >pushad
00401E2A >lea eax, [ebp-14]
00401E2D >push eax
00401E2E >call <jmp.&kernel32.lstrlen>
00401E33 >mov ecx, eax
00401E35 >lea ebx, [ebp-14] ; sn_1
00401E38 >xor eax, eax
00401E3A >xor edx, edx
00401E3C >mov al, [ebx]
00401E3E >or al, al ; //检测sn_1的字符是否属于0~9,A~F
00401E40 >je short 00401E59
00401E42 >cmp al, 30
00401E44 >jb short 00401E4D
00401E46 >cmp al, 39
00401E48 >ja short 00401E4D
00401E4A >inc edx
00401E4B >jmp short 00401E56
00401E4D >cmp al, 41
00401E4F >jb short 00401E56
00401E51 >cmp al, 46
00401E53 >ja short 00401E56
00401E55 >inc edx
00401E56 >inc ebx
00401E57 ^>jmp short 00401E3C
00401E59 >cmp edx, 10
00401E5C ^>jnz 00401DBA ; \\
00401E62 >popad
00401E63 >add esi, 11
00401E66 >push 0C ; 12
00401E68 >lea eax, [ebp-28]
00401E6B >push eax
00401E6C >push esi ; sn_2(不包括最后的"!")
00401E6D >call <lstrncpy>
00401E72 >lea esi, [ebp-28]
00401E75 >push esi ; sn_2
00401E76 >push 0C ; 12
00401E78 >lea eax, [ebp-28]
00401E7B >push eax ; sn_2
00401E7C >call <Base64Decode> ; sn_2' = Base64Decode(sn_2),只有跟进去才能识别出来
00401E81 >push 0
00401E83 >call <_big_create@4>
00401E88 >mov [408F9C], eax
00401E8D >push 0
00401E8F >call <_big_create@4>
00401E94 >mov [408F8C], eax
00401E99 >push 0
00401E9B >call <_big_create@4>
00401EA0 >mov [408F94], eax
00401EA5 >push dword ptr [408F9C]
00401EAB >lea eax, [ebp-14]
00401EAE >push eax ; sn_1
00401EAF >call <_big_cinstr@8>
00401EB4 >push dword ptr [408F8C]
00401EBA >push 0040836D ; ASCII "80FCD59237BDF149"
00401EBF >call <_big_cinstr@8>
00401EC4 >push dword ptr [408F94]
00401ECA >push 0040837E ; ASCII "10001"
00401ECF >call <_big_cinstr@8>
00401ED4 >push dword ptr [408F9C] ; sn_1
00401EDA >push dword ptr [408F8C] ; n
00401EE0 >push dword ptr [408F94] ; e
00401EE6 >push dword ptr [408F9C] ; sn_1
00401EEC >call <_big_powmod@16> ; sn_1=sn_1^e (mod n)=599420D7ACCA8EE5
00401EF1 >push 00408F2A
00401EF6 >push dword ptr [408F9C] ; sn_1
00401EFC >call <_big_big_to_bytes@8>
很明显的RSA算法,用RSATool分解n,结果如下:
n=p*q:
80FCD59237BDF149
p:
B05851CB
q:
BB4056BB
d:
17911A5C18507F99
e:
10001
00401F01 >push dword ptr [408F8C]
00401F07 >call <_big_destroy@4>
00401F0C >push dword ptr [408F94]
00401F12 >call <_big_destroy@4>
00401F17 >push dword ptr [408F9C]
00401F1D >call <_big_destroy@4>
00401F22 >lea eax, [ebp-28]
00401F25 >push eax ; sn_2'
00401F26 >push 00408F2A ; sn_1 = sn_1 + sn_2'
00401F2B >call <jmp.&kernel32.lstrcat>
00401F30 >push 00408DF8 ; name
00401F35 >call <jmp.&kernel32.lstrlen>
00401F3A >push 00408F5C
00401F3F >push eax ; nameLen
00401F40 >push 00408DF8 ; name
00401F45 >call <MD5(modified)> ; MD5(name) ===>跟进去
<MD5(modified)>
{
0040202E > >push ebp
......
00402082 >mov dword ptr [esi], 4552205B ; //这4个state常数被更改
00402088 >mov dword ptr [esi+4], 474E4556
0040208F >mov dword ptr [esi+8], 72432045
00402096 >mov dword ptr [esi+C], 5D207765; \\
......
}
00401F4A >mov ecx, eax
00401F4C >mov ebx, 00408DF8 ; ASCII "9062A7B02DF78E2"
00401F51 >xor eax, eax
00401F53 >mov al, [ebx] ; //MD5值小写转大写[MD5(name):"9062a7b02df78e22e50417eed97a3e02"]
00401F55 >or al, al ; MD5[i]
00401F57 >je short 00401F68
00401F59 >cmp al, 61
00401F5B >jb short 00401F65
00401F5D >cmp al, 7A
00401F5F >ja short 00401F65
00401F61 >sub al, 20
00401F63 >mov [ebx], al
00401F65 >inc ebx
00401F66 ^>jmp short 00401F53 ; \\
00401F68 >xor ebx, ebx
00401F6A >mov eax, 00408DF8 ; MD5
00401F6F >add eax, 0F
00401F72 >mov byte ptr [eax], 0 ; MD5值第16字符置\null,即MD5值仅取前15位有效
00401F75 >push 00408F2A ; sn_1 = sn_1 + sn_2'
00401F7A >push 00408DF8 ; ASCII "9062A7B02DF78E2"
00401F7F >call <jmp.&kernel32.lstrcmp>
00401F84 >retn
小总一下程序验证的思路:
(1) sn_1 = sn_1^e (mod n);
(2) sn_2'= Base64Decode(sn_2);
(3) 串接 sn_1(8字节) 和 sn_2'(7字节),并与MD5(name)后的前15字节进行比较判断。
那么注册算法就是:
(1) 对MD5(name)前8字节进行RSA解密运算生成sn_1;
(2) 对MD5(name)中间的7字节进行Base64编码生成sn_2;
(3) 用'-'连接sn_1和sn_2,并在最末端添加一'!'即可。
注册机源代码祥见附件,这里仅给出几组可用的注册码:
Name: happy
Serial: 4B36C7C6B3A5D799-MkRGNzhFMg==!
Name: 看雪学院
Serial: 142F41BA4C9A496B-MTFCMURDRg==!
因为编辑框背景和输入的字体颜色相同,所以,需要选中方能知道注册成功与否。
--------------------------------------------------------------------------------
【经验总结】
没什么难度嘛,大家只要学习一些密码学的知识,我相信各位都可以加入这些组织。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪软件安全论坛, 转载请注明作者并保持文章的完整, 谢谢!
2007年01月24日 19:20:42
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!