【文章标题】: HappyTown的第26个CrackMe分析
【文章作者】: HorstStein
【作者邮箱】: [email]horststein@hotmail.com[/email]
【软件名称】: HappyTown's CrackMe_0026
【下载地址】: http://bbs.pediy.com/showthread.php?s=&threadid=33848
【加壳方式】: 没有
【保护方式】: 序列号
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
首先请阅读The Elliptic Curve Digital Signature Algorithm (ECDSA)第26页,下面的参数均以此为准。
HappyTown的CrackMe_0026用到了ECDSA和SHA1,使用了miracl库。
00401130 /$>sub esp, 390
00401136 |.>push ebx
00401137 |.>push ebp
00401138 |.>push esi
00401139 |.>push edi
0040113A |.>mov ecx, 18
0040113F |.>xor eax, eax
00401141 |.>lea edi, [esp+1D5]
00401148 |.>mov byte ptr [esp+1D4], 0
00401150 |.>rep stos dword ptr es:[edi]
00401152 |.>stos word ptr es:[edi]
00401154 |.>push 10 ; 0x10
00401156 |.>push 320 ; 0x320
0040115B |.>stos byte ptr es:[edi]
0040115C |.>call 00401D40 ; mirsys
00401161 |.>mov ebp, eax
00401163 |.>mov ecx, 18
00401168 |.>xor eax, eax
0040116A |.>lea edi, [esp+115]
00401171 |.>mov byte ptr [esp+114], 0
00401179 |.>mov byte ptr [esp+4C], 0
0040117E |.>rep stos dword ptr es:[edi]
00401180 |.>stos word ptr es:[edi]
00401182 |.>stos byte ptr es:[edi]
00401183 |.>mov ecx, 18
00401188 |.>xor eax, eax
0040118A |.>lea edi, [esp+4D]
0040118E |.>mov byte ptr [esp+B0], 0
00401196 |.>rep stos dword ptr es:[edi]
00401198 |.>stos word ptr es:[edi]
0040119A |.>stos byte ptr es:[edi]
0040119B |.>mov ecx, 18
004011A0 |.>xor eax, eax
004011A2 |.>lea edi, [esp+B1]
004011A9 |.>mov byte ptr [esp+178], 0
004011B1 |.>rep stos dword ptr es:[edi]
004011B3 |.>stos word ptr es:[edi]
004011B5 |.>stos byte ptr es:[edi]
004011B6 |.>mov ecx, 18
004011BB |.>xor eax, eax
004011BD |.>lea edi, [esp+179]
004011C4 |.>mov esi, [esp+3AC]
004011CB |.>rep stos dword ptr es:[edi]
004011CD |.>stos word ptr es:[edi]
004011CF |.>mov ebx, [<&USER32.GetDlgItemTextA>] ; USER32.GetDlgItemTextA
004011D5 |.>add esp, 8
004011D8 |.>stos byte ptr es:[edi]
004011D9 |.>lea eax, [esp+10C]
004011E0 |.>push 65 ; /Count = 65 (101.)
004011E2 |.>push eax ; |Buffer
004011E3 |.>push 3E8 ; |ControlID = 3E8 (1000.)
004011E8 |.>push esi ; |hWnd
004011E9 |.>call ebx ; \GetDlgItemTextA
004011EB |.>lea edi, [esp+10C] ; name
004011F2 |.>or ecx, FFFFFFFF
004011F5 |.>xor eax, eax
004011F7 |.>repne scas byte ptr es:[edi]
004011F9 |.>not ecx
004011FB |.>dec ecx
004011FC |.>cmp ecx, 3
004011FF |.>jb 00401680
00401205 |.>lea edi, [esp+10C]
0040120C |.>or ecx, FFFFFFFF
0040120F |.>repne scas byte ptr es:[edi]
00401211 |.>not ecx
00401213 |.>dec ecx
00401214 |.>cmp ecx, 18
00401217 |.>ja 00401680
0040121D |.>lea ecx, [esp+44]
00401221 |.>push 65 ; /Count = 65 (101.)
00401223 |.>push ecx ; |Buffer
00401224 |.>push 3E9 ; |ControlID = 3E9 (1001.)
00401229 |.>push esi ; |hWnd
0040122A |.>call ebx ; \GetDlgItemTextA
0040122C |.>lea edx, [esp+44] ; sn
00401230 |.>push 2D
00401232 |.>push edx
00401233 |.>call 0040A130
00401238 |.>add esp, 8
0040123B |.>test eax, eax
0040123D |.>je 00401680
00401243 |.>mov cl, [esp+44]
00401247 |.>cmp cl, 2D
0040124A |.>je short 0040125F
0040124C |.>xor eax, eax
0040124E |>>/mov [esp+eax+A8], cl
00401255 |.>|mov cl, [esp+eax+45]
00401259 |.>|inc eax
0040125A |.>|cmp cl, 2D
0040125D |.>\jnz short 0040124E
0040125F |>>lea eax, [esp+44]
00401263 |.>push 2D
00401265 |.>push eax
00401266 |.>call 0040A130 ; 检查sn中是否包含"-"
0040126B |.>lea ecx, [esp+4C]
0040126F |.>add esp, 8
00401272 |.>sub eax, ecx
00401274 |.>mov cl, [esp+eax+44]
00401278 |.>test cl, cl
0040127A |.>lea eax, [esp+eax+44]
0040127E |.>je short 00401295
00401280 |.>lea ecx, [esp+170]
00401287 |>>/mov dl, [eax+1]
0040128A |.>|mov [ecx], dl
0040128C |.>|mov dl, [eax+1]
0040128F |.>|inc ecx
00401290 |.>|inc eax
00401291 |.>|test dl, dl
00401293 |.>\jnz short 00401287
00401295 |>>lea edi, [esp+A8]
0040129C |.>or ecx, FFFFFFFF
0040129F |.>xor eax, eax
004012A1 |.>repne scas byte ptr es:[edi]
004012A3 |.>not ecx
004012A5 |.>dec ecx
004012A6 |.>je 00401680
004012AC |.>lea edi, [esp+170]
004012B3 |.>or ecx, FFFFFFFF
004012B6 |.>repne scas byte ptr es:[edi]
004012B8 |.>not ecx
004012BA |.>dec ecx
004012BB |.>je 00401680
004012C1 |.>mov al, [esp+A8]
004012C8 |.>test al, al
004012CA |.>je short 00401317
004012CC |.>lea esi, [esp+A8] ; sn_r:即'-'前面的部分
004012D3 |>>/mov eax, [410F80] ; /检查sn_r是否为16进制数
004012D8 |.>|mov edi, 1
004012DD |.>|cmp eax, edi
004012DF |.>|jle short 004012F4
004012E1 |.>|movsx eax, byte ptr [esi]
004012E4 |.>|push 80
004012E9 |.>|push eax
004012EA |.>|call 0040A0A0
004012EF |.>|add esp, 8
004012F2 |.>|jmp short 00401305
004012F4 |>>|movsx ecx, byte ptr [esi]
004012F7 |.>|mov edx, [410D74] ; CrackMe_.00410D7E
004012FD |.>|mov al, [edx+ecx*2]
00401300 |.>|and eax, 80
00401305 |>>|test eax, eax
00401307 |.>|je 00401680
0040130D |.>|mov al, [esi+1]
00401310 |.>|inc esi
00401311 |.>|test al, al
00401313 |.>\jnz short 004012D3 ; \
00401315 |.>jmp short 0040131C
00401317 |>>mov edi, 1
0040131C |>>mov al, [esp+170]
00401323 |.>test al, al
00401325 |.>je short 0040136A
00401327 |.>lea esi, [esp+170] ; sn_s:即'-'后面的部分
0040132E |>>/cmp [410F80], edi ; /检查sn_s是否为16进制数
00401334 |.>|jle short 00401349
00401336 |.>|movsx eax, byte ptr [esi]
00401339 |.>|push 80
0040133E |.>|push eax
0040133F |.>|call 0040A0A0
00401344 |.>|add esp, 8
00401347 |.>|jmp short 0040135A
00401349 |>>|movsx ecx, byte ptr [esi]
0040134C |.>|mov edx, [410D74] ; CrackMe_.00410D7E
00401352 |.>|mov al, [edx+ecx*2]
00401355 |.>|and eax, 80
0040135A |>>|test eax, eax
0040135C |.>|je 00401680
00401362 |.>|mov al, [esi+1]
00401365 |.>|inc esi
00401366 |.>|test al, al
00401368 |.>\jnz short 0040132E ; \
0040136A |>>push 2982
0040136F |.>mov dword ptr [ebp+234], 10 ; mip->IOBASE = 16
00401379 |.>call 00401B20 ; A=mirvar(0x2982)
0040137E |.>push 3408
00401383 |.>mov [esp+48], eax
00401387 |.>call 00401B20 ; B=mirvar(0x3408)
0040138C |.>push 0
0040138E |.>mov [esp+48], eax
00401392 |.>call 00401B20
00401397 |.>push 0
00401399 |.>mov [esp+44], eax
0040139D |.>call 00401B20
004013A2 |.>push 0
004013A4 |.>mov esi, eax
004013A6 |.>call 00401B20
004013AB |.>push 0
004013AD |.>mov ebp, eax
004013AF |.>call 00401B20
004013B4 |.>push 0
004013B6 |.>mov edi, eax
004013B8 |.>call 00401B20
004013BD |.>push 0
004013BF |.>mov [esp+50], eax
004013C3 |.>call 00401B20
004013C8 |.>push 0
004013CA |.>mov ebx, eax
004013CC |.>call 00401B20
004013D1 |.>push 0
004013D3 |.>mov [esp+50], eax
004013D7 |.>call 00401B20
004013DC |.>push 0
004013DE |.>mov [esp+4C], eax
004013E2 |.>call 00401B20
004013E7 |.>push 0
004013E9 |.>mov [esp+54], eax
004013ED |.>call 00401B20
004013F2 |.>push 0
004013F4 |.>mov [esp+4C], eax
004013F8 |.>call 00401B20
004013FD |.>mov [esp+50], eax
00401401 |.>mov eax, [esp+68]
00401405 |.>push 00410104 ; ASCII "AEBF94CEE3E707"
0040140A |.>push eax ; q:这个是椭圆曲线的特征
0040140B |.>call 004076D0 ; cinstr(q, "AEBF94CEE3E707")
00401410 |.>push 004100F4 ; ASCII "AEBF94D5C6AA71"
00401415 |.>push esi ; n:阶
00401416 |.>call 004076D0 ; cinstr(n, "AEBF94D5C6AA71")
0040141B |.>mov ecx, [esp+5C]
0040141F |.>add esp, 44
00401422 |.>push 004100E4 ; ASCII "7A3E808599A525"
00401427 |.>push ecx ; xG:基点G的x坐标
00401428 |.>call 004076D0 ; cinstr(xG,"7A3E808599A525")
0040142D |.>mov edx, [esp+24]
00401431 |.>push 004100D4 ; ASCII "9F70A02013BC9B"
00401436 |.>push edx ; xQ:Q点的x坐标
00401437 |.>call 004076D0 ; cinstr(xQ,"9F70A02013BC9B")
0040143C |.>mov eax, [esp+44]
00401440 |.>mov ecx, [esp+4C]
00401444 |.>mov edx, [esp+50]
00401448 |.>push 0 ; MR_PROJECTIVE
0040144A |.>push eax ; q
0040144B |.>push ecx ; B
0040144C |.>push edx ; A
0040144D |.>call 004032B0 ; ecurve_init(A,B,q,MR_PROJECTIVE),给定椭圆曲线y^2=x^3+Ax+B (mod q)
00401452 |.>call 00403070 ; G=epoint_init() 初始化G点
00401457 |.>mov [esp+4C], eax
0040145B |.>call 00403070 ; X=epoint_init()
00401460 |.>mov [esp+30], eax
00401464 |.>call 00403070 ; Q=epoint_init()
00401469 |.>mov [esp+34], eax
0040146D |.>mov eax, [esp+4C]
00401471 |.>push eax ; G
00401472 |.>mov eax, [esp+3C]
00401476 |.>push 0
00401478 |.>push eax ; xG
00401479 |.>push eax ; xG
0040147A |.>call 00403520 ; epoint_set(xG,xG,0,G)
0040147F |.>mov ecx, [esp+44]
00401483 |.>mov eax, [esp+4C]
00401487 |.>push ecx ; Q
00401488 |.>push 0
0040148A |.>push eax ; xQ
0040148B |.>push eax ; xQ
0040148C |.>call 00403520 ; epoint_set(xQ,xQ,0,Q)
00401491 |.>add esp, 40
00401494 |.>lea edx, [esp+A8]
0040149B |.>push edx ; sn_r
0040149C |.>push ebp ; r
0040149D |.>call 004076D0 ; cinstr(r, sn_r)
004014A2 |.>lea eax, [esp+178]
004014A9 |.>push eax ; sn_s
004014AA |.>push edi ; s
004014AB |.>call 004076D0 ; cinstr(s, sn_s)
004014B0 |.>push esi ; n
004014B1 |.>push ebp ; r
004014B2 |.>call 00402A20 ; compare(r, n),即r是否小于n
004014B7 |.>add esp, 18
004014BA |.>cmp eax, -1
004014BD |.>jnz 00401680
004014C3 |.>push esi ; n
004014C4 |.>push edi ; s
004014C5 |.>call 00402A20 ; compare(s, n),即s是否小于n
004014CA |.>add esp, 8
004014CD |.>cmp eax, -1
004014D0 |.>jnz 00401680
004014D6 |.>lea ecx, [esp+238]
004014DD |.>push ecx ; 下面是SHA1(name)
004014DE |.>call 004073A0 ; SHA1_Init,跟进去可以看见那5个常数
004014E3 |.>mov al, [esp+110]
004014EA |.>add esp, 4
004014ED |.>test al, al
004014EF |.>je short 0040151F
004014F1 |.>lea edx, [esp+10C]
004014F8 |.>mov [esp+38], edx
004014FC |>>/movsx eax, al
004014FF |.>|lea ecx, [esp+238]
00401506 |.>|push eax
00401507 |.>|push ecx
00401508 |.>|call 004073E0 ; SHA1_Update
0040150D |.>|mov eax, [esp+40]
00401511 |.>|add esp, 8
00401514 |.>|inc eax
00401515 |.>|mov [esp+38], eax
00401519 |.>|mov al, [eax]
0040151B |.>|test al, al
0040151D |.>\jnz short 004014FC
0040151F |>>lea edx, [esp+1D4]
00401526 |.>lea eax, [esp+238]
0040152D |.>push edx
0040152E |.>push eax
0040152F |.>call 00407630 ; SHA1_Final
00401534 |.>mov ecx, [esp+38]
00401538 |.>lea edx, [esp+1DC]
0040153F |.>push ecx ; e
00401540 |.>push edx ; SHA1(name)
00401541 |.>push 14 ; 取20个字节
00401543 |.>call 00407220 ; bytes_to_big
00401548 |.>push edi ; s
00401549 |.>push edi ; s
0040154A |.>push edi ; s
0040154B |.>push esi ; n
0040154C |.>push edi ; s
0040154D |.>call 004061B0 ; xgcd:s = s^-1 (mod n)
00401552 |.>push ebx ; w
00401553 |.>push edi ; s
00401554 |.>call 004027A0 ; copy(s,w):w = s
00401559 |.>mov eax, [esp+58]
0040155D |.>mov ecx, [esp+60]
00401561 |.>push eax ; u1
00401562 |.>push esi ; n
00401563 |.>push esi ; n
00401564 |.>push ebx ; w
00401565 |.>push ebx ; w
00401566 |.>push ecx ; e
00401567 |.>call 004060A0 ; mad:u1 = e*w (mod n)
0040156C |.>mov edx, [esp+68]
00401570 |.>add esp, 48
00401573 |.>push edx ; u2
00401574 |.>push esi ; n
00401575 |.>push esi ; n
00401576 |.>push ebx ; w
00401577 |.>push ebx ; w
00401578 |.>push ebp ; r
00401579 |.>call 004060A0 ; mad:u2 = r*w (mod n)
0040157E |.>mov eax, [esp+28]
00401582 |.>mov ecx, [esp+2C]
00401586 |.>mov edx, [esp+38]
0040158A |.>push eax ; X
0040158B |.>mov eax, [esp+48]
0040158F |.>push ecx ; Q
00401590 |.>mov ecx, [esp+48]
00401594 |.>push edx ; u2
00401595 |.>push eax ; G
00401596 |.>push ecx ; u1
00401597 |.>call 00404BF0 ; ecurve_mult2: X=u1*G+u2*Q
0040159C |.>mov edx, [esp+3C]
004015A0 |.>push edx ; X
004015A1 |.>call 00403050 ; point_at_infinity:测试X是否为无穷远点
004015A6 |.>add esp, 30
004015A9 |.>cmp eax, 1
004015AC |.>je 00401680
004015B2 |.>mov eax, [esp+24]
004015B6 |.>push eax ; xX(X点的x坐标)
004015B7 |.>push eax ; xX
004015B8 |.>mov eax, [esp+18]
004015BC |.>push eax ; X
004015BD |.>call 004036E0 ; epoint_get
004015C2 |.>mov ecx, [esp+30]
004015C6 |.>push ecx ; xX
004015C7 |.>push ebp ; r
004015C8 |.>call 00402A20 ; compare,r和xX是否相等?也就是在这里判断注册成功与否
004015CD |.>add esp, 14
004015D0 |.>test eax, eax
004015D2 |.>jnz 00401680
004015D8 |.>mov edx, [esp+40]
004015DC |.>push edx
004015DD |.>call 004024F0 ; mirkill
004015E2 |.>mov eax, [esp+40]
004015E6 |.>push eax
004015E7 |.>call 004024F0
004015EC |.>mov ecx, [esp+3C]
004015F0 |.>push ecx
004015F1 |.>call 004024F0
004015F6 |.>push esi
004015F7 |.>call 004024F0
004015FC |.>push ebx
004015FD |.>call 004024F0
00401602 |.>mov edx, [esp+3C]
00401606 |.>push edx
00401607 |.>call 004024F0
0040160C |.>mov eax, [esp+38]
00401610 |.>push eax
00401611 |.>call 004024F0
00401616 |.>push ebp
00401617 |.>call 004024F0
0040161C |.>push edi
0040161D |.>call 004024F0
00401622 |.>mov ecx, [esp+54]
00401626 |.>push ecx
00401627 |.>call 004024F0
0040162C |.>mov edx, [esp+40]
00401630 |.>push edx
00401631 |.>call 004024F0
00401636 |.>mov eax, [esp+48]
0040163A |.>push eax
0040163B |.>call 004024F0
00401640 |.>mov ecx, [esp+54]
00401644 |.>push ecx
00401645 |.>call 004024F0
0040164A |.>mov edx, [esp+60]
0040164E |.>push edx
0040164F |.>call 00403280 ; epoint_free
00401654 |.>mov eax, [esp+4C]
00401658 |.>push eax
00401659 |.>call 00403280
0040165E |.>mov ecx, [esp+4C]
00401662 |.>push ecx
00401663 |.>call 00403280
00401668 |.>add esp, 40
0040166B |.>call 00402510 ; mirexit
显然,这是一个标准的ECDSA验证过程,那么注册机按ECDSA的签名过程写即可。
私钥d经计算为:9D3F1E3CDDA5E5
关键代码如下:
int GenSn()
{
int i;
DWORD temp;
unsigned char name[100] = {0};
unsigned char hash[20] = {0}; //SHA1(name)
unsigned char sn[100] = {0};
unsigned char sn_r[100] = {0};
unsigned char sn_s[100] = {0};
sha sh;
big a,b,q,n,d,r,k,s,e,xG,xX,w,u1,u2; // 定义MIRACL的大数
//椭圆曲线上的2个点
epoint * X; //临时点
epoint * G; //基点
miracl *mip=mirsys(0x320,0x10);
mip->IOBASE = 16;
a = mirvar(0x2982);
b = mirvar(0x3408);
q = mirvar(0); //椭圆曲线的特征参数
n = mirvar(0); //G的阶
d = mirvar(0); //私钥
r = mirvar(0);
k = mirvar(0);
s = mirvar(0);
e = mirvar(0); //hash(name)
xG = mirvar(0); //基点G的x坐标
xX = mirvar(0); //临时点X的x坐标
w = mirvar(0);
u1 = mirvar(0);
u2 = mirvar(0);
again: //若签名r或(和)s为0,则重新生成签名
//initialize parameters of ecurve and set ecurve
cinstr(q,"AEBF94CEE3E707");
cinstr(n,"AEBF94D5C6AA71");
cinstr(d,"9D3F1E3CDDA5E5");
cinstr(xG,"7A3E808599A525");
ecurve_init(a,b,q,MR_PROJECTIVE);
G = epoint_init();
X = epoint_init();
epoint_set(xG,xG,0,G);
//取得name
printf("Enter your name:");
scanf("%s", name);
//e = SHA1(name)
shs_init(&sh);
for (i=0; name[i]!=0; i++)
{
shs_process(&sh,name[i]);
}
shs_hash(&sh, hash);
bytes_to_big(20, hash, e);
//求签名r,s;并输出
irand(GetTickCount());
temp = brand();
lgconv(temp,k); //随机数k
ecurve_mult(k,G,X); //X = kG
epoint_get(X,xX,xX);
divide(xX,n,n); //Xx = Xx (mod n) = r
cotstr(xX,sn_r);
if (strlen(sn_r) == 0) //r ?= 0,若为0,则重新生成签名
{
goto again;
}
xgcd(k,n,k,k,k); //k = k^-1 (mod n)
multiply(xX,d,d); //d = Xx * d //Xx = r
add(e,d,d);
multiply(d,k,k);
divide(k,n,n);
cotstr(k,sn_s);
if (strlen(sn_s) == 0) //s ?=0,若为0,则重新生成签名
{
goto again;
}
strcpy(sn,sn_r);
sn[strlen(sn)] = 0x2D;
strcat(sn,sn_s);
printf("\nYour Serial:%s",sn);//输出sn
mirkill(q);//mirkill.....
printf("\n");
system("pause");
return 0;
}
给两组可用的注册码:
name:HorstStein
sn:9E78967285AF5A-A12B48CDE38856
name:pediy
sn:93877B493B8F71-8E7C12B710218B
--------------------------------------------------------------------------------
【经验总结】
首先,感谢一下HappyTown为我们带来这么好的crackme.
我注意到HappyTown在00401554处调用了一个copy函数,其实这个根本没有必要,不知道是什么原因。
还有一点就是,好像在取sn_s时,造成了数组越界。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2006年10月26日 10:34:08
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)