共计 1625 个字符,预计需要花费 5 分钟才能阅读完成。
Crackme026 的逆向分析
1. 程序观察
程序提示用户名至少要有 5 个字符。
如果序列号错误,name 的输入框会闪一下,但没有弹窗提示。
2. 简单查壳
程序使用 VB5 编写,没有壳。
3. 程序分析
因为程序是使用 VB5 写的,所以我们先使用 VB Decompiler 看一下
可以看到,有两个点击事件,程序也有两个功能按钮。
使用 OD 载入程序,转到地址 402B10 处。下断点,点击 check 按钮,程序断在了 402B10。所以该段代码应该就是验证的代码。
继续向下看代码
1.
程序求得输入 name 的长度,如果小于 5 个字符,就会出现上面出现的提示弹窗。
2.
程序建立循环,循环次数为用户名的长度。
程序获取用户名第 i 位的 ASCII 值。
i 为循环次数,如果是第一次循环,就获取用户名第 1 位的 ASCII 值,也就是 name[0] 的 ASCII 值。
程序将字符串 432.4 转化为浮点数,再将 ASCII(name[i-1]) 转化为浮点数,两数相乘,再乘以浮点数 17.79。
也就是 432.5 * ASCII(name[i-1]) * 17.79
程序将上面的结果除以 15,也就是 (432.5 * ASCII(name[i-1]) * 17.79) /15
然后再将结果转化为字符串。
至此,一个循环结束。
3.
将最后一次循环的结果转化为浮点数,去除小数点后部分,然后再转化为字符串。
4.
程序取 name 首字符的 ASCII 值,转化为浮点数;再将 3. 的结果转化为浮点数,两者相加。
5.
取 name 首字符的 ASCII 值,乘以 0x19。
再将 3. 的结果转化为浮点数,减去上一步骤的结果,再转化为十六进制值。
6.
将 3. 的结果转化为十六进制。
7.
取 name[0] 的 ASCII 值,乘以 name 的长度,再减去 0x1B。
8.
将 4. 和 5. 拼接在一起。
将上面拼接的结果和 6. 的结果拼接在一起。
将上面拼接的结果和 7. 的结果拼接在一起。
将 name 的长度转化为字符串,和上面拼接的结果拼接在一起。
将上面拼接的结果和 “-CM” 拼接在一起。
最后进行比较
4. 注册机
#include <stdio.h>
#include <string.h>
#include <Windows.h>
int Keygen()
{char szName[20] = {0};
char szSerial[100] = {0};
char szSerial1[20] = {0};
int NameLen = 0;
__int64 Result = 0;
__int64 Result1 = 0;
printf("请输入用户名:");
scanf_s("%s", szName, 20);
NameLen = strlen(szName);
Result = (szName[NameLen - 1] * 432.4 * 17.79)/15;
Result1 = szName[0] + Result;
sprintf(szSerial1, "%I64d", Result1);
strcat(szSerial, szSerial1);
Result1 = Result - szName[0] * 0x19;
sprintf(szSerial1, "%I64X", Result1);
strcat(szSerial, szSerial1);
sprintf(szSerial1, "%I64X", Result);
strcat(szSerial, szSerial1);
Result1 = szName[0] * 0x5 - 0x1B;
sprintf(szSerial1, "%I64d", Result1);
strcat(szSerial, szSerial1);
Result1 = NameLen;
sprintf(szSerial1, "%I64d", Result1);
strcat(szSerial, szSerial1);
strcat(szSerial, "-CM");
printf("%s", szSerial);
return 0;
}
int main(int argc, char* argv[])
{Keygen();
return 0;
}
相关文件在我的 Github