介绍
该程序是一个面试题,主要目的是分析该软件做算法还原并且实现一个注册机。
话不多说,开始分析。
找到关键点
找关键点之前先观察软件,发现账号最高为8位,密码最高为24位。输入后点击注册没有提示信息及任何的反应。这时候,首先使用字符串搜索大法。找找是否有关键的字符串
有一个很明显的注册成功。
直接回车到该地址,找到函数头然后下断点。
关键算法预览
非常明显的三段算法
详细分析
关键点已经找全,接下来做细致的分析。然后写出对应的代码做出注册机
第一段
- 第一段总结:从0x30、0x42、0x62开始循环,每次按进制+1,循环26次。并且保存数组中(内存部分的值):str0_9[26]、stra_z[26]、strA_Z[26]
- 记好这三组值数组首地址。分别:ebp-0x864、ebp-0x844、ebp-0x884
- 后面算法取值的时候需要做一个偏移计算
判断账号和密码长度分析
第二段
第二段算法两个地址分别存放了两串奇怪的值,分别取出来做了异或计算的操作。这个地方很容易放过去。:xoruser[8]
- 第二段详细算法
第三段
第三段分为两个部分
- 第一个部分计算出三个下标。:key[3]
- 第二个部分又细分为3个小部分,从前面循环出的三组数据中取值。:passwd[24]
- 3.1部分
循环次数除以3取余,判断余数是否为2
- 3.2部分
判断余数是否为1
- 3.3部分
判断余数是否为0
代码实现
定义好数组
第一部分
按初始值0x30、0x42、0x62开始遍历26次。将结果分别存入数组内
第二部分
取两组奇怪的值做计算,结果放到xoruser[8]数组中。
第三部分
- 利用前面计算出的xoruser数组中的值计算出三个下标存入key[3]中
- 3.1-3.3根据key[]分别在三个数组中取值。循环8次每次取三个值放入passwd[]中
- 3.1部分
- 3.2部分
- 3.3部分
完整代码
#include <iostream>
#include <Windows.h>
char user[9] = {}; //账号
char str1 = 0x30;
char str2 = 0x42;
char str3 = 0x62;
char str0_9[26] = {}; //ebp - 0x864
char strA_Z[26] = {}; //ebp - 0x844
char stra_z[26] = {}; //ebp - 0x884
//奇怪字符
char str_temp[8] = {0x00,0x00,0x88, 0x85, 0xBB, 0xF7, 0xFF, 0xFF }; //00 00 88 85 BB F7 FF FF 第一串奇怪值
char str_temp1[8] = { 0xB8, 0x04, 0xFA, 0x42, 0x00, 0xE8, 0xAD, 0x13 }; //B8 04 FA 42 00 E8 AD 13 第二串奇怪值
//按账号计算出一组值
char xoruser[8] = {};
//根据前面计算结果,算出一个三位的下标
char key[3] = {};
char passwd[24] = {}; //密码存放数组 ebp - 8A0
int main()
{
printf("请输入一个8位账号:\n");
scanf_s("%s",&user,9);
for (int i = 0; i < 26; i++)
{
str0_9[i] = str1 + i;
strA_Z[i] = str2 + i;
stra_z[i] = str3 + i;
}
for (int i = 0; i < 8; i++)
{
char temp,temp1;
temp = user[i] ^ i;
temp1 = temp ^ str_temp[i];
xoruser[i] = str_temp1[i] ^ temp1; //ecx = temp ^ str_temp[i]
}
for (int j = 0; j < 8; j++)
{
char temp, temp1, temp2;
temp = xoruser[j] & 0xE0;
temp1 = (temp) & 0x1F;
temp2 = temp + temp1;
key[0] = ((temp2 & 0xff) >> 0x5); // key[0] = ((xoruser[i]&0xE0) + ((xoruser[i] & 0xE0)&0x1F)) >> 5
temp = xoruser[j] & 0x1C;
temp1 = ((temp) & 0x3);
key[2] = ((temp + temp1) & 0xFF) >> 2; //key[2] = (((xoruser[i] & 0x1C) & 0x3) + (xoruser[i] & 0x1C)) >> 2
key[1] = xoruser[j] & 0x3; //key[1] = xoruser[i] & 0x3
char count_temp1, count_temp2; //临时变量
if (j % 3 == 2)
{
count_temp1 = str0_9[0] + key[1];
count_temp2 = (j * 3);
passwd[count_temp2] = count_temp1; //passwd[0] + i*3 = str0_9[key[1]]
count_temp1 = strA_Z[8 + key[0]];
count_temp2 = (1 + (j * 3));
passwd[count_temp2] = count_temp1; //passwd[1]+i*3 = strA_Z[8] + key[0]
count_temp1 = stra_z[16 + key[2]];
count_temp2 = (2 + (j * 3));
passwd[count_temp2] = count_temp1; //passwd[2] + i *3 =stra_z[16] + key[2]
}
else if (j % 3 == 1) {
count_temp1 = strA_Z[16 + key[0]];
count_temp2 = j * 3;
passwd[count_temp2] = count_temp1; //passwd[i*3]=strA_Z[16 + key[0]]
count_temp1 = stra_z[8 + key[2]];
count_temp2 = (1 + (j * 3));
passwd[count_temp2] = count_temp1; //passwd[1] + i*3 = stra_z[8] + key[2]
count_temp1 = str0_9[key[1]];
count_temp2 = (2 + (j * 3));
passwd[count_temp2] = count_temp1; //passwd[2] + i*3 = str0_9[key[1]]
}
else if (j % 3 == 0) {
count_temp1 = strA_Z[16 + key[2]];
count_temp2 = j * 3;
passwd[count_temp2] = count_temp1; //passwd[0] + i *3 = strA_Z[16] + key[2]
count_temp1 = stra_z[8 + key[1]];
count_temp2 = (1 + (j * 3));
passwd[count_temp2] = count_temp1; //passwd[1] + i *3 =stra_z[8] + key[1]
count_temp1 = str0_9[key[0]];
count_temp2 = (2 + (j * 3));
passwd[count_temp2] = count_temp1; //passwd[2] + i * 3 = str0_9[0] + key[0]
}
}
printf("密钥为:%s\n",passwd);
system("pause");
}
验证
总结
- 总的算法:对三个初始值做循环,遍历出三组数据分别存入三个数组内。取两组奇怪的值分别做异或运算将结果保存。利用异或的结果计算出三个下标,拿这三个值又做三次运算。将运算的结果去前面三个数组内取值。最终生成一个24位密钥
- 在逆向这种环环相扣的算法时,每个关键数据和数组的起始地址位置都该记录下来。逆向的耐心很重要,一些地方该逆还得逆。躲不了…
- Crack地址:https://pan.baidu.com/s/1MfEAt4ydCXNriBLOL3JL8A
提取码:6lv6