void __cdecl sub_401130(unsigned long *base_a1, unsigned char *char_a2, signed int leng_a3)
{
int z = 0;
//unsigned long * key =(unsigned long *)char_a2;
unsigned long tmp =0;
unsigned long tmp_char = 0;
unsigned long key1=0, key2=0;// KEY初始为0
unsigned long *k1=&key1;
unsigned long *k2=&key2;
memcpy_s(base_a1 + 0x12, 0x1000 , mem_6198, 0x1000); //复制 00406198内存数据0x1000字节,无变动
//print_base(base_a1, 20);
for (int x = 0; x < 0x12; x++)
{
tmp = 0;
for (int y = 0; y <4; y++) //"94940361391"; //循环取字符串中4个字符组成一个DWORD值
{
if (z == leng_a3) z = 0;
tmp_char = 0+char_a2[z];
tmp_char = tmp_char << ((3 - y) * 8);
tmp |= tmp_char;
z++;
}
base_a1[x] = mem_6150[x] ^ tmp; //mem_6150 内存00406150数据,取48字节
}
//print_base(base_a1, 20);
z = 0;
for (int x = 0; x < 9; x++) //分9次用Key异或加密数据表头部,每次写入两个DWORD值,共18次,即0x48(72.)个字节
{
sub_401070(base_a1, k1, k2);
*(base_a1 + z) = *k1;
*(base_a1 + z + 1) = *k2;
z+=2;
}
//print_base(base_a1, 20);
for (int y = 0; y < 4; y++) //分4次,每次0x80(128),共0x200(512.)次,每次写入两个DWORD值,即0x1000(4096.)个字节
{
for (int x = 0; x < 0x80; x++)
{
sub_401070(base_a1, k1, k2);
*(base_a1 + z) = *k1;
*(base_a1 + z + 1) = *k2;
z += 2;
}
}
}
参考我代码后的备注可以看出,sub_401130函数的三个数参,unsigned long *base_a1这是一个固定的地址,实际是一个用于加密的数据表的指针, unsigned char *char_a2是用于对数据表中的数据进行加密的字符串,循环取字符串中4个字符组成一个DWORD值与数据表中数据异或加密,signed int leng_a3为传入的字符串的长度。在sub_401130中又调用了sub_401070,于是对sub_401070进行分析和代码还原,整理如下:
[C++] 纯文本查看复制代码
void sub_401070(unsigned long *base, unsigned long *k1, unsigned long *k2) //加密密钥Key1和Key2,不变更数据表
{
unsigned long tmp = *k1;
for (int x = 0; x < 0x10; x++)
{
*k1 ^= base[x];
tmp = *k1;
*k1 = sub_401000(base, tmp);
*k1 = *k1^*k2;
*k2 = tmp;
}
*k1 ^= *(base + 0x10) ;
*k2 ^= *(base + 0x11) ;
swap(*k1, *k2);
}
sub_401070有三个参数:unsigned long *base是数据表,另外还有 unsigned long *k1, unsigned long *k2,这是两个DWORD值,k1,k2,通过sub_401070子程序进行加密变换,sub_401070不变更数据表。在上面的sub_401130调用sub_401070,最初传入k1,k2值均为0,经sub_401070加密后得到的DWORD值,填充到数据表。所以说sub_401130是加密数据表的过程,sub_401070是加密KEY1和KEY2的过程。在sub_401070中调用了sub_401000函数,sub_401000还原代码如下:
i
void sub_4010D0(unsigned long *base, unsigned long *k1, unsigned long *k2) //对输入的key进行加密,与sub_401070极似
{
unsigned long tmp;
int s = 0x44 / 4;
for (int x = 0; x < 0x10; x++)
{
*k1 ^= base;
tmp = *k1; *k1 = sub_401000(base, tmp);
*k1 = *k1^*k2;
s--;
*k2 = tmp;
}
*k1 ^= *(base + 1);
*k2 ^= *base;
swap(*k1, *k2);
}
sub_4010D0接受三个参数,unsigned long *base,是引用数据表的指针, unsigned long *k1, unsigned long *k2是我们输入的Key1,key2,经sub_4010D0函数中对数据库数据异或操作加密后,与程序在初始过程中保存在[0x4099F0]和:[0x4099EC] 中两个DWORD值进行比较,如果一样,程序提示注册成功,不一样,则提示失败。通过以上分析后,我们将程序的流程进行还原整理,代码如下,这段代码中已包含了逆向找到直接Unlock code的部分: