原文:https://www.pediy.com/kssd/pediy11/123369.html
这个KeygenMe的验证过程主要就是:利用username计算出一个20字节的数据,然后利用lic的32字节的数据同样计算出一个20字节的数据,如果相同,那么就成功。
利用username计算出20字节的过程是一个正向的过程,直接剥代码就搞定,这道题目的关键就是怎样利用username计算出的20字节的数据推出lic,因为lic有32字节的数据。表明上看来这是一个不可能的事情,因为20字节到32字节是一个扩充的过程,可是只要仔细分析lic把32字节压缩成20字节的过程,这个逆向过程其实是很简单的。
由于username的组成限定了只能在“ABCDEFGHJKMNPQRSTVWXYZ1234567890”这32个中选择,然后根据查表得出值,这个值才是验证计算过程需要使用的数据。
这里需要特别注意一点,这个值最大不超过32,也就是最大值是5位。这就是这个压缩过程的关键所在。一个字节有8位,用8位来存储5位的值,有3位是空闲的,这个压缩过程就是将这空闲的3位全部利用起来。20/32正好等于5/8,这就是最好的证明。实际上这个压缩过程是没有任何数据损失的!!!
仔细分析lic压缩的过程,实际上就是一个精心构造的过程,把所有的空闲3字节都填上数据。下表就是利用5个字节存储8个字节的构造(注意,这8字节的数据每个值都不超过32),整个20字节就是将这个过程重复4次。表中每个单元格表示压缩后数组的一位。
1 2 3 4 5 6 7 8
(1-1 1-2 1-3 1-4 1-5) (2-1 2-2 2-3 第1字节
2-4 2-5) (3-1 3-2 3-3 3-4 3-5) (4-1 第2字节
4-2 4-3 4-4 4-5) (5-1 5-2 5-3 5-4 第3字节
5-5) (6-1 6-2 6-3 6-4 6-5) (7-1 7-2 第4字节
7-3 7-4 7-5) (8-1 8-2 8-3 8-4 8-5) 第5字节
注:1-1表示原始数据的第一个值的第一位。
只要了解了这个压缩过程,逆向过程就很好写出来了。只要逐字节额的拼凑,就可以利用20字节拼出所需要的32字节了,也就是需要计算出来的lic。!!!
好像好多人都死在这个BASE32编码算法上了
char *Base32(char *sha1,char *code,int len)
{
char base[]={"ABCDEFGHJKMNPQRSTVWXYZ1234567890"};
int length =(len*8+4)/5;
char* sb = code;
int cur_i = 0;
byte cur_b = 0;
int index;
int k;
for (int i = 0; i < length; i++)
{
index = 0;
for (int j = 0; j < 5; j++)
{
k = i * 5 + j;
if (k == len * 8)
break;
if (k % 8 == 0)
{
cur_b = *(BYTE*)(sha1+cur_i);
cur_i++;
}
index <<= 1;
index |= (cur_b & 128) == 0 ? 0 : 1;
cur_b <<= 1;
}
*(BYTE*)(code+i)=base[index];
}
return code;
}