【文章标题】: HappyTown的第27个CrackMe分析
【文章作者】: HorstStein
【作者邮箱】: [email]horststein@hotmail.com[/email]
【软件名称】: HappyTown's CrackMe_0027
【下载地址】: http://bbs.pediy.com/showthread.php?s=&threadid=33850
【加壳方式】: 没有
【保护方式】: 序列号
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
RSA签名算法的描述在文章的下面,你可以先浏览一下,然后再来理解程序对签名的验证过程可能会更好。
00401154 |>push 10 ; 0x10
00401156 |>push 320 ; 0x320
0040115B |>stos byte ptr es:[edi]
0040115C |>call 00401AC0 ; mirsys
00401161 |>mov ebp, eax
00401163 |>mov ecx, 18
00401168 |>xor eax, eax
0040116A |>lea edi, [esp+2D]
0040116E |>mov byte ptr [esp+2C], 0
00401173 |>mov byte ptr [esp+90], 0
0040117B |>rep stos dword ptr es:[edi]
0040117D |>stos word ptr es:[edi]
0040117F |>stos byte ptr es:[edi]
00401180 |>mov ecx, 18
00401185 |>xor eax, eax
00401187 |>lea edi, [esp+91]
0040118E |>mov esi, [esp+2C4]
00401195 |>rep stos dword ptr es:[edi]
00401197 |>stos word ptr es:[edi]
00401199 |>mov ebx, [<&USER32.GetDlgItemTextA>] ; USER32.GetDlgItemTextA
0040119F |>add esp, 8
004011A2 |>stos byte ptr es:[edi]
004011A3 |>lea eax, [esp+24]
004011A7 |>push 65 ; /Count = 65 (101.)
004011A9 |>push eax ; |Buffer
004011AA |>push 3E8 ; |ControlID = 3E8 (1000.)
004011AF |>push esi ; |hWnd
004011B0 |>call ebx ; \GetDlgItemTextA
004011B2 |>lea edi, [esp+24] ; name
004011B6 |>or ecx, FFFFFFFF
004011B9 |>xor eax, eax
004011BB |>repne scas byte ptr es:[edi]
004011BD |>not ecx
004011BF |>dec ecx
004011C0 |>cmp ecx, 3 ; name长度不能小于3
004011C3 |>jb 004013F5
004011C9 |>lea edi, [esp+24]
004011CD |>or ecx, FFFFFFFF
004011D0 |>repne scas byte ptr es:[edi]
004011D2 |>not ecx
004011D4 |>dec ecx
004011D5 |>cmp ecx, 23 ; name长度不能大于35
004011D8 |>ja 004013F5
004011DE |>lea ecx, [esp+88]
004011E5 |>push 65 ; /Count = 65 (101.)
004011E7 |>push ecx ; |Buffer
004011E8 |>push 3E9 ; |ControlID = 3E9 (1001.)
004011ED |>push esi ; |hWnd
004011EE |>call ebx ; \GetDlgItemTextA
004011F0 |>test eax, eax ; sn长度不能为0
004011F2 |>je 004013F5
004011F8 |>mov al, [esp+88]
004011FF |>test al, al
00401201 |>je short 00401249
00401203 |>lea esi, [esp+88]
0040120A |>/cmp dword ptr [40DFEC], 1 ; /sn是否为16进制数
00401211 |>|jle short 00401227
00401213 |>|xor edx, edx
00401215 |>|push 80
0040121A |>|mov dl, [esi]
0040121C |>|push edx
0040121D |>|call 00407050
00401222 |>|add esp, 8
00401225 |>|jmp short 00401239
00401227 |>|mov ecx, [40DDE0] ; CrackMe_.0040DDEA
0040122D |>|xor eax, eax
0040122F |>|mov al, [esi]
00401231 |>|mov al, [ecx+eax*2]
00401234 |>|and eax, 80
00401239 |>|test eax, eax
0040123B |>|je 004013F5
00401241 |>|mov al, [esi+1]
00401244 |>|inc esi
00401245 |>|test al, al
00401247 |>\jnz short 0040120A ; \
00401249 |>push 0
0040124B |>mov dword ptr [ebp+234], 10 ; mip->IOBASE=16
00401255 |>call 004018A0 ; mirvar
0040125A |>push 0
0040125C |>mov esi, eax
0040125E |>call 004018A0
00401263 |>push 0
00401265 |>mov ebp, eax
00401267 |>call 004018A0
0040126C |>push 0
0040126E |>mov edi, eax
00401270 |>call 004018A0
00401275 |>push 0
00401277 |>mov [esp+2C], eax
0040127B |>call 004018A0
00401280 |>push 0
00401282 |>mov ebx, eax
00401284 |>call 004018A0
00401289 |>push 0
0040128B |>mov [esp+2C], eax
0040128F |>call 004018A0
00401294 |>push 0
00401296 |>mov [esp+34], eax
0040129A |>call 004018A0
0040129F |>mov edx, [esp+30]
004012A3 |>push 0040D14C ; ASCII "6012CF41CA8C4406C94D3C1E9CC3A8A7372B29383B5F5761"
004012A8 |>push edx ; nA
004012A9 |>mov [esp+44], eax
004012AD |>call 00403E20
004012B2 |>push 0040D13C ; ASCII "331F925C548E7"
004012B7 |>push ebx ; eA
004012B8 |>call 00403E20
004012BD |>push 0040D108 ; ASCII "A41D2F44D7121ADBA723D82F5274B4932103CF7F7B4BCEF1"
004012C2 |>push edi ; nB
004012C3 |>call 00403E20
004012C8 |>push 0040D0D4 ; ASCII "855DD8EBF213704056CC1C0A8BF50154CABC04E00F8ED603"
004012CD |>push ebp ; dB
004012CE |>call 00403E20
004012D3 |>add esp, 40
004012D6 |>lea eax, [esp+88]
004012DD |>push eax ; sn
004012DE |>push esi ; C
004012DF |>call 00403E20 ; cinstr(C, sn):C=sn
004012E4 |>push edi ; nB
004012E5 |>push esi ; C
004012E6 |>call 004027A0 ; compare(C, nB):C是否小于nB
004012EB |>add esp, 10
004012EE |>cmp eax, -1
004012F1 |>jnz 004013F5
004012F7 |>lea ecx, [esp+150]
004012FE |>push ecx ; 下面是SHA1(name)
004012FF |>call 00403AF0 ; SHA1_Init,跟进去就可以看见那几个常数
00401304 |>mov al, [esp+28]
00401308 |>add esp, 4
0040130B |>test al, al
0040130D |>je short 0040133C
0040130F |>lea edx, [esp+24]
00401313 |>mov [esp+20], edx
00401317 |>/and eax, 0FF
0040131C |>|push eax
0040131D |>|lea eax, [esp+154]
00401324 |>|push eax
00401325 |>|call 00403B30 ; SHA1_Update
0040132A |>|mov eax, [esp+28]
0040132E |>|add esp, 8
00401331 |>|inc eax
00401332 |>|mov [esp+20], eax
00401336 |>|mov al, [eax]
00401338 |>|test al, al
0040133A |>\jnz short 00401317
0040133C |>lea ecx, [esp+EC]
00401343 |>lea edx, [esp+150]
0040134A |>push ecx ; 这里保留了最后的hash值
0040134B |>push edx
0040134C |>call 00403D80 ; SHA1_Final
00401351 |>mov eax, [esp+1C]
00401355 |>lea ecx, [esp+F4]
0040135C |>push eax ; h
0040135D |>push ecx ; SHA1(name)
0040135E |>push 14 ; 20:SHA1(name)的字节长度
00401360 |>call 00403970 ; bytes_to_big(20, SHA1(name), h)
00401365 |>mov edx, [esp+2C]
00401369 |>push edx ; S
0040136A |>push edi ; nB
0040136B |>push ebp ; dB
0040136C |>push esi ; C
0040136D |>call 00402CE0 ; powmod:S=C^dB (mod nB)
00401372 |>mov eax, [esp+40]
00401376 |>mov ecx, [esp+34]
0040137A |>mov edx, [esp+3C]
0040137E |>push eax ; m
0040137F |>push ecx ; nA
00401380 |>push ebx ; eA
00401381 |>push edx ; S
00401382 |>call 00402CE0 ; powmod:m=S^eA (mod nA)
00401387 |>mov eax, [esp+48]
0040138B |>mov ecx, [esp+50]
0040138F |>push eax ; h
00401390 |>push ecx ; m
00401391 |>call 004027A0 ; compare(m,h)是否相等,相等则注册成功
00401396 |>add esp, 3C
00401399 |>test eax, eax
0040139B |>jnz short 004013F5
我们先来看一下RSA签名算法的过程,然后即可轻松理解上面的验证过程:
/* A签名的过程(请参考《计算机密码学 第三版》,卢开澄(我的老师:D),清华大学出版社,P162):nA < nB
* S1. A计算
* S≡h^dA (mod nA)
* S2. A将S用B的公钥加密得密文
* C≡S^eB (mod nB)
* B收到C后解密如下:
* S1. 对C用B的密钥dB解密得
* C^dB (mod nB)≡S^(eB * dB) (mod nB) ≡S
* S2. 对S用A的公钥再解密
* S^eA (mod nA)≡h^(dA * eA) (mod nA) ≡h
*/
/* 在这个CrackMe中的各个参数(用RSATool可求得):
* A:
* pA = 84E8B65E382CBC80494D438B;
* qA = B90CC96501089AF27EC13E43;
* nA = 6012CF41CA8C4406C94D3C1E9CC3A8A7372B29383B5F5761; //在原程序中有
* dA = 59445332D2C4A00497EFCC34D2C34C1EB72B572566EFE263;
* eA = 331F925C548E7; //在原程序中有
*
* B:
* pB = DA974C254AB581D22550A323;
* qB = C0333135920DF051F992C0DB;
* nB = A41D2F44D7121ADBA723D82F5274B4932103CF7F7B4BCEF1; //在原程序中有
* dB = 855DD8EBF213704056CC1C0A8BF50154CABC04E00F8ED603; //在原程序中有
* eB = 23B9294352183;
* 192 bit
*/
好了,我们来写这个CrackMe的注册机,这里是关键代码:
#include <miracl.h>
void GenSn(unsigned char *name, unsigned char *sn)
{
int i;
sha sh;
char szSHAHash[20]={0}; //存放SHA1(Name)
big dA,nA,eB,nB,S,C,h;
miracl *mip=mirsys(0x320,0x10);
//initialization
mip->IOBASE = 16; // 设定16进制模式
dA = mirvar(0);
nA = mirvar(0);
eB = mirvar(0);
nB = mirvar(0);
S = mirvar(0);
C = mirvar(0);
h = mirvar(0);
cinstr(nA, "6012CF41CA8C4406C94D3C1E9CC3A8A7372B29383B5F5761");
cinstr(dA, "59445332D2C4A00497EFCC34D2C34C1EB72B572566EFE263");
cinstr(nB, "A41D2F44D7121ADBA723D82F5274B4932103CF7F7B4BCEF1");
cinstr(eB, "23B9294352183");
//计算h = SHA1(name)
shs_init(&sh);
for (i=0; name[i]!=0; i++)
{
shs_process(&sh,name[i]);
}
shs_hash(&sh, szSHAHash);
bytes_to_big(20, szSHAHash, h);
//
powmod(h,dA,nA,S); //S≡h^dA (mod nA)
powmod(S,eB,nB,C); //C≡S^eB (mod nB)
//输出
cotstr(C,sn);
mirkill(dA);
mirkill(nA);
mirkill(eB);
mirkill(nB);
mirkill(S);
mirkill(C);
mirkill(h);
mirexit();
}
给出两组可用的注册码:
name:HorstStein
sn:93B1735114E67B2492DA403EC8F18DFADCA356A482A6B794
name:pediy
sn:5A79793A010344A53ADBD73933B1E2A1255D105020DAE6A2
附件中有我写的注册机。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2006年10月26日 11:01:26
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
上传的附件: