cyclops's Jade Crackme详解

来源:互联网 发布:mac os 10.7的升级包 编辑:程序博客网 时间:2024/06/05 16:51

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打开,查找字串,找到:

00401BE0   .  A1 5C464000   mov eax,dword ptr ds:[0x40465C]00401BE5   .  56            push esi00401BE6   .  85C0          test eax,eax00401BE8   .  8BF1          mov esi,ecx00401BEA   .  74 22         je X00401C0E00401BEC   .  68 58414000   push 00404158                            ;  Registered!!!00401BF1   .  68 E8030000   push 0x3E800401BF6   .  E8 59020000   call <jmp.&MFC42.#CWnd::SetDlgItemTextA_>

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

00401795  |.  51            push ecx                                           ;  组100401796  |.  52            push edx                                           ;  data+t100401797  |.  E8 44FBFFFF   call 004012E00040179C  |.  83C4 08       add esp,0x80040179F  |.  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。

0040141E  |.  56            push esi0040141F  |.  6A 3F         push 0x3F00401421  |.  6A 01         push 0x100401423  |.  68 31200000   push 0x203100401428  |.  B9 48424000   mov ecx,004042480040142D  |.  8975 F8       mov [local.2],esi00401430  |.  8975 F4       mov [local.3],esi00401433  |.  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的算法:

sscanf(RAND,"%x",&len);sprintf(T1,"%o",len);

 

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

void CMySocket::GetSN1(const char *indata, char *&outdata){outdata=new char[17];DWORD a=0,b=0;__asm{pushadxor eax,eaxxor edx,edxmov edi,indataxor esi,esimov cl,byte ptr ds:[edi]             test cl,clje exit1start1:movsx ecx,clxor ecx,0x159753mov eax,ecxadd edx,ecxor eax,0x237891not eaxand eax,ecxmov cl,byte ptr ds:[esi+edi+0x1]     add eax,edxlea edx,dword ptr ds:[edx+esi-0x1]   xor edx,0xA6542689inc esitest cl,cljnz start1exit1:mov a,edxmov b,eaxpopad}sprintf(outdata,"%08X%08x",a,b);}

 

SN2的算法:

void CMySocket::GetSN2(const char *indata, char *&outdata){outdata=new char[9];DWORD sn=0xFFFFFFFF,k=0,*p=0;GetK1(p);__asm{pushadmov edi,pmov edx,indataor eax,0xFFFFFFFF                    movsx ecx,byte ptr ds:[edx]          test ecx,ecxje exit1inc edxloop1:xor ecx,eax                          and ecx,0xFF                        shr eax,0x8mov ecx,dword ptr ds:[ecx*4+edi]xor eax,ecxmovsx ecx,byte ptr ds:[edx]          inc edxtest ecx,ecxjnz loop1                  ; 运算取EAX,要逆这个exit1:not eaxmov sn,eaxpopad}sprintf(outdata,"%x",sn);delete p;}

 

K1的算法:

int CMySocket::GetK1(DWORD *&K1){K1=new DWORD[0x400];DWORD t=0,i=0,j=0;for (i=0;i<0x400;i++){t=i;for (j=0;j<8;j++){if (t&1==1){__asm{pushadmov eax,tshr eax,1xor eax,0xEDB88320mov t,eaxpopad}}else{__asm{pushadmov eax,tshr eax,1mov t,eaxpopad}}}K1[i]=t;}return 0;}

 

五、写客户端

void CJade_CMDlg::On1() {const char key1[]="---...:: [CYc] ::...---";const char key2[]="---...:: [cYC] ::...---";char buffer[0x65]={0},*data=0,*sn1=0,*sn2=0,*sn=0,*temp=0;char t1[11]={0};DWORD len=0,stop=0,errorcode=0;if( AfxSocketInit() == FALSE){ AfxMessageBox("Failed to Initialize Sockets"); return; }CAsyncSocket s;if(s.Create(0,SOCK_STREAM,0x3f,"127.0.0.1")==FALSE){myerror(GetLastError());MessageBox("Failed to Create Socket");return;}s.Connect("127.0.0.1",8241);Sleep(200);stop=0;errorcode=s.Receive(buffer,5);while(-1==errorcode){errorcode=s.Receive(buffer,5);stop++;if (stop>10000){AfxMessageBox("Receive1 out time!");return;}}s.Send(key1,strlen(key1));memset(buffer,0xee,0x64);s.Send(buffer,0x64);stop=0;errorcode=s.Receive(t1,2);while(-1==errorcode){errorcode=s.Receive(t1,2);stop++;if (stop>10000){AfxMessageBox("Receive2 out time!");return;}}sscanf(t1,"%x",&len);sprintf(t1,"%o",len);len=0x64+strlen(t1);data=new char[len+1];ZeroMemory(data,len);memset(data,0xee,0x64);strcat(data,t1);GetSN1(data,sn1);delete [] data;len+=strlen(sn1);data=new char[len+1];ZeroMemory(data,len);strcpy(data,sn1);temp=(char*)((DWORD)data+strlen(sn1));memset(temp,0xee,0x64);strcat(data,t1);GetSN2(data,sn2);delete [] data;len=strlen(sn1)+strlen(sn2);sn=new char[len+2];strcpy(sn,sn1);strcat(sn,"-");strcat(sn,sn2);s.Send(sn,strlen(sn));s.Send(sn,strlen(sn));s.Send(t1,strlen(t1));s.Send(key2,strlen(key2));s.Close();//*/delete [] sn,sn1,sn2,data;AfxMessageBox("可以注册了!");} 

 

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