【文章标题】: HappyTown的第29个CrackMe分析
【文章作者】: HorstStein
【原贴地址】: http://bbs.pediy.com/showthread.php?s=&threadid=34166
--------------------------------------------------------------------------------
【详细过程】
aalloverred已经给出了一种解决方案,我现在从另外的角度分析一下。
HappyTown的这个crackme有两个要点:
(1)hash函数的hash_ctx结构填充0而不是0x80;
(2)所采用的公钥加密算法;
公钥算法描述:
1.A选择两个数P和Q,它们与(P-1)和(Q-1)互素。
2.A公布N=PQ作为它的公开密钥。
3.A计算P'和Q'使得PP'≡1(mod Q-1)和QQ'≡1(mod P-1)成立。
4.B加密报文M为C=M^N(mod N)。
5.A通过解M≡C^P'(mod Q)和M≡C^Q'(mod P)求出M。
HappyTown给出了N和Q,使得仅使用除法而不需要分解N即可算出P,方便了很多。
00401610 sub esp, 104
00401616 push ebx
00401617 push ebp
00401618 push esi
00401619 push edi
0040161A mov ecx, 18
0040161F xor eax, eax
00401621 lea edi, [esp+B1]
00401628 mov byte ptr [esp+B0], 0
00401630 rep stos dword ptr es:[edi]
00401632 stos word ptr es:[edi]
00401634 stos byte ptr es:[edi]
00401635 mov ecx, 18
0040163A xor eax, eax
0040163C lea edi, [esp+4D]
00401640 mov byte ptr [esp+4C], 0
00401645 rep stos dword ptr es:[edi]
00401647 stos word ptr es:[edi]
00401649 stos byte ptr es:[edi]
0040164A xor eax, eax
0040164C push 10 ; 0x10
0040164E mov [esp+19], eax
00401652 push 320 ; 0x320
00401657 mov [esp+21], eax
0040165B mov byte ptr [esp+1C], 0
00401660 mov [esp+25], eax
00401664 mov [esp+29], ax
00401669 mov [esp+2B], al
0040166D call <mirsys>
00401672 push 0
00401674 mov dword ptr [eax+234], 10
0040167E call <_mirvar>
00401683 push 0
00401685 mov [esp+38], eax
00401689 call <_mirvar>
0040168E push 0
00401690 mov ebp, eax
00401692 call <_mirvar>
00401697 push 0
00401699 mov [esp+28], eax
0040169D call <_mirvar>
004016A2 push 0
004016A4 mov ebx, eax
004016A6 call <_mirvar>
004016AB mov esi, [esp+134]
004016B2 mov edi, [<&USER32.GetDlgItemTextA>] ; USER32.GetDlgItemTextA
004016B8 add esp, 1C
004016BB lea ecx, [esp+B0]
004016C2 mov [esp+24], eax
004016C6 push 65 ; /Count = 65 (101.)
004016C8 push ecx ; |Buffer
004016C9 push 3E8 ; |ControlID = 3E8 (1000.)
004016CE push esi ; |hWnd
004016CF call edi ; \GetDlgItemTextA
004016D1 cmp eax, 2 ; name的长度不小于2
004016D4 jnb short 004016E3
004016D6 pop edi
004016D7 pop esi
004016D8 pop ebp
004016D9 xor eax, eax
004016DB pop ebx
004016DC add esp, 104
004016E2 retn
004016E3 lea edx, [esp+4C]
004016E7 push 65
004016E9 push edx
004016EA push 3E9
004016EF push esi
004016F0 call edi
004016F2 test eax, eax ; serial不能为空
004016F4 jnz short 00401701
004016F6 pop edi
004016F7 pop esi
004016F8 pop ebp
004016F9 pop ebx
004016FA add esp, 104
00401700 retn
00401701 mov al, [esp+4C]
00401705 test al, al
00401707 je short 0040174C
00401709 lea esi, [esp+4C] ; sn
0040170D /cmp dword ptr [40DF90], 1 ; 这个循环检查sn是否是十六进制字符
00401714 |jle short 0040172A
00401716 |xor eax, eax
00401718 |push 80
0040171D |mov al, [esi]
0040171F |push eax
00401720 |call <__isctype>
00401725 |add esp, 8
00401728 |jmp short 0040173C
0040172A |mov edx, [40DD84] ; CrackMe_.0040DD8E
00401730 |xor ecx, ecx
00401732 |mov cl, [esi]
00401734 |mov al, [edx+ecx*2]
00401737 |and eax, 80
0040173C |test eax, eax
0040173E |je 004017E9
00401744 |mov al, [esi+1]
00401747 |inc esi
00401748 |test al, al
0040174A \jnz short 0040170D
0040174C lea eax, [esp+2C]
00401750 push eax
00401751 call <Hash_Init>
00401756 lea edi, [esp+B4] ; name
0040175D or ecx, FFFFFFFF
00401760 xor eax, eax
00401762 lea edx, [esp+30]
00401766 repne scas byte ptr es:[edi]
00401768 not ecx
0040176A dec ecx
0040176B push ecx ; name长度
0040176C lea ecx, [esp+B8]
00401773 push ecx ; name
00401774 push edx ; hash_ctx
00401775 call <Hash_Update>
0040177A lea eax, [esp+3C]
0040177E lea ecx, [esp+24]
00401782 push eax
00401783 push ecx
00401784 call <Hash_Final>
00401789 mov edx, [esp+28]
0040178D lea eax, [esp+2C]
00401791 push edx ; h
00401792 push eax ; Hash(name)
00401793 push 0A ; 10位
00401795 call <bytes_to_big> ; h=抓取Hash(name)的前10个字节
0040179A mov edi, [esp+4C]
0040179E lea ecx, [esp+70]
004017A2 push ecx ; sn
004017A3 push edi
004017A4 call <_cinstr>
004017A9 push 0040D0F0 ; ASCII "53AA4A5D47684616BD856ED3DB0F3899CDE3A052CE2B3011"
004017AE push ebp ; n
004017AF call <_cinstr>
004017B4 push 0040D0D4 ; ASCII "A5DA242D7DD4EACD19819D83"
004017B9 push ebx ; q
004017BA call <_cinstr>
004017BF mov esi, [esp+60]
004017C3 push esi ; m
004017C4 push ebp ; n
004017C5 push ebp ; n
004017C6 push edi ; sn
004017C7 call <_powmod> ; m=sn^n (mod n)
004017CC add esp, 4C
004017CF push ebx ; q
004017D0 push ebx ; q
004017D1 push esi ; m
004017D2 call <_divide> ; m=m (mod q)
004017D7 mov edx, [esp+1C]
004017DB push esi ; m
004017DC push edx ; h
004017DD call <_compare> ; m和h若相等则注册成功,否则失败
004017E2 add esp, 14
004017E5 test eax, eax
004017E7 je short 004017F6
验证过程就是算法的第4步。注册机就更简单了,详见附件。
给出两组可用的注册码:
name:HorstStein
serial:5BD25220B70AE77F47DDF01D
name:pediy
serial:5ACE4953EB892534B14D4D97
--------------------------------------------------------------------------------
【经验总结】
这个CrackMe使用了障眼法,呵呵。再一就是这个hash函数比较有意思。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪论坛, 转载请注明作者并保持文章的完整, 谢谢!
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
上传的附件: