主要基于des和aes-cbc-128算法。主要的坑:
- aes解密后头部16字节完全无用被丢弃。
- deflate解压。从头部2字节0x7801看出,压缩时的参数为速度最快算法。
- des密钥"ocularv3"
- aes密钥为: des解密后的包头第8字节开始的16字节,iv为16字节的0串。cbc算法会根据aes解密结果更新iv,所以iv会发生变化、但是无需干涉。
废话不说,上干货。
代码使用openssl库中的evp接口解密。
cpp
int __stdcall TcpClient(string ip,int port) {
int ret = 0;
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (s == INVALID_SOCKET) {
perror("socket\r\n");
return -1;
}
sockaddr_in sa = { 0 };
sa.sin_family = AF_INET;
sa.sin_addr.S_un.S_addr = inet_addr(ip.c_str());
sa.sin_port = ntohs(port);
ret = connect(s, (sockaddr*)&sa, sizeof(sockaddr_in));
if (ret < 0) {
perror("connect\r\n");
return -1;
}
int bufsize = 0x1000000;
char* sendbuf = new char[bufsize];
char* recvbuf= new char[bufsize];
DES_key_schedule key_schedule;
DES_cblock deskey;
memcpy((char*)deskey, "ocularv3", 8);
DES_set_key_unchecked(&deskey, &key_schedule);
unsigned char decryptbuf[0x1000] = { 0 };
unsigned char encryptbuf[0x1000] = { 0 };
int recvLen = 0;
char packetbuf[0x1000];
int packlen = makeFakePacket(packetbuf);
DWORD zipsize = packlen * 16;
unsigned char* zipbuf = new unsigned char[packlen + 1024];
ret=zcompress((Bytef*)packetbuf, packlen, zipbuf, (uLong*)&zipsize);
memcpy((Bytef*)sendbuf + 16 + sizeof(OCP_HEADER), zipbuf, zipsize);
int sendsize = zipsize+16;
OCP_HEADER* hdr = (OCP_HEADER*)sendbuf;
memset(hdr, 0, sizeof(OCP_HEADER));
for (int i = 0; i < 16; i++) {
sendbuf[8 + i] = 'A';
}
for (int i = 0; i < 16; i++) {
sendbuf[32 + i] = 'B';
}
hdr->tag = 0x4d4f;
hdr->payloadLen = sendsize;
hdr->flag = 0x4000|0x8000;
hdr->cmd = 0xc600;
const char* key = "ocularv3";
unsigned char iv[16] = { 0 };
char* indata = 0;
char* outdata = 0;
AESCBC128Encryptor aes_enc((unsigned char*)&hdr->field8, iv);
unsigned char aes_enc_buf[0x1000];
int aes_enc_len = aes_enc.update((unsigned char*)sendbuf + sizeof(OCP_HEADER), hdr->payloadLen, aes_enc_buf);
int aes_enc_last_len = aes_enc.final((unsigned char*)aes_enc_buf + aes_enc_len);
memcpy(sendbuf + sizeof(OCP_HEADER), aes_enc_buf, aes_enc_last_len + aes_enc_len);
sendsize = aes_enc_last_len + aes_enc_len;
hdr->payloadLen = aes_enc_last_len + aes_enc_len;
indata = (char*)&hdr->field8;
outdata = (char*)encryptbuf;
for (int i = 0; i < 3; i++) {
DES_ecb_encrypt((const_DES_cblock*)indata,
(DES_cblock*)outdata,
&key_schedule,
DES_ENCRYPT);
indata += 8;
outdata += 8;
}
memcpy((char*) & hdr->field8, encryptbuf, 24);
indata = (char*)encryptbuf;
outdata = (char*)decryptbuf;
for (int i = 0; i < 4; i++) {
DES_ecb_encrypt((const_DES_cblock*)indata,
(DES_cblock*)outdata,
&key_schedule,
DES_DECRYPT);
indata += 8;
outdata += 8;
}
AESCBC128Decryptor aes_dec((unsigned char*)decryptbuf, iv);
unsigned char aes_dec_buf[0x1000];
int aes_dec_len = aes_dec.update((unsigned char*)sendbuf + sizeof(OCP_HEADER), sendsize, aes_dec_buf);
int aes_dec_last_len = aes_dec.final((unsigned char*)aes_dec_buf + aes_dec_len);
ret = send(s, (char*)sendbuf, sendsize+sizeof(OCP_HEADER), 0);
recvLen = recv(s, recvbuf, bufsize-1, 0);
if (recvLen > 0 && recvLen < bufsize) {
recvbuf[recvLen] = 0;
int procLen = 0;
char* procBuf = recvbuf;
unsigned char* dstbuf = decryptbuf;
while(procLen < recvLen){
OCP_HEADER* hdr = (OCP_HEADER*)(procBuf);
if (hdr->flag & 0x4100) {
char* indata = (char*)&hdr->field8;
char* outdata = (char*)dstbuf + 8;
memcpy(dstbuf, procBuf, 8);
for (int i = 0; i < 3; i++) {
DES_ecb_encrypt((const_DES_cblock*)indata,
(DES_cblock*)outdata,
&key_schedule,
DES_DECRYPT);
indata += 8;
outdata += 8;
}
hdr = (OCP_HEADER*)dstbuf;
if (hdr->payloadLen) {
AESCBC128Decryptor aes_dec((unsigned char*)dstbuf + 8, iv);
unsigned char aes_dec_buf[0x1000];
int aes_dec_len = aes_dec.update((unsigned char*)procBuf + sizeof(OCP_HEADER), hdr->payloadLen, aes_dec_buf);
int aes_last_dec_len = aes_dec.final((unsigned char*)aes_dec_buf + aes_dec_len);
procLen += hdr->payloadLen;
}
procLen += sizeof(OCP_HEADER);
procBuf += procLen;
dstbuf += procLen;
}
}
}
closesocket(s);
delete [] sendbuf;
delete[] recvbuf;
return 0;
}