selph
selph
发布于 2022-09-04 / 235 阅读
1
0

新160个CrackMe练习:063-dc0de-crackme

算法难度:⭐⭐⭐⭐

爆破难度:⭐

信息收集

运行情况:

image

查壳与脱壳:

Delphi程序,无壳

image

调试分析

通过IDR找到按钮事件的函数,在IDA里分析:

开始是初始化操作,读取Name和Serial,然后复制了一串奇怪的东西到变量里

image

接下来对刚刚复制的内容的值全部进行+1操作

然后判断了下用户名长度,必须是1-10字符

image

往下是一个循环:功能是复制字符串,把那个奇怪的东西复制了一份

image

然后往刚刚复制完成的后面间隔一个00,复制我们的UserName:

image

然后遍历这个新生成的str2字符串,进入一个大循环:当值分别是这7种情况的时候分别单独进行处理

具体计算方式如果看反汇编不太清楚,可以看下面的注册机代码

image

不同情况的处理基本上是两个一组:

3C和3E的处理分别是对一个索引值进行–和++操作

image

2B和2D的操作则是将使用索引取到的值分别进行++和–操作

image

对于5B和5D:

  • 如果索引的值是0,5B是向后搜索5D,
  • 如果索引的值是非0,5D则是向前搜索5B

对于21分支,则是设置跳出条件

image

大循环之后,还有个小循环:

累加原Name所在位置开始往后10个字节的值,累加到edi里,这个edi是个固定值:0x012F73C

然后比对,如果相同则弹窗成功

image


注册机

注册码生成算法:

#include <iostream>
#include <string>

char str[100] = ";;;;;;;;;;;;;**====,,=,,========*=**=*=**=*=**=*=*=* ";
char str2[100] = { 0 };

int main()
{
	std::string name = "";
	std::cin >> name;

	for (int i = 0; i < strlen(str); i++) {
		str[i] = str[i] + 1;
		str2[i] = str[i];
	}

	for (int i = 0; i < name.length(); i++)
		str2[strlen(str) + i + 1] = name[i];

	// n索引指向的是Name
	int n = strlen(str) + 2-1;
	int flag = 0;
	for (int i = 0; flag != 1; i++)
	{
		switch (str2[i])
		{
		case 0x3E:n++; break;
		case 0x3C:n--; break;
		case 0x2B:str2[n]++; break;
		case 0x2D:str2[n]--; break;
		case 0x21:flag = 1; break;
		case 0x5B: {
			if (str2[n] == 0)
				do i++; while (str2[i] != 0x5D);
			break;
		}
		case 0x5D: {
			if (str2[n] != 0)
				do i--; while (str2[i] != 0x5B);
			break;
		}default:
			break;
		}
	}
	int sum = 0x012F73C;
	for (int i = 0; i < 10; i++)
	{
		int len = strlen(str) + i + 1;
		sum += str2[len];
	}
	std::cout << sum << std::endl;
}

效果:

image

总结

是个不错的switch-case语句的反汇编练习


评论