新CrackMe160之140 - crackme1_nitroito

OD载入程序, F8单步执行,可知004047CE处是弹框,跳过即可去掉这个NAG, 具体操作为在004047B1这行改为jmp 004047E2,直接跳到主界面去
重新载入去NAG后程序, 搜索界面看到成功关键词"Well done"定位到0040403E, 是一个方法,来到方法头00404034处,可看到信息栏提示来自00404258的调用,跳转到调用00404258处(选中信息行右键->转到...)
向上可以看到用户名长度5位以上, 系列号长度27位,且6,13,20位为'-'号,可得系列号格式为:(6)-(6)-(6)-(6)
0040424F处为关键算法, 断点运行这里,F7进入分析具体算法, 一路F8向下,
来到004040B7,入参是用户名, 执行方法后出来是用户名+一串(生成50位的串)str1, 这个有用户名参与的,我们标记好
来到004040CD,入参是上面生成的串,出参是27位的串,格式与系列号格式一样,我们可以猜想它就是正确的系列号, 这里重点标注为真正算法处
来到004040E7,发现是循环对比上面生成的串与输入的系列号, 说明上面的串就是正确的系列号

重新执行,直接来到004040CD处, F7进入分析, 看到了三个'-'号标注, 说明每个减号之间就会生成一个6位串,最后组合起来,根据这样的猜想,进行详细分析
00403E1D, 00403E30, 00403E4E, 00403E6C 入参都为前面组装的字符串str1, 出参是确实是一个6位串, 接下来就需要进入每个方法去分析6位串是如何生成的了,

123456-654321-456789-987654

继续重新执行,直接来到00403E1D处, F7进入分析,
00403D0F处, 将str1反转得到str2
00403D16处, 将str1累加: sum1 += (str1[i] + i + 1) * 2, sum1 += len(str1)
00403D1E处, 将str2累加: sum2 += (str2[i] ^ sum1) * (i + 1), sum2 = sum2 | ((i + 1) ^ sum1)
00403D2A处, 入参0x1A,
1). 00403886, sum2 % 0x1A 得 val
2). 0040389F, sum2 / 0x1A 得 num
3). 004038AD处,入参num,val, val<0xA +0x30得到一个数字0~9, 0xA<=val<0x1A +0x37得到一个大写字母A~Z,
其他三串同理可得
需要注意的是第三,四串的入参字符串变化了,由原Str串生成一个新的串在00403E43处生成

注册机如下, 可以对着看算法:

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

int func_sum1(unsigned char *str);
int func_sum2(int sum1, unsigned char *str); 
void func_getcode(int sum2, char *code);

int main() {
	char user[51] = {0}; 
	printf("用户名: ");
	scanf("%s", user); getchar(); 
	int len = strlen(user);
	if(len < 5){
		printf("用户名5位以上");
		getchar(); return 0; 
	}
	char code[7] = {0};
	unsigned char str[] = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ辽陀诶忍屹率卧";
	unsigned char str1[] = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ辽陀诶忍屹率卧";
	int lens = strlen(str);
	int i, sum1=0, sum2=0;
	for(i=0; i<len; i++){ //得到新串 
		str[i] = user[i];
	}
	for(i=0; i<lens; i++){ //生成新串 
		str1[i] = (str[i] + str1[i] + str1[i]) & 0xFF;
	}
	
	//第一组 
	sum1 = func_sum1(str);
	strrev(str); //反转字符串
	sum2 = func_sum2(sum1, str);
	func_getcode(sum2, code);
	//strrev(code);
	printf("注册码为: %s-",code);
	
	//第二组
	strrev(str); //反转字符串,得到原串
	sum2 = func_sum2(sum1, str);
	func_getcode(sum2, code);
	strrev(code);
	printf("%s-",code);
	
	//第三组
	sum1 = func_sum1(str1);
	sum2 = func_sum2(sum1, str1);
	func_getcode(sum2, code);
	strrev(code);
	printf("%s-",code);
	
	//第四组
	strrev(str1);
	sum1 = func_sum1(str1);
	sum2 = func_sum2(sum1, str1);
	func_getcode(sum2, code);
	//strrev(code);
	printf("%s\n",code);
	
	getchar(); return 0;
}

int func_sum1(unsigned char *str){
	int i, sum1=0, lens=strlen(str);
	for(i=0; i<lens; i++){ //得到累加sum1 
		sum1 += (str[i] + i + 1) * 2;
	}
	sum1 += lens;
	return sum1;
}

int func_sum2(int sum1, unsigned char *str){
	int i, sum2=0, lens=strlen(str);
	for(i=0; i<lens; i++){ //得到累加sum2
		sum2 += (str[i] ^ sum1) * (i + 1);
		sum2 = sum2 | ((i + 1) ^ sum1);
	}
	return sum2; 
}

void func_getcode(int sum2, char *code){
	int i=0;
	while(sum2 > 0){
		code[i] = sum2 % 0x1A;
		if(code[i] < 0xA) code[i] += 0x30;
		else code[i] += 0x37;
		sum2 = sum2 / 0x1A;
		i++;
		if(i>6) break;
	}
}

运行示例:
用户名: Crackme
注册码为: JNDLD1-1DFO39-21CIM7-P4KF12

 
 
本节高手录制的视频,点击前往查看

 
 
 
使用的工具连接(工具有点多有点大,可以先下OD,其它的后面慢慢下) 点击前往下载

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

posted @ 2024-12-30 14:35  hankerstudio  阅读(17)  评论(0)    收藏  举报