PCQQ official algorithm reverse

When analyzing the pcqq protocol, there is an official algorithm in the 0836 package. After many tests, it is found that if the algorithm is not available or wrong, the account will be frozen or blocked. In order to solve this problem, we need to reverse this algorithm
1. Use od debugging to find the assembly code of this algorithm as

mov eax, [ebp+0Ch]
mov eax, [eax]
add eax, 08h
push eax
mov edx, [ebp+08h]
mov edx, [edx]
add edx, 08h
mov ecx, [ebp+10h]
mov ecx, [ecx]
add ecx, 08h
call 00000024Ch

mov esp, ebp
pop ebp
retn 000Ch

sub esp, 14h
mov eax, [edx]
push ebx
mov [esp+14h], ecx
mov ebx, 00000010h
mov ecx, [esp+1Ch]
push ebp
push esi
mov esi, [edx+04h]
mov edx, [ecx+04h]
mov [esp+0Ch], edx
mov edx, [ecx]
mov ebp, [esp+0Ch]
mov [esp+10h], edx
mov edx, [ecx+0Ch]
mov ecx, [ecx+08h]
push edi
bswap esi
bswap eax
mov edi, 9E3779B9h
mov [esp+1Ch], edx
mov [esp+18h], ecx
mov edx, esi
mov ecx, esi
shr edx, 05h
shl ecx, 04h
add edx, ebp
add ecx, [esp+14h]
xor edx, ecx
lea ecx, [esi+edi]
xor edx, ecx
add eax, edx
mov edx, eax
mov ecx, eax
shl edx, 04h
add edx, [esp+18h]
shr ecx, 05h
add ecx, [esp+1Ch]
xor edx, ecx
lea ecx, [eax+edi]
xor edx, ecx
lea edi, [edi-61C88647h]
add esi, edx
dec ebx
jne 00000041h
mov ebp, [esp+20h]
bswap esi
pop edi
bswap eax
mov [ebp+04h], esi
mov [ebp+00h], eax
mov eax, ebp
pop esi
pop ebp
pop ebx
add esp, 14h
retn 0004h

2. The assembly is found, but how to call it in the code? The first method: vs can directly nest assembly code in the _asm{} block. But I don't know why the call 00000024h part reports an error, so I can only use the second method, which is to directly translate it into c source code.
3. At this time, I silently opened the fourth edition of Encryption and Decryption, which I bought from the Kanxue Forum, read two chapters, and then went straight to work. code show as below

// test.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"

typedef unsigned char BYTE;

BYTE* Long2Bytes(unsigned long n);
unsigned long Bytes2Long(BYTE *bytes);
BYTE* ReverseBytes(BYTE* data, int size);
void Official(BYTE *data, BYTE *key, BYTE *result);
BYTE* SubBytes(BYTE *bytes, int start, int count);
void PrintBytes(BYTE *bytes, int size);

int _tmain(int argc, _TCHAR* argv[])
{
    
    
	BYTE *data = new BYTE[8]{
    
    1, 2, 3, 4, 5, 6, 7, 8};//要加密的数据
	BYTE *key = new BYTE[16]{
    
    9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};//加密key
	BYTE *result = new BYTE[8]{
    
    0};//加密结果
	Official(data, key, result);
	PrintBytes(result,8);
	delete[] data;
	delete[] key;
	delete[] result;
	getchar();
	return 0;
}
void PrintBytes(BYTE *bytes, int size){
    
    
	for (int i = 0; i < size; i++){
    
    
		printf("%d ",bytes[i]);
	}
}
void Official(BYTE *data, BYTE *key, BYTE *result){
    
    
	unsigned long eax = Bytes2Long(SubBytes(data,0,4));
	unsigned long esi = Bytes2Long(SubBytes(data, 4, 4));
	unsigned long var4 = Bytes2Long(ReverseBytes(SubBytes(key, 0, 4), 4));
	unsigned long ebp = Bytes2Long(ReverseBytes(SubBytes(key, 4, 4), 4));
	unsigned long var3 = Bytes2Long(ReverseBytes(SubBytes(key, 8, 4), 4));
	unsigned long var2 = Bytes2Long(ReverseBytes(SubBytes(key, 12, 4), 4));
	//printf("%lu %lu %lu %lu %lu %lu\n", eax,esi,var4, ebp, var3, var2);

	unsigned long edi = 0x9E3779B9;
	unsigned long edx = 0;
	unsigned long ecx = 0;
	for (int i = 0; i < 16; i++){
    
    
		edx = esi;
		ecx = esi;
		edx = edx >> 5;
		ecx = ecx << 4;
		edx += ebp;
		ecx += var4;
		edx = edx ^ ecx;
		ecx = esi + edi;
		edx = edx ^ ecx;
		eax += edx;
		edx = eax;
		ecx = eax;
		edx = edx << 4;
		edx = edx + var3;
		ecx = ecx >> 5;
		ecx += var2;
		edx = edx ^ ecx;
		ecx = eax + edi;
		edx = edx ^ ecx;
		edi -= 0x61C88647;
		esi += edx;
	}
	memcpy(result,Long2Bytes(eax), 4);
	memcpy(result+4, Long2Bytes(esi), 4);
}
BYTE* Long2Bytes(unsigned long n){
    
    
	BYTE *temp = new BYTE[4];
	temp[0] = n / 16777216;
	temp[1] = (n - temp[0] * 16777216)/65536;
	temp[2] = (n - temp[0] * 16777216 - temp[1] * 65536) / 256;
	temp[3] = (n - temp[0] * 16777216 - temp[1] * 65536-temp[2]*256);
	return temp;
}
unsigned long Bytes2Long(BYTE *bytes){
    
    
	unsigned long a =bytes[0] * 16777216;
	unsigned long  b = bytes[1] * 65536;
	unsigned long  c = bytes[2] * 256;
	unsigned long  d = bytes[3];
	unsigned long  n = a + b + c + d;
	return n;
}
//因为数据在内存中是从低到高存放的,所以要反取字节
BYTE* ReverseBytes(BYTE* bytes, int size){
    
    
	BYTE *temp = new BYTE[size];
	for (int i = 0; i < size; i++){
    
    
		temp[i] = bytes[size - i - 1];
	}
	return temp;
}
BYTE* SubBytes(BYTE* bytes, int start, int count){
    
    
	BYTE *temp = new BYTE[count];
	for (int i = 0; i < count; i++){
    
    
		temp[i] = bytes[start + i];
	}
	return temp;
}

4. One thing to pay attention to here is that the number type must be unsigned long, otherwise the data will overflow, resulting in algorithm calculation errors... pit

Guess you like

Origin blog.csdn.net/a1663049254/article/details/88950926