cyclops's Jade Crackme详解

本文详细解析了一个名为Jade的CM(Crackme),通过逆向工程揭示其注册逻辑。该CM利用CAsyncSocket进行通信,接收并验证特定的数据模式来判断注册是否成功。文章深入分析了如何通过编程实现逆向算法,包括RAND生成、SN获取等关键步骤,并提供了一个客户端实现示例。最终指导读者完成注册过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 esi
00401BE6   .  85C0          test eax,eax
00401BE8   .  8BF1          mov esi,ecx
00401BEA   .  74 22         je X00401C0E
00401BEC   .  68 58414000   push 00404158                            ;  Registered!!!
00401BF1   .  68 E8030000   push 0x3E8
00401BF6   .  E8 59020000   call <jmp.&MFC42.#CWnd::SetDlgItemTextA_>

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

00401795  |.  51            push ecx                                           ;  组1
00401796  |.  52            push edx                                           ;  data+t1
00401797  |.  E8 44FBFFFF   call 004012E0
0040179C  |.  83C4 08       add esp,0x8
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。

0040141E  |.  56            push esi
0040141F  |.  6A 3F         push 0x3F
00401421  |.  6A 01         push 0x1
00401423  |.  68 31200000   push 0x2031
00401428  |.  B9 48424000   mov ecx,00404248
0040142D  |.  8975 F8       mov [local.2],esi
00401430  |.  8975 F4       mov [local.3],esi
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的算法:

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
	{
		pushad
		xor eax,eax
		xor edx,edx
		mov edi,indata
		xor esi,esi
		mov cl,byte ptr ds:[edi]             
		test cl,cl
		je exit1
			
start1:		
		movsx ecx,cl
		xor ecx,0x159753
		mov eax,ecx
		add edx,ecx
		or eax,0x237891
		not eax
		and eax,ecx
		mov cl,byte ptr ds:[esi+edi+0x1]     
		add eax,edx
		lea edx,dword ptr ds:[edx+esi-0x1]   
		xor edx,0xA6542689
		inc esi
		test cl,cl
		jnz start1			
exit1:
		mov a,edx
		mov b,eax
		popad
	}
	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
	{			
		pushad
		mov edi,p
		mov edx,indata
		or eax,0xFFFFFFFF                    
		movsx ecx,byte ptr ds:[edx]          
		test ecx,ecx
		je exit1
		inc edx
loop1:		
		xor ecx,eax                          
		and ecx,0xFF                        
		shr eax,0x8
		mov ecx,dword ptr ds:[ecx*4+edi]
		xor eax,ecx
		movsx ecx,byte ptr ds:[edx]          
		inc edx
		test ecx,ecx
		jnz loop1                  ; 运算取EAX,要逆这个
exit1:
		not eax
		mov sn,eax
		popad
	}
	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
				{
					pushad
					mov eax,t
					shr eax,1
					xor eax,0xEDB88320
					mov t,eax
					popad
				}
			}
			else
			{
				__asm
				{
					pushad
					mov eax,t
					shr eax,1
					mov t,eax
					popad
				}
			}
		}
		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。端口要在连接时输入,在新建时输入会提示错误。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值