算法难度:⭐⭐⭐⭐
爆破难度:⭐
信息收集
运行情况:
查壳与脱壳:
无壳:
调试分析
首先看按钮的逻辑:
首先获取UserName,进行长度验证,然后获取Serial
接下来将获取的UserName和Serial作为参数,调用校验函数00427A20
如果得到的返回值是0x0BC614E则表示验证成功
接下来看这个校验函数:
首先是一些初始化操作,保存了参数到局部变量里
接下来对UserName进行处理:计算一个累加值
计算方法看注释,这里简述一下:
- 取一个字符到ebx
- ebx左移8位
- ebx进行或操作,或一个数组中的字符
- 如果ebx小于0了,则乘以-1
- 循环
最终将刚刚计算的值转换成字符串,计算字符串长度
这里的字符串长度就是接下来循环的次数,也就是这个累加值的位数
接下来的校验流程大概是:
- 取ebx的最后一位作为索引,从新的数组中获取一个字符
- 将新得到的字符拼接到正确序列号的字符串里
- 然后删去最后一位,回到步骤1
注册机
注册码生成算法:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
const char* arr = "LANNYDIBANDINGINANAKEKHYANGNGENTOT";
const char* arr2 = "LANNY5646521";
int main()
{
//char name[100] = { 0 };
char name[] = "selph";
char serial[100] = { 0 };
int len = 0;
int ebx = 0;
for (int i = 0;name[i]; i++)
{
ebx += name[i];
ebx <<= 8;
ebx |= arr[i];
if (ebx < 0) {
ebx *= -1;
}
}
ebx ^= 0x12345678;
for (int i = 0; ebx; i++)
{
serial[i] = arr2[ebx % 10];
ebx /= 10;
}
std::cout << serial << std::endl;
}
效果:
总结
比上一节看VB舒服多了,感觉这一节的难点在于分析理解这些反汇编是在干嘛的