selph
selph
发布于 2022-08-18 / 168 阅读
0
0

新160个CrackMe练习:048-monkeycrackme1

算法难度:⭐⭐⭐

爆破难度:⭐

信息收集

运行情况:

image

查壳与脱壳:

image

调试分析

程序验证逻辑很简单:

首先以硬编码0xce6d和0x58bf创建了一个对象结构,然后读取Name,计算一个字符串,然后读取Serial字符串,进行比对,一样则表示成功,否则表示失败

这里要注意,delphi使用的是32位的fastcall,传参顺序是eax,edx,ecx,栈,最后调用计算字符串的函数的时候,有一个栈中的参数

image

计算逻辑也很简单:

首先保存变量,初始化输出缓冲区

然后计算Name长度,遍历每一个字符

对于每一个字符,和两字节变量右移8位后的结果异或一下,然后转换成十六进制(大写)拼接到输出缓冲区里

然后中间处理了一下两字节值,初值是4DE1是参数传入的,修改方式是使用异或后的一字节,加上原本的两字节值,然后乘以安全对象的第一个成员,最后加上安全对象的第二个成员的值(第一个成员的值和第二个成员的值可以通过动态调试得知,是固定值)

image

注册机

注册码生成算法:

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>
typedef struct _TSecurity
{
	_TSecurity(uint16_t a, uint16_t b) :vul1(a), vul2(b) {}
	uint16_t vul1;
	uint16_t vul2;
}TSecurity,*PTSecurity;

int main()
{
	TSecurity obj(0xce6d,0x58bf);
	char name[100] = { 0 };
	short num = 0x4de1;
	char serial[100] = { 0 };
	char tmp[100] = { 0 };

	std::cin >> name;
	int len = strlen(name);
	for (int i = 0; i < len; i++)
	{
		uint8_t c = name[i] ^ (num >> 8);
		num = (c + num) * obj.vul1 + obj.vul2;
		sprintf(tmp, "%02X", c);
		strcat(serial, tmp);
	}

	std::cout << serial;

}

效果:

image


评论