QQ登录协议安全性分析和改进
如上面所述,具体的上下文请参考上面的那篇日志,这里就不再累赘了。
为了方便起见,我们使用“上文”来代替上面提到的那篇日志。
对于QQ登陆协议中由客户端生成的密钥ck采用如下例程:
int fillrandom (char *buffer, const int size) {
int i;
for(i = 0; i < size; i++) buffer[i] = rand() & 0xff;
}
因此,由上文可知,ck应该在random.bin中出现的,而random.bin大小为16M。于是可以直接生成random.bin文件,使用类似下面的这个函数
//buffer大小至少为16M
int generate_random (char *buffer) {
return fillrandom(buffer, 16<<20);
}
然后直接将buffer的内容保存到文件random.bin就可以了。
进一步,我们发现,临时密钥tk和ck之间存在某种偏移量的关系,而tk是可以直接从数据包中得到的。于是我们可以这样做,就是搜索找到tk在random.bin的偏移量,然后加16,得到的就是ck在random.bin中的偏移量了。
为了进一步提高这个效率,建议对random.bin进行排序,然后使用对半搜索的技巧,可以大大提高搜索的时间,具体的搜索算法可以参考《The Art of Computer Programming》。而这也是算法得以移植到资源受限设备上的关键之处。
下面这段仅供参考:(其实只要使用th的前5个字节就可以定位了,再加上3个字节刚好可以表示16M的地址空间,一共是8个字节,使用long long 或者__int64)
#define BLOCK_SIZE 0x200
#define BLOCK_16M 0x8000
#define BLOCK_COUNT BLOCK_16M
using namespace std;
static int status = 0;
void _srand(int seed)
{
//srand(seed);
status = seed;
}
int _rand()
{
//return rand();
return(((status = status * 214013L + 2531011L) >> 16) & 0x7fff);
}
#define TEST_LEN 5
#define TOTAL_BYTE (BLOCK_SIZE * BLOCK_16M)
unsigned char buffer[TOTAL_BYTE + TEST_LEN];
unsigned __int64 hash[TOTAL_BYTE];
int main()
{
int i, j;
_srand(1);
for(i = 0; i < TOTAL_BYTE; i++) {
buffer[i] = (unsigned char)(_rand() & 0xff);
}
//懒人啊,16M是一个周期,直接将前面的一段复制到后面,填满一个key的长度,这样就不用进行求余操作了。
for(i = 0; i < TEST_LEN; i++) buffer[TOTAL_BYTE + i] = buffer[i];
memset(hash, 0, sizeof(hash));
for(j = 0; j < TOTAL_BYTE; j++) {
memcpy((unsigned char*)(hash + j) + 3, buffer + j, TEST_LEN);//前5个字节作为key
hash[j] |= j & 0xffffff;//低三个字节保存key对应在random.bin中的偏移量作为value
}
sort(hash, hash + TOTAL_BYTE);//排序,前5个字节key决定了(key,value)的大小关系
//保存到文件
FILE *f = NULL;
f = fopen("sorted.bin", "wb");
fwrite(hash, sizeof(hash), 1, f);
fclose(f);
return 0;
}