新手破解练习Crackme160之125 - nullz

  1. Very Easy
    OD载入程序, 通过失败关键词 "Invalid Registration Key!" 定位到00401A4B, 跳转来自004019EF, 上面即是字符串比较, 得到固定串 "qJT62aWfviq0P57JGs2FelQkX", 输入验证成功~
     

  2. Simple version1
    同理搜索错误提示关键词 "User Name must ..." 定位到00401B10, 00401C96, 分别下断, 点验证~ 在00401B10处停下~, 所以这个事件入口是00401A70, 看到有跳入指示, 所以往上看, 发现了5个jmp应该对应1~5关的跳转吧, 都下断测试确实如猜想那般~ 我们继续第2关, 输入abcde, 12345单步分析算法:
    1). for(i=1; i<=len; i++){ rlt = (rlt+user[i]) * i; }
    2). for((i=0; i<len; i++){ code[i] = rlt / user[i] % 10 + 0x30; }
    3). 得到code = "63963" 与 输入的12345对比
    注册机代码如下:

	#include <stdio.h>
	#include <string.h>

	int main() {
		char user[21] = {0};
		char code[21] = {0};
		unsigned long rlt = 0;
		printf("User Name: "); scanf("%s",user);
		int len = strlen(user);
		if(len < 5){
			printf("User Name must have at least 5 characters.");
			return 0;
		}
		for(int i=1; i<=len; i++){
			rlt = (rlt + user[i]) * i;
		}
		for(int i=0; i<len; i++){
			code[i] = rlt / user[i] % 10 + 0x30;
		}
		printf("Reg. Key : %s\n", code);
		
		getchar();getchar();
		return 0;
	}

运行示例:
User Name: abcde
Reg. Key : 63963
 

  1. Simple version2
    断点已经下好了直接单步跟踪分析算法: (直接上注册机代码, 对着看吧)
	#include <stdio.h>
	#include <string.h>

	int main() {
		char user[21] = {0};
		unsigned long esi = 0x81276345;
		int edi=0;
		printf("User Name: "); scanf("%s",user);
		int len = strlen(user);
		if(len < 5){
			printf("User Name must have at least 5 characters.");
			return 0;
		}
		for(int i=0; i<len; i++){
			esi += user[i];
			esi ^= i << 8;
			esi *= (i + 1);
			esi *= ~edi;
			edi += len;
		}
		
		printf("Reg. Key : %lu\n", esi);
		getchar();getchar();
		return 0;
	}

运行示例:
User Name: abcde
Reg. Key : 3534803155
 

  1. Pretty Common
    同上断点已下, 输入abcde, 12345, 67890, 单步跟踪, 这个比较复杂一些, 有好几个循环, 需要花比较多时间来跟踪分析, 其中公司名无用, 随便输, 注册机代码如下, 可以对比理解一下:
	#include <stdio.h>
	#include <string.h>

	int CalculateValue(char *szName, unsigned int nLength, unsigned int initValue);
	char *reverse_string(char *p, unsigned int nLength);

	int main() {
		char user[21] = {0};
		char code[101] = {0};
		unsigned long val1=0, val2=0;
		printf("User Name: "); scanf("%s",user);
		int len = strlen(user);
		if(len < 5){
			printf("User Name must have at least 5 characters.");
			return 0;
		}
		
		for(int i=0; i<len; i++){
			if(i % 2 == 1){
				val1=CalculateValue((char*)user, len, val2+i);
			} else {
				val2=CalculateValue((char*)user, len, val1+i);
			}
		}
		
		sprintf(code, "%lu-%X", val1, val2);
		reverse_string((char*)code, strlen(code));
		printf("Reg. Key : %s\n", code);
		
		getchar();getchar();
		return 0;
	}


	int CalculateValue(char *szName, unsigned int nLength, unsigned int initValue)
	 {
		unsigned int i, j, k, nTemp, nTemp1, nTemp2, nTemp3, nTemp4, nTemp5, nValue;
		int iResult;
		char szConst[] = "h14Ml0x\n7kCHwXBzH\tG8iN9+wb5VHZ";
		unsigned int dwConstLength = strlen(szConst);
	 
		nValue = 1;
		for (i = 0; i < nLength; i++)
		{
			nTemp = szName[i];
			nValue *= nTemp;
			k = 1;
			for (j = 0; j < dwConstLength / 2; j++)
			{
				nTemp2 = k + j;
				nTemp3 = szName[i] % nTemp2;
				nTemp4 = szConst[dwConstLength - j - 1] - nTemp3;
				nTemp5 = szConst[j];
				nTemp5 += nValue;
				nValue = nTemp5 + nTemp4;
			}
			nValue *= (i+1);
			nValue = nValue << 8;
			nValue ^= initValue;
		}
		iResult = nValue;
		return iResult;
	 }

	//字符串倒序 
	char *reverse_string(char *p, unsigned int len)
	 {
		if ((NULL == p) || (0 == len) || ('\0' == *p)) return p;
		char c;
		int i=0;
		while(i<len/2){ //头尾对换 
			c = *(p+len-1-i);
			*(p+len-1-i) = *(p+i);
			*(p+i) = c;
			i++;
		}
		return p;
	 }

运行示例:
Company: 任意
User Name: abcde
Reg. Key : A0B544EA-6808514132
 

  1. Slightly Diffical
    这关比较难一点, 步骤比较多, 大佬都没做完, 我先记录下大佬代码:
	#include <stdio.h>
	#include <string.h>

	unsigned int getvaluebyname(char *szName,unsigned int filesize,unsigned int nCompanyLength,unsigned int *psize);
	int rol(unsigned int num, unsigned char i);

	int main() {
		unsigned char szName[32] = { 0 };
		unsigned char szCompany[32] = { 0 };
		char * pBuf,c0,c1,c2,*pTempBuf,*pNewBuf;
		unsigned int nNameLength, nFileLength, nCompanyLength, nNameValue, nbufsize, i, j, nReadSize, *pInt, nTemp,nTemp10, nTemp2, nTemp9,nTemp11;
		FILE *fp=NULL;
		printf("User Name: ");
		scanf("%s", szName);
		nNameLength = strlen((char*)szName);
	 
		if (nNameLength < 5)
		{
			printf("User Name must have at least 5 characters.");
			return 0;
		}
	 
		printf("Company:");
		scanf("%s", szCompany);
		nCompanyLength = strlen((char*)szCompany);
	 
		fp = fopen("nullz.exe", "rb");
		if (NULL == fp)
		{
			printf("Open nullz.exe Fail.\r\n");
			return 0;
		}
	 
		fseek(fp, 0, SEEK_END);
		nFileLength = ftell(fp);
	 
		nNameValue = getvaluebyname("abcdefgh", nFileLength, nCompanyLength,&nbufsize);
		if (nNameValue < nFileLength)
			fseek(fp, nNameValue, 0);
		pBuf = new char[nbufsize + 3];
		if (NULL == pBuf)
		{
			fclose(fp);
			printf("Set Memery Fail.\r\n");
			return 0;
		}
	 
		nReadSize=fread(pBuf, 1, nbufsize, fp);
		fclose(fp);
		j = 0;
		for (i = 0; i < nReadSize; i = i + 4)
		{
			pInt = (unsigned int *)(pBuf + i);
			nTemp = (*pInt) ^ (*((unsigned int *)szName)) ^ j;
			while(true){ // 由下面汇编翻译
				nTemp = rol(nTemp, (nTemp % 0x1F) & 0xFF);
				if(nTemp >= 0) {break;}
				nTemp = ~nTemp; 
			}
			/* __asm{
				push eax
				push edx
				push ecx
				push ebx
	 
				mov eax,nTemp
				xor edx,edx
				mov ebx,0x1F
				div ebx
				mov eax, nTemp
				mov cl,dl
				rol eax,cl
				jnb _NEXT
				not eax
				_NEXT:
				mov nTemp,eax
	 
				pop ebx
				pop ecx
				pop edx
				pop eax
			}*/
			*pInt = nTemp;
			j += 4;
		}
	 
		pTempBuf = pBuf+1;
		pNewBuf = new char[nReadSize >> 2]();
		j = 0;
		for (i = 0; i <((nReadSize/4)*4); i=i+4)
		{
			nTemp2 = (unsigned char)*(pTempBuf - 1);
			nTemp2 = nTemp2<<8;
			nTemp2 |= (unsigned char)(pTempBuf[0]);
			nTemp2 = nTemp2 << 8;
			nTemp2 |= (unsigned char)*(pTempBuf + 1);
			pTempBuf += 4;
			nTemp2 = nTemp2 << 8;
			nTemp2 |= (unsigned char)*(pTempBuf - 2);
			*((unsigned int*)(pNewBuf + j * 4)) = nTemp2;
			j++;
		}
	 
		nTemp10 = 0xFF33FF77;//esi
		pTempBuf = pNewBuf;
		nTemp9 = 1;
		nTemp11 = (*(unsigned int *)(pTempBuf)) ^ (*(unsigned int *)(pTempBuf-4));//对应00402222  |.  33CB          xor ecx,ebx
		//以下代码未验证 
		for (i = 0; i <((nReadSize / 4) ); i++)
		{
			nTemp2 = *((unsigned int *)(pTempBuf + 4 * i));
			nTemp10 ^= nTemp2;
			nTemp2 -= i;
			nTemp10 *= (i + 1);
			nTemp9 += nTemp2;
			c0 = *(((char*)&nTemp9));
			*(((char*)&nTemp9)) = *(((char*)&nTemp10)+1);
			*(((char*)&nTemp10) + 1) = c0;
		}
		nTemp = (nTemp11^nTemp10 + nTemp9) ^ nTemp9;
		//printf("Reg. key : %s\r\n ", (char*)&nTemp);
		
		getchar();getchar();
		return 0;
	 }
	 
	int rol(unsigned int num, unsigned char i)
	{
		return (num << i) | (num >> (sizeof(int) * 8 - i));
	}
	 
	//004023BA  |.  E8 A1000000   call nullz.00402460
	 //getvaluebyname实现了call 00402460函数调用的功能
	unsigned int getvaluebyname(char *szName,unsigned int filesize,unsigned int nCompanyLength,unsigned int *psize)
	 {
		unsigned int nResult = 0;
		unsigned int i = 0,nLength,nTemp;
		nLength = strlen(szName);
		nResult = 1;
		for (i = 0; i < nLength; i++)
		{
			nResult *= (szName[i] - nCompanyLength + i);
		}
		nResult ^= (filesize<<8);
		nTemp = filesize >> 1;
		if (0 == (nResult%nTemp))
			nResult = ~nResult;
		nResult =  nResult%nTemp;
		*psize = nResult;
		nResult = filesize - nResult;
		nResult = nResult >> 1;
		return nResult;
	 }

因为代码没完全写完, 所以就还没有结果了, 有空再来细究~
 

  1. Little Challenging
    这关作都说了还没有, 不用解了~

 
 
 
这是160个软件part1
这是160个软件part2

1~160每个破解过程,在吾爱破解论坛都有高手破解过了,也有整理好现成的, 我这边主要就是自己动手操作的过程,与他们的不太一样
附上高手们的连接: 点击前往查看
使用的工具连接(工具有点多有点大,可以先下OD,其它的后面慢慢下) 点击前往下载

新人入门教程"玩玩破解,写给新人看" 点击前往查看
我就是从这里开始的,对我这样的小白感觉超级友好~

下面是我的OD的界面布局,我觉得这4个是最常用的界面,其它的我基本上没用到~
OD界面布局

posted @ 2024-07-31 16:12  hankerstudio  阅读(10)  评论(0)    收藏  举报