首页
论坛
专栏
课程

[原创]超~详细的CrackMe算法分析

2020-3-21 21:45 1090

[原创]超~详细的CrackMe算法分析

2020-3-21 21:45
1090

前言:这是来自看雪的一道题,年代久远。4nil前辈留下的一个crakeme。在此给出个人写得详细的,可以使新手从汇编到高级语言一一对应上的解析。希望不管是大佬还是新手,都可以来“刁难”我,提出问题,让我看看自己还有哪些不足,我会尽力回答的。

这是无壳版本(壳本身不难)。这道题的亮点在于:1.有多个导致挂的判断。2.无错误提示。3.有中间注册码,循环渐进的一个crackme。


爆破过程如下:

载入后输入name,Serial -> 鼠标右键 -> 中文搜索引擎 -> 搜索ASCII -> 发现” SHiT ... you entered the correct serial!”,下断点->往前翻找到004015A1的push下断 -> 从004015A1的push 一路F8下来,会发现0040162D的je short unpacked.00401682是关键跳转,

双击改变Z的值


继续F8,会弹窗


->在  0040162D 鼠标右键 -> 二进制用nop填充 -> 鼠标右键 -> 复制到可执行文件 -> 所有修改 -> 是 -> 鼠标右键 -> 保存文件,就可以了。



分析过程如下图:




算法如下:

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

int main()
{
	char name[20], midserial[30], lastnum[6];
	char* namef;
	int first,henNamef;
	int x,precondition;
	char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	unsigned long serial = 0, name_len = 0, serial_len, i, total = 0, temp;
	namef = "";
	printf("\t|*------Keygen 4 Bigman's CrackMe#6------*|\n\n");
	/*
	前提条件:
	1.name不能为空
	2.name[1]*x(某个值) = 11CF余17,即11b8整除name[1]
	3.  0x190<precondition(即此时的edi,图一)<0x2300
	*/
	for (int i = 1; i < 10; i++) //图二上半部分
	{
		x= 0x11b8 % i;
		if (x == 0) {
			printf("the first num you can use is:%d\n", i);
		}
		
	}
	
	printf("Input ur name:(not null)");
	scanf("%s", name);
	name_len = strlen(name);
	precondition = ((0x2bc - (0x30 - (0x48 / name_len)) * 5) * 0x68) - 0xcf6c;
	if (precondition > 0x190 && precondition<0x2300)  //图一
	{
		for (i = 0;i < name_len;i++)  //图二下半部分
		{
			total += name[i];
		}
		midserial[0] = 'T';

		for (i = 0;i < name_len;i++) //图三部分
		{
			temp = (((((name[i] ^ table[i * 3 - 1]) + ((total*i - total) ^ 0xffffffff) + 0x14d + (i + 3)*name_len*name[i]) % 10 + 0x30) ^ 0xadac)*(i + 2)) % 10 + 0x30;
			midserial[i + 1] = temp;
		}
		midserial[name_len + 1] = '\0';

		temp = (name_len*total) % 0x64 + 0x30; //图四部分
		ultoa(temp, lastnum, 10);
		strcat(midserial, "-");
		strcat(midserial, lastnum);
		serial_len = strlen(midserial);
		for (i = 1;i < serial_len;i++)  //图五部分
		{
			midserial[i] = ((midserial[i] ^ 0x20) % 10 + 0x30);
		}

		printf("Serial:%s\n", midserial);

	}

	getch();
	return 0;
}




2020安全开发者峰会(2020 SDC)议题征集 中国.北京 7月!

上传的附件:
最新回复 (5)
绥术 2020-3-21 21:56
2
0
我第一行一行的代码,删不掉,另外希望有人对我的格式,写法提出更多意见。谢谢!
刺刺 2020-3-22 00:03
3
0
感谢楼主,写的真的很详细
zzhwaxy 2020-3-23 12:26
4
0

有两点说一下

1.这段指令实际是对name长度做了限制,只能在3-8之间

0040156A  |.  81FF 00230000 cmp     edi, 2300
00401570  |.  7F 08         jg      short 0040157A
00401572  |.  81FF 90010000 cmp     edi, 190
00401578  |.  7D 04         jge     short 0040157E

2.这段指令应该是编译器优化过的,实际为 esi = edx - esi - 1 + 0x14D

0040141B  |.  83F6 FF       |xor     esi, FFFFFFFF                   ;  esi = (SUM*(i-1))^0xFFFFFFFF
0040141E  |.  8DB432 4D0100>|lea     esi, dword ptr [edx+esi+14D]    ;  esi = edx + esi + 0x14D

另外,附上我写的注册机

#include<stdio.h>
#include<math.h>
#define OFFSET(i) (3*(i)-1<0? 0:3*(i)-1+0x41)
int main(int argc,char**argv)
{
  char name[20],key[20];
  int len,SUM=0;
  printf("name:");
  if(argc!=2)
    scanf("%[^\n]",name);
  else
    sprintf(name,"%s",argv[1]);
  printf("%s\n",name);
  len=strlen(name);
  if(len<3 || len >9)
    return 0;
  for(int i=0;i<len;i++)
    SUM+=name[i];
  for(int i=0;i<len;i++)
    {
      name[i]=((((name[i]^OFFSET(i))-SUM*(i-1)-1+0x14D+name[i]*(i+3)*strlen(name))%10+0x30^0xADAC)*(i+2))%10+0x30;
    }
  sprintf(key,"%d%s-%d",6,name,len*SUM%0x64+0x30);
  len=strlen(key);
  for(int i=1;i<len;i++)
    {
      key[i]=(key[i]^0x20)%0xA+0x30;
    }
  printf("key:%s",key);
}
最后于 2020-3-23 12:27 被zzhwaxy编辑 ,原因:
尕可 2020-3-23 13:44
5
0
楼主跟楼上的都挺厉害的。
绥术 2020-3-23 16:30
6
0
zzhwaxy # 有两点说一下 1.这段指令实际是对name长度做了限制,只能在3-8之间 ``` 0040156A |. 81FF 00230000 cmp edi, 2300 0040157 ...
所言极是,谢谢提醒。
游客
登录 | 注册 方可回帖
返回