这个crackme 是tkm 2004年的strainer,用ECC保护的。虽然ECC大家玩得比较熟了,不过这个东东的保护方法还是有点意思。
用PEiD查壳并脱壳,unpack不是目的,算法才是关键。unpack后载入ida,用miracl的sig,或
http://www.secretashell.com/cryptocrk/tutorials/miracl.calls.zip这里的方法识别miracl库函数,检查序列号的流程一目了然。
1.获取name,sn1,sn2
代码:
Un_FSG__:0040194C loc_40194C:
Un_FSG__:0040194C push 50h
Un_FSG__:0040194E push offset name
Un_FSG__:00401953 push 2
Un_FSG__:00401955 push edi
Un_FSG__:00401956 call GetDlgItemText ; name>=4
Un_FSG__:0040195B mov esi, eax
Un_FSG__:0040195D push 50h
Un_FSG__:0040195F push offset sn1
Un_FSG__:00401964 push 3
Un_FSG__:00401966 push edi
Un_FSG__:00401967 call GetDlgItemText ; sn1>=4
Un_FSG__:0040196C mov ebx, eax
Un_FSG__:0040196E push 50h
Un_FSG__:00401970 push offset sn2
Un_FSG__:00401975 push 4
Un_FSG__:00401977 push edi
Un_FSG__:00401978 call GetDlgItemText ; sn2>=1
2.检查序列号
1)椭圆曲线E(a,b,p)、点(pt1,pt2,pt3,pt4,pt5)初始化
代码:
Un_FSG__:0040149C call epoint_init
Un_FSG__:004014A1 mov edi, eax
Un_FSG__:004014A3 mov [esp+1F8h+var_1F8], 0
Un_FSG__:004014AA call _mirvar
Un_FSG__:004014AF mov [ebp+pt2_x], eax
Un_FSG__:004014B5 call epoint_init
Un_FSG__:004014BA mov [esp+1F8h+var_1F8], 0
Un_FSG__:004014C1 mov [ebp+pt2], eax
Un_FSG__:004014C7 call _mirvar
Un_FSG__:004014CC mov [ebp+big_t], eax
Un_FSG__:004014D2 call epoint_init
Un_FSG__:004014D7 mov [ebp+pt3], eax
Un_FSG__:004014DD call epoint_init
Un_FSG__:004014E2 mov [ebp+pt4], eax
Un_FSG__:004014E8 call epoint_init
Un_FSG__:004014ED mov dword ptr [esi+220h], 10h
Un_FSG__:004014F7 mov [ebp+pt5], eax
...
Un_FSG__:00401512 mov ebx, [ebp+a]
Un_FSG__:00401518 push offset a416d656e657369 ; "416D656E65736961"
Un_FSG__:0040151D push ebx
Un_FSG__:0040151E call _cinstr
Un_FSG__:00401523 pop eax
Un_FSG__:00401524 pop edx
Un_FSG__:00401525 mov eax, [ebp+b]
Un_FSG__:0040152B push offset a1b35b7093fee5a ; "1B35B7093FEE5AE601A"
Un_FSG__:00401530 push eax
Un_FSG__:00401531 call _cinstr
Un_FSG__:00401536 pop ebx
Un_FSG__:00401537 pop esi
Un_FSG__:00401538 mov esi, [ebp+p]
Un_FSG__:0040153E push offset aFffffffdffffff ; "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF"
Un_FSG__:00401543 push esi
Un_FSG__:00401544 call _cinstr
Un_FSG__:00401549 pop eax
Un_FSG__:0040154A pop edx
Un_FSG__:0040154B mov edx, [ebp+pt1_x]
Un_FSG__:00401551 push offset a71263a72c2fdfb ; "71263A72C2FDFB8FE851182B408210A4"
Un_FSG__:00401556 push edx
Un_FSG__:00401557 call _cinstr
Un_FSG__:0040155C mov eax, [ebp+pt2_x]
Un_FSG__:00401562 pop ecx
Un_FSG__:00401563 pop ebx
Un_FSG__:00401564 push offset a2c052124bdd94e ; "2C052124BDD94E5645E99B01DCECA28D"
Un_FSG__:00401569 push eax
Un_FSG__:0040156A call _cinstr
Un_FSG__:0040156F mov eax, [ebp+p]
Un_FSG__:00401575 push 1
Un_FSG__:00401577 push eax
Un_FSG__:00401578 mov eax, [ebp+b]
Un_FSG__:0040157E push eax
Un_FSG__:0040157F mov eax, [ebp+a]
Un_FSG__:00401585 push eax
Un_FSG__:00401586 call _ecurve_init
Un_FSG__:0040158B mov eax, [ebp+pt1_x]
Un_FSG__:00401591 add esp, 20h
Un_FSG__:00401594 push edi ; pt1
Un_FSG__:00401595 push 0
Un_FSG__:00401597 push eax
Un_FSG__:00401598 mov eax, [ebp+pt1_x]
Un_FSG__:0040159E push eax
Un_FSG__:0040159F call _epoint_set
Un_FSG__:004015A4 mov ecx, [ebp+pt2_x]
Un_FSG__:004015AA mov eax, [ebp+pt2]
Un_FSG__:004015B0 mov ebx, [ebp+pt2_x]
Un_FSG__:004015B6 push eax
Un_FSG__:004015B7 push 1
Un_FSG__:004015B9 push ebx
Un_FSG__:004015BA push ecx
Un_FSG__:004015BB call _epoint_set
其中E的参数为:
a:416D656E65736961
b:1B35B7093FEE5AE601A
p:FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF
pt1的x坐标为:71263A72C2FDFB8FE851182B408210A4
pt2的x坐标为:2C052124BDD94E5645E99B01DCECA28D
2)sn1,sn2转变为大数,并变形
代码:
Un_FSG__:004015C0 mov esi, [ebp+big_sn1]
Un_FSG__:004015C6 add esp, 18h
Un_FSG__:004015C9 movsx ebx, ds:Serial_sign
Un_FSG__:004015D0 push offset sn1
Un_FSG__:004015D5 sub ebx, 30h
Un_FSG__:004015D8 push esi
Un_FSG__:004015D9 lea esi, [ebp+var_1A8]
Un_FSG__:004015DF call _cinstr
Un_FSG__:004015E4 pop eax
Un_FSG__:004015E5 pop edx
Un_FSG__:004015E6 mov eax, [ebp+big_sn2]
Un_FSG__:004015EC push offset sn2
Un_FSG__:004015F1 push eax
Un_FSG__:004015F2 call _cinstr
其中sn1的第一个byte是正负标志位,剩下的部分转化为大数
代码:
Un_FSG__:004015F7 mov eax, [ebp+big_t]
Un_FSG__:004015FD push eax
Un_FSG__:004015FE mov eax, [ebp+p]
Un_FSG__:00401604 push eax
Un_FSG__:00401605 mov eax, [ebp+big_sn1]
Un_FSG__:0040160B push 1
Un_FSG__:0040160D push eax
Un_FSG__:0040160E call _powmod
Un_FSG__:00401613 mov eax, [ebp+big_t]
Un_FSG__:00401619 add esp, 20h
Un_FSG__:0040161C mov edx, [ebp+pt3]
Un_FSG__:00401622 push edx
Un_FSG__:00401623 push ebx
Un_FSG__:00401624 xor ebx, ebx
Un_FSG__:00401626 push eax
Un_FSG__:00401627 mov eax, [ebp+big_t]
Un_FSG__:0040162D push eax
Un_FSG__:0040162E call _epoint_set
pt3的x坐标为big_sn1%p
3)计算name的sha值,并变形
代码:
Un_FSG__:00401636 call _shs_init
Un_FSG__:0040163B mov al, ds:name
Un_FSG__:00401640 add esp, 10h
Un_FSG__:00401643 test al, al
Un_FSG__:00401645 jz short loc_401661
Un_FSG__:00401647
Un_FSG__:00401647 loc_401647: ; CODE XREF: _check+27Fj
Un_FSG__:00401647 movsx ecx, al
Un_FSG__:0040164A push edx
Un_FSG__:0040164B inc ebx
Un_FSG__:0040164C push edx
Un_FSG__:0040164D push ecx
Un_FSG__:0040164E push esi
Un_FSG__:0040164F call _shs_process
Un_FSG__:00401654 mov al, ds:name[ebx]
Un_FSG__:0040165A add esp, 10h
Un_FSG__:0040165D test al, al
Un_FSG__:0040165F jnz short loc_401647
Un_FSG__:00401661
Un_FSG__:00401661 loc_401661: ; CODE XREF: _check+265j
Un_FSG__:00401661 push ebx
Un_FSG__:00401662 push ebx
Un_FSG__:00401663 lea ebx, [ebp+var_38]
Un_FSG__:00401666 push ebx
Un_FSG__:00401667 push esi
Un_FSG__:00401668 call _shs_hash
Un_FSG__:0040166D mov edx, [ebp+big_hName]
Un_FSG__:00401673 add esp, 0Ch
Un_FSG__:00401676 push edx
Un_FSG__:00401677 push ebx
Un_FSG__:00401678 push 14h
Un_FSG__:0040167A call _bytes_to_big
Un_FSG__:0040167F mov eax, [ebp+big_hName]
Un_FSG__:00401685 push eax
Un_FSG__:00401686 mov eax, [ebp+p2] ;FFFFFFFE000000006FAFED9C3353F08D
Un_FSG__:0040168C push eax
Un_FSG__:0040168D mov eax, [ebp+big_hName]
Un_FSG__:00401693 push 3
Un_FSG__:00401695 push eax
Un_FSG__:00401696 call _powmod
big_hName=sha(name)^3%p2
p2被初始化为FFFFFFFE000000006FAFED9C3353F08D
4)计算中间值
代码:
Un_FSG__:0040169B mov eax, [ebp+pt4]
Un_FSG__:004016A1 add esp, 1Ch
Un_FSG__:004016A4 push eax
Un_FSG__:004016A5 mov eax, [ebp+pt3]
Un_FSG__:004016AB push eax
Un_FSG__:004016AC mov eax, [ebp+big_sn2]
Un_FSG__:004016B2 push eax
Un_FSG__:004016B3 call _ecurve_mult ; pt4=pt3*big_sn2
Un_FSG__:004016B8 mov eax, [ebp+big_hName]
Un_FSG__:004016BE add esp, 0Ch
Un_FSG__:004016C1 push edi
Un_FSG__:004016C2 push edi
Un_FSG__:004016C3 push eax
Un_FSG__:004016C4 call _ecurve_mult ; pt1=pt1*big_hName
Un_FSG__:004016C9 mov ebx, [ebp+big_sn1]
Un_FSG__:004016CF add esp, 0Ch
Un_FSG__:004016D2 mov ecx, [ebp+pt5]
Un_FSG__:004016D8 mov esi, [ebp+pt2]
Un_FSG__:004016DE push ecx
Un_FSG__:004016DF push esi
Un_FSG__:004016E0 push ebx
Un_FSG__:004016E1 call _ecurve_mult ; pt5=pt2*big_sn1
Un_FSG__:004016E6 pop eax
Un_FSG__:004016E7 pop edx
Un_FSG__:004016E8 mov edx, [ebp+pt5]
Un_FSG__:004016EE push edx
Un_FSG__:004016EF push edi
Un_FSG__:004016F0 call _ecurve_add ; pt5=pt5+pt1
Un_FSG__:004016F0 ; pt5=pt1*big_hName+
Un_FSG__:004016F0 ; pt2*big_sn1
pt4=pt3*big_sn2
pt5=pt5+pt1
=pt1*big_hName+pt2*big_sn1
5)比较
通过两处进行比较
代码:
Un_FSG__:004016F5 mov eax, [ebp+pt4]
Un_FSG__:004016FB pop ecx
Un_FSG__:004016FC pop ebx
Un_FSG__:004016FD push eax
Un_FSG__:004016FE mov eax, [ebp+pt5]
Un_FSG__:00401704 push eax
Un_FSG__:00401705 call _epoint_comp ; pt4=t5
...
Un_FSG__:004017F5 mov eax, [ebp+pt5]
Un_FSG__:004017FB push edi
Un_FSG__:004017FC push eax
Un_FSG__:004017FD call _epoint_comp ;pt5!=pt1
如果pt4=pt5且pt5!=pt1则通过
3.Keygen
最终只要pt3*big_sn2=pt1*big_hName+pt2*big_sn1即可通过检查
其中pt3的x坐标为big_sn1%p
big_hName是name的hash值变形得来,是不可逆的,同样pt1,pt2是给定的也做不了文章,能下手的就是pt3,sn1,sn2这几部分
不妨试试,令pt3=pt1+pt2,big_sn2=big_hName
那么方程被简化为pt2*big_hName=pt2*big_sn1
椭圆曲线作为一个阶数为n的有限群,它上面任意一点满足pt*n=indefinite(因为元素的阶是群的阶的因子)。如果椭圆曲线不好理解,可以拿模质数的乘法群来类比。indefinite相当于1。在{1,2,3,4,5,6}这几个数构成的mod 7群里,群的阶(元素个数)为6,任意一个数的6次方除以7均余1也就是那个单位元。
所以只要big_sn1%n=big_hName即可
那么最终我们得到了一组同余方程
big_sn1=pt3_x mod p
big_sn1=big_hName mod n
得到sn1
利用big_sn2=big_hName
得到sn2
当时在keygen的时候我对miracl还不熟,我自己手工解这个同余方程,大家可以用miracl实现一个更好的keygen下面是keygen的链接
keygen