首页
社区
课程
招聘
[转帖]cyclops's Jade Crackme详解
发表于: 2012-5-25 19:59 4773

[转帖]cyclops's Jade Crackme详解

2012-5-25 19:59
4773
原地址
CM介绍:

这是一个www.crackmes.de上2006的CM。

Download Jade.zip, 6 kb
Browse contents of Jade.zip

This is some thing different from others....
No crypto....But some thing else....

Difficulty: 2 - Needs a little brain (or luck)
Platform: Windows 2000/XP only
Language: C/C++

Published: 26. Jul, 2006
Downloads: 696

在看雪的Crackme2007全集里也有,但不详细!

一、打开这个CM,发现没得文本控件,不能输入用户名和密码之类的。只有两个按键,一个“注册”和“关闭”。点注册也没有反应。用OD打开,查找字串,找到:

[plain] view plaincopy
01.00401BE0   .  A1 5C464000   mov eax,dword ptr ds:[0x40465C]  
02.00401BE5   .  56            push esi  
03.00401BE6   .  85C0          test eax,eax  
04.00401BE8   .  8BF1          mov esi,ecx  
05.00401BEA   .  74 22         je X00401C0E  
06.00401BEC   .  68 58414000   push 00404158                            ;  Registered!!!  
07.00401BF1   .  68 E8030000   push 0x3E8  
08.00401BF6   .  E8 59020000   call <jmp.&MFC42.#CWnd::SetDlgItemTextA_>  

看看流程,[0x40465C]里为非0才注册成功。[0x40465C]在哪里赋值呢?用OD的查找常量0x40465C,找到:

[plain] view plaincopy
01.00401795  |.  51            push ecx                                           ;  组1  
02.00401796  |.  52            push edx                                           ;  data+t1  
03.00401797  |.  E8 44FBFFFF   call 004012E0  
04.0040179C  |.  83C4 08       add esp,0x8  
05.0040179F  |.  A3 5C464000   mov dword ptr ds:[0x40465C],eax  

只有一个地方,就是call 004012E0的返回值。向上看看,看到:

004016D7  |.  E8 8E060000   |call <jmp.&MFC42.#CAsyncSocket::Receive_5478>     ;  }

居然用CAsyncSocket的Receive来接收数据,看来要先补一补CAsyncSocket(我有另一个文章专门介绍CAsyncSocket的)。

二、根据CAsyncSocket编程流程,先要找到它的Create方法,在OD反汇编窗口,按Ctrl+N,找到:MFC42.#CAsyncSocket::Create_2077,点它,按回车,OK。

[plain] view plaincopy
01.0040141E  |.  56            push esi  
02.0040141F  |.  6A 3F         push 0x3F  
03.00401421  |.  6A 01         push 0x1  
04.00401423  |.  68 31200000   push 0x2031  
05.00401428  |.  B9 48424000   mov ecx,00404248  
06.0040142D  |.  8975 F8       mov [local.2],esi  
07.00401430  |.  8975 F4       mov [local.3],esi  
08.00401433  |.  E8 4A090000   call <jmp.&MFC42.#CAsyncSocket::Create_2077>  

看看Create的参数,Create(0x2031,0x1,0x3F,0),它监听着本机地址的上0x2031端口,所以客户端也要这样。进入监听后,它循环执行Accept(并非CAsyncSocket的正确方法)

,直到有客户端连接。

三、分析Accept后的代码,由于代码太多,这里不粘出来了,主要是4014D6到40179F。以下是分析:

1、4014D6,发送一个“hello”给客户湍。

2、401503,循环接收数据,大小为0x64,记为KEY1。

3、401514,是一个比较函数,比较刚才接收的是否是"---...:: [CYc] ::...---"。

4、401524,随机返回一个数值,再转换成16进制形式的字串,记为RAND。

5、401547,一个简单的反Debug。

6、40158F,循环接收数据,大小为0x64,记为DATA。

7、4015B2,发RAND。

8、4015EC,循环接收数据,大小为0x64,记为SN。

9、401620,循环接收数据,大小为0x64,分析发现这个数据没有用。

10、40162A,是一个反调试,用带反反调试的OD不用理。

11、40168B,循环接收数据,大小为0x64,记为T1。

12、40169D,把T1看成一个8进制字串,转换成16进制,和RAND比较,不对就OVER。

13、4016D7,循环接收数据,大小为0x64,记为KEY2。

14、4016E8,是一个比较函数,比较刚才接收的是否是"---...:: [cYC] ::...---"。

15、401713,把SN转换成SN1+‘-’+SN2。

16、40173F,这段前后是复制字串生成SN1+DATA+T1和DATA+T1。

17、40177A,两个作用。1.生成一个固定的整数数组,记为K1。2.根据K1和SN1+DATA+T1运算出一个数与SN2比较,不对就OVER。

18、401797,根据DATA+T1运算出两个数,转换成16进制字串后与SN1比较,不对就OVER。

19、[0x40465C]为1后,再点注册就可以注册成功了。

四、写逆向代码

先写RAND到T1的算法:

[html] view plaincopy
01.sscanf(RAND,"%x",&len);  
02.sprintf(T1,"%o",len);  

SN1的算法,我是直接抠汇编:

[cpp] view plaincopy
01.void CMySocket::GetSN1(const char *indata, char *&outdata)  
02.{  
03.    outdata=new char[17];  
04.    DWORD a=0,b=0;  
05.    __asm  
06.    {  
07.        pushad  
08.        xor eax,eax  
09.        xor edx,edx  
10.        mov edi,indata  
11.        xor esi,esi  
12.        mov cl,byte ptr ds:[edi]               
13.        test cl,cl  
14.        je exit1  
15.              
16.start1:      
17.        movsx ecx,cl  
18.        xor ecx,0x159753  
19.        mov eax,ecx  
20.        add edx,ecx  
21.        or eax,0x237891  
22.        not eax  
23.        and eax,ecx  
24.        mov cl,byte ptr ds:[esi+edi+0x1]      
25.        add eax,edx  
26.        lea edx,dword ptr ds:[edx+esi-0x1]     
27.        xor edx,0xA6542689  
28.        inc esi  
29.        test cl,cl  
30.        jnz start1            
31.exit1:  
32.        mov a,edx  
33.        mov b,eax  
34.        popad  
35.    }  
36.    sprintf(outdata,"%08X%08x",a,b);  
37.}  

SN2的算法:

[cpp] view plaincopy
01.void CMySocket::GetSN2(const char *indata, char *&outdata)  
02.{  
03.    outdata=new char[9];  
04.    DWORD sn=0xFFFFFFFF,k=0,*p=0;  
05.    GetK1(p);  
06.    __asm  
07.    {            
08.        pushad  
09.        mov edi,p  
10.        mov edx,indata  
11.        or eax,0xFFFFFFFF                     
12.        movsx ecx,byte ptr ds:[edx]            
13.        test ecx,ecx  
14.        je exit1  
15.        inc edx  
16.loop1:        
17.        xor ecx,eax                           
18.        and ecx,0xFF                          
19.        shr eax,0x8  
20.        mov ecx,dword ptr ds:[ecx*4+edi]  
21.        xor eax,ecx  
22.        movsx ecx,byte ptr ds:[edx]            
23.        inc edx  
24.        test ecx,ecx  
25.        jnz loop1                  ; 运算取EAX,要逆这个  
26.exit1:  
27.        not eax  
28.        mov sn,eax  
29.        popad  
30.    }  
31.    sprintf(outdata,"%x",sn);  
32.    delete p;  
33.}  

K1的算法:

[cpp] view plaincopy
01.int CMySocket::GetK1(DWORD *&K1)  
02.{  
03.    K1=new DWORD[0x400];  
04.    DWORD t=0,i=0,j=0;  
05.    for (i=0;i<0x400;i++)  
06.    {  
07.        t=i;  
08.        for (j=0;j<8;j++)  
09.        {  
10.            if (t&1==1)  
11.            {  
12.                __asm  
13.                {  
14.                    pushad  
15.                    mov eax,t  
16.                    shr eax,1  
17.                    xor eax,0xEDB88320  
18.                    mov t,eax  
19.                    popad  
20.                }  
21.            }  
22.            else  
23.            {  
24.                __asm  
25.                {  
26.                    pushad  
27.                    mov eax,t  
28.                    shr eax,1  
29.                    mov t,eax  
30.                    popad  
31.                }  
32.            }  
33.        }  
34.        K1[i]=t;  
35.    }  
36.    return 0;  
37.}  

五、写客户端

[cpp] view plaincopy
01.void CJade_CMDlg::On1()   
02.{     
03.    const char key1[]="---...:: [CYc] ::...---";  
04.    const char key2[]="---...:: [cYC] ::...---";  
05.    char buffer[0x65]={0},*data=0,*sn1=0,*sn2=0,*sn=0,*temp=0;  
06.    char t1[11]={0};  
07.    DWORD len=0,stop=0,errorcode=0;   
08.      
09.    if( AfxSocketInit() == FALSE)  
10.    {   
11.        AfxMessageBox("Failed to Initialize Sockets");   
12.        return;   
13.    }  
14.    CAsyncSocket s;  
15.    if(s.Create(0,SOCK_STREAM,0x3f,"127.0.0.1")==FALSE)  
16.    {  
17.        myerror(GetLastError());  
18.        MessageBox("Failed to Create Socket");  
19.        return;      
20.    }  
21.    s.Connect("127.0.0.1",8241);      
22.    Sleep(200);  
23.  
24.    stop=0;  
25.    errorcode=s.Receive(buffer,5);  
26.    while(-1==errorcode)  
27.    {  
28.        errorcode=s.Receive(buffer,5);  
29.        stop++;  
30.        if (stop>10000)  
31.        {  
32.            AfxMessageBox("Receive1 out time!");  
33.            return;  
34.        }  
35.    }  
36.    s.Send(key1,strlen(key1));  
37.  
38.    memset(buffer,0xee,0x64);  
39.    s.Send(buffer,0x64);  
40.  
41.    stop=0;  
42.    errorcode=s.Receive(t1,2);  
43.    while(-1==errorcode)  
44.    {  
45.        errorcode=s.Receive(t1,2);  
46.        stop++;  
47.        if (stop>10000)  
48.        {  
49.            AfxMessageBox("Receive2 out time!");  
50.            return;  
51.        }  
52.    }  
53.    sscanf(t1,"%x",&len);  
54.    sprintf(t1,"%o",len);  
55.      
56.    len=0x64+strlen(t1);  
57.    data=new char[len+1];  
58.    ZeroMemory(data,len);  
59.    memset(data,0xee,0x64);  
60.    strcat(data,t1);  
61.    GetSN1(data,sn1);     
62.    delete [] data;  
63.    len+=strlen(sn1);  
64.    data=new char[len+1];  
65.    ZeroMemory(data,len);  
66.    strcpy(data,sn1);  
67.    temp=(char*)((DWORD)data+strlen(sn1));  
68.    memset(temp,0xee,0x64);  
69.    strcat(data,t1);  
70.    GetSN2(data,sn2);  
71.    delete [] data;  
72.    len=strlen(sn1)+strlen(sn2);  
73.    sn=new char[len+2];  
74.    strcpy(sn,sn1);  
75.    strcat(sn,"-");  
76.    strcat(sn,sn2);  
77.  
78.    s.Send(sn,strlen(sn));  
79.    s.Send(sn,strlen(sn));   
80.    s.Send(t1,strlen(t1));   
81.    s.Send(key2,strlen(key2));  
82.    s.Close();//*/  
83.    delete [] sn,sn1,sn2,data;  
84.    AfxMessageBox("可以注册了!");  
85.}   

总结:要注意的是客户端的IP,对本机而言,IP应该是“127.0.0.1”或是网的IP。端口要在连接时输入,在新建时输入会提示错误。

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 1689
活跃值: (379)
能力值: ( LV15,RANK:440 )
在线值:
发帖
回帖
粉丝
2
专辑里网络验证型的好像一共也没几个……
thank you for sharing.
2012-5-26 08:27
0
游客
登录 | 注册 方可回帖
返回
//