头文件:
/**********************************************************************************************
* OICQ协议分析类
* version: 1.0
* author: yuzaobo
* description: OICQ分析是通过端口+特征码来实现的, 目前版本限定TCP连接Server端口为80或443,
UDP连接Server端口为8000。 每一个OICQ协议包均以0x02开头, 以0x03结尾。
由于OICQ协议包采用加密方式在网络上传输, 因此对OICQ的分析基于二进制码。
当OICQ命令为0x00 0xdd(数据包第四位、第五位), 数据方向为LAN2WAN时,
Client向Server发送帐号信息, 帐号由四个字节记录, 分别为数据包的8-11位
由此可以记录登录帐号。
----------------------------------------------
| key value |
| | | |
| local_accont session_key |
| packet_number local_account |
----------------------------------------------
***********************************************************************************************/
#ifndef _OICQ_ANALYSIS_H
#define _OICQ_ANALYSIS_H
#include <map>
#include "activeuser.h"
#include "netheaders.h"
#include "Crypter.h"
#include "decode.h"
#include "CDataBase.h"
#define OICQ_PASSWD_ERR 0x99 //??? This should lead to policy performing.
//#define MSG_ANSI // message saved as ascii, or comment it to use utf8
//define message type
#define TYPE_LOGIN 0
#define TYPE_FRIEND 1
#define TYPE_GROUP 2
using namespace std;
typedef struct tagSessionKey
{
BYTE skey[16];
}SessionKey, *pSessionKey;
typedef struct tagOicqPasswd
{
BYTE passwd[16];
}OicqPasswd, *pOicqPasswd;
typedef struct tagOicqInfo
{
char type; // message type: login: 0, friend: 1 and group: 2
ULONG local_account;
ULONG remote_account;
//char direct;
char content[20000];
} SOicqInfo, *PSOicqInfo;
class COicqAnalysis
{
public:
COicqAnalysis();
~COicqAnalysis();
int Run(const PIPHeader ip_header, const PTCPHeader tcp_header, const char* data, const int direct, \
Single_User_App_Details* suad, PSOicqInfo oicq_info);
int Run(const PIPHeader ip_header, const PUDPHeader udp_header, const char* data, const int direct, \
Single_User_App_Details* suad, PSOicqInfo oicq_info);
protected:
int _Run(const PIPHeader ip_header, const char* data, USHORT length, const int direct, Single_User_App_Details* suad, PSOicqInfo oicq_info);
map<ULONG, SessionKey> m_mapSessionKey; //STL map structure, store QQ session key info
map<unsigned __int64, ULONG>m_mapLocalAccount; //store local account info
map<ULONG, OicqPasswd>m_mapPassword;
map<ULONG, ULONG>m_mapGroupNumber; //group interior number -- group exterior number pair
};
#endif
CPP文件:
#include "OicqAnalysis.h"
COicqAnalysis::COicqAnalysis()
{
CDataBase* pDb = new CDataBase();
unsigned int count = 0;
while(!pDb->ExecuteSql("select * from nboicqaccount"))
{
if (++count > 5) // If it still failed after 5 times, exit
{
MessageBoxA(NULL, "ExecuteSql Error while get oicq account info!", "Error", MB_ICONERROR | MB_OK);
exit(1);
}
pDb->ExecuteSql("select * from nboicqaccount");
}
MYSQL_RES* res = pDb->StoreResult();
//int num_rows = (int)mysql_num_rows(res);
MYSQL_ROW row;
while (row = mysql_fetch_row(res))
{
OicqPasswd oicq_passwd;
char temp[3] = "";
for (int i = 0; i < 16; i++)
{
char* endptr;
temp[0] = row[1][2*i];
temp[1] = row[1][2*i+1];
oicq_passwd.passwd[i] = (BYTE)strtol(temp, &endptr, 16);
}
m_mapPassword.insert(map<ULONG, OicqPasswd>::value_type(atoi(row[0]), oicq_passwd));
}
pDb->FreeResult(res);
delete pDb;
}
COicqAnalysis::~COicqAnalysis()
{
}
//TCP
int COicqAnalysis::Run(const PIPHeader ip_header, const PTCPHeader tcp_header, const char *data, const int direct, Single_User_App_Details *suad, PSOicqInfo oicq_info)
{
if (suad->app_confirm != 2)
{
suad->analysis_count++;
}
if (suad->remote_port != 443/* && suad->remote_port != 80*/)
{
return USER_ERROR;
}
USHORT length = ip_header->length - ip_header->headerLength - tcp_header->headerLength;
USHORT real_length = ((UCHAR)data[0]<<8) + (UCHAR)data[1];
if (length != real_length)
{
return USER_ERROR;
}
const char* real_data = data + 2;
return _Run(ip_header, real_data, length-2, direct, suad, oicq_info);
}
//UDP
int COicqAnalysis::Run(const PIPHeader ip_header, const PUDPHeader udp_header, const char* data, const int direct, Single_User_App_Details* suad, PSOicqInfo oicq_info)
{
if (suad->app_confirm != 2)
{
suad->analysis_count++;
}
if (suad->remote_port != 8000)
{
return USER_ERROR;
}
suad->direct = APPDIR_EXTERIOR; //UDP, could not determine application direction by SYN and ACK
USHORT length = udp_header->length - 8;
return _Run(ip_header, data, length, direct, suad, oicq_info);
}
int COicqAnalysis::_Run(const PIPHeader ip_header, const char* data, USHORT length, const int direct, Single_User_App_Details* suad, PSOicqInfo oicq_info)
{
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// 0x00dd(密码验证), 0x00e5(获取登录信息), 0x30(登录验证, 获取用于整个会话过程的session key)
// 0x00cd(发送消息), 0x0017(接收消息)
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (data[0] == 0x02 && data[length-1] == 0x03) // OICQ packet start with 0x02 and end with 0x03
{
suad->app_id = APPID_QQ;
suad->app_confirm = 2;
/*************************************************************************************************
* Password verify(0x00dd): Client --> Server
*************************************************************************************************/
if (direct == LAN2WAN && data[3] == 0x00 && (UCHAR)data[4] == 0xdd)
{
//get random key
BYTE random_key[16] = "";
memcpy(random_key, &(data[11]), 16);
//decrypt
BYTE pbRet[2000] = "";
CCrypter crypter;
int out_len = crypter.Decrypt((BYTE*)data, 27, length-28, random_key, pbRet, 2000);
if (out_len <= 0)
{
OutputDebugStringA("0xdd(LAN2WAN) decrypt packet error.\n");
return USER_CONFIRM;
}
//get encrypted 0x78 bytes key
BYTE encrypted_key[120] = "";
memcpy(encrypted_key, &(pbRet[82]), 120);
//get password(2 times md5)
BYTE passwd_key[16] = "";
ULONG local_account = (((UCHAR)data[7])<<24) + (((UCHAR)data[8])<<16) + (((UCHAR)data[9])<<8) + (UCHAR)data[10];
map<ULONG, OicqPasswd>::iterator iter_passwd = m_mapPassword.find(local_account);
if (iter_passwd == m_mapPassword.end())
{
OutputDebugStringA("0xdd(LAN2WAN) Registered QQ password is incorrect!\n");
oicq_info->local_account = local_account; //alarm, should know QQ number
return OICQ_PASSWD_ERR;
}
else
{
memcpy(passwd_key, iter_passwd->second.passwd, 16);
}
//decrypt 0x78 bytes key
BYTE decrypted_key[104] = "";
out_len = crypter.Decrypt(encrypted_key, 0, 120, passwd_key, decrypted_key, 104);
if (out_len <= 0)
{
OutputDebugStringA("0xdd(LAN2WAN) decrypt 0x78 bytes key error\n");
oicq_info->local_account = local_account; //alarm, should know QQ number, ip can get from ip_header.source
return OICQ_PASSWD_ERR; //used for QQ alarm, thus disconnect user from internet
}
//and store it in m_mapSessionKey
SessionKey session_key;
memcpy(session_key.skey, &(decrypted_key[88]), 16);
map<ULONG, SessionKey>::iterator iter1 = m_mapSessionKey.find(local_account);
if (iter1 == m_mapSessionKey.end())
{
m_mapSessionKey.insert(map<ULONG, SessionKey>::value_type(local_account, session_key));
}
else //login, modify session key
{
iter1->second = session_key;
}
//store ip+port--local_account pair in m_mapLocalAccount
unsigned __int64 ip_port = (((unsigned __int64)(ip_header->source))<<32) + suad->local_port; // key = local_ip<<32 + local_ip; so that it's unique
map<unsigned __int64, ULONG>::iterator iter = m_mapLocalAccount.find(ip_port);
if (iter == m_mapLocalAccount.end())
{
m_mapLocalAccount.insert(map<unsigned __int64, ULONG>::value_type(ip_port, local_account));
}
else
{
iter->second = local_account;
//OutputDebugStringA("00xdd(LAN2WAN) packet_number conflict.\n");
}
return USER_CONFIRM;
}
/*************************************************************************************************
* Password verify(0x00dd): Server --> Client
*************************************************************************************************/
if (direct == WAN2LAN && data[3] == 0x00 && (UCHAR)data[4] == 0xdd)
{
//find local_account
ULONG local_account = 0;
unsigned __int64 ip_port = (((unsigned __int64)(ip_header->destination))<<32) + suad->local_port;
map<unsigned __int64, ULONG>::iterator iter1 = m_mapLocalAccount.find(ip_port);
if (iter1 == m_mapLocalAccount.end())
{
OutputDebugStringA("0xdd(WAN2LAN): find local_account error.\n");
return USER_CONFIRM;
}
else
{
local_account = iter1->second;
}
//find key
SessionKey session_key;
map<ULONG, SessionKey>::iterator iter2 = m_mapSessionKey.find(local_account);
if (iter2 == m_mapSessionKey.end())
{
OutputDebugStringA("0xdd(WAN2LAN): Read key by local_account error.\n");
return USER_CONFIRM;
}
else
{
session_key = iter2->second;
}
//decrypt packet
BYTE pbRet[2000] = "";
CCrypter crypter;
int out_len = crypter.Decrypt((BYTE*)data, 7, length-8, session_key.skey, pbRet, 2000);
if (out_len <= 0)
{
OutputDebugStringA("0xdd(WAN2LAN): decrypt error.\n");
return USER_CONFIRM;
}
//get key for next 0x00e5 and insert into m_mapSessionKey
memcpy(session_key.skey, &(pbRet[out_len-18]), 16);
map<ULONG, SessionKey>::iterator iter = m_mapSessionKey.find(local_account);
if (iter == m_mapSessionKey.end())
{
OutputDebugStringA("0xdd(WAN2LAN): Modify key by local_account error.\n");
return USER_CONFIRM;
}
else //login, modify session key
{
iter->second = session_key;
return USER_CONFIRM;
}
}
/*************************************************************************************************
* Login(0x00e5): Server --> Client
*************************************************************************************************/
if (direct == WAN2LAN && data[3] == 0x00 && (UCHAR)data[4] == 0xe5)
{
//find local_account
ULONG local_account = 0;
unsigned __int64 ip_port = (((unsigned __int64)(ip_header->destination))<<32) + suad->local_port;
map<unsigned __int64, ULONG>::iterator iter1 = m_mapLocalAccount.find(ip_port);
if (iter1 == m_mapLocalAccount.end())
{
OutputDebugStringA("0xe5(WAN2LAN): find local_account error.\n");
return USER_CONFIRM;
}
else
{
local_account = iter1->second;
}
//find key
SessionKey session_key;
map<ULONG, SessionKey>::iterator iter2 = m_mapSessionKey.find(local_account);
if (iter2 == m_mapSessionKey.end())
{
OutputDebugStringA("0xe5(WAN2LAN): Read key by local_account error.\n");
return USER_CONFIRM;
}
else
{
session_key = iter2->second;
}
//decrypt packet
BYTE pbRet[2000] = "";
CCrypter crypter;
int out_len = crypter.Decrypt((BYTE*)data, 7, length-8, session_key.skey, pbRet, 2000);
if (out_len <= 0)
{
OutputDebugStringA("0xe5(WAN2LAN): decrypt error.\n");
return USER_CONFIRM;
}
//get key for next 0x00e5 and insert into m_mapSessionKey
memcpy(session_key.skey, &(pbRet[4]), 16);
map<ULONG, SessionKey>::iterator iter = m_mapSessionKey.find(local_account);
if (iter == m_mapSessionKey.end())
{
OutputDebugStringA("0xe5(WAN2LAN): Modify key by local_account error.\n");
return USER_CONFIRM;
}
else //modify session key
{
iter->second = session_key;
return USER_CONFIRM;
}
}
/*************************************************************************************************
* Login Verify(0x0030): Server --> Client
*************************************************************************************************/
if (direct == WAN2LAN && data[3] == 0x00 && (UCHAR)data[4] == 0x30)
{
//find local_account
ULONG local_account = 0;
unsigned __int64 ip_port = (((unsigned __int64)(ip_header->destination))<<32) + suad->local_port;
map<unsigned __int64, ULONG>::iterator iter1 = m_mapLocalAccount.find(ip_port);
if (iter1 == m_mapLocalAccount.end())
{
OutputDebugStringA("0x30(WAN2LAN): find local_account error.\n");
return USER_CONFIRM;
}
else
{
local_account = iter1->second;
}
//find key
SessionKey session_key;
map<ULONG, SessionKey>::iterator iter2 = m_mapSessionKey.find(local_account);
if (iter2 == m_mapSessionKey.end())
{
OutputDebugStringA("0x30(WAN2LAN): Read key by local_account error.\n");
return USER_CONFIRM;
}
else
{
session_key = iter2->second;
}
//decrypt packet
BYTE pbRet[2000] = "";
CCrypter crypter;
int out_len = crypter.Decrypt((BYTE*)data, 7, length-8, session_key.skey, pbRet, 2000);
if (out_len <= 0)
{
OutputDebugStringA("0x30(WAN2LAN): decrypt error.\n");
return USER_CONFIRM;
}
//get session key and insert into m_mapSessionKey
memcpy(session_key.skey, &(pbRet[1]), 16);
map<ULONG, SessionKey>::iterator iter = m_mapSessionKey.find(local_account);
if (iter == m_mapSessionKey.end())
{
OutputDebugStringA("0x30(WAN2LAN): Modify key by local_account error.\n");
//return USER_CONFIRM;
}
else //modify session key
{
iter->second = session_key;
//return USER_CONFIRM;
}
//login succeed, return login info
oicq_info->type = TYPE_LOGIN;
oicq_info->local_account = local_account;
oicq_info->remote_account = 0;
strcpy(oicq_info->content, "<Login>");
return USER_SUCCEED;
}
/*************************************************************************************************
* Send Friend Message(0x00cd): Client --> Server
*************************************************************************************************/
if (direct == LAN2WAN && data[3] == 0x00 && (UCHAR)data[4] == 0xcd)
{
ULONG local_account = (((UCHAR)data[7])<<24) + (((UCHAR)data[8])<<16) + (((UCHAR)data[9])<<8) + (UCHAR)data[10];
map<ULONG, SessionKey>::iterator iter = m_mapSessionKey.find(local_account);
if (iter == m_mapSessionKey.end())
{
OutputDebugStringA("0xcd(LAN2WAN): Read key by local_account error.\n");
return USER_CONFIRM;
}
else //modify session key
{
BYTE pbRet[2000] = "";
CCrypter crypter;
int out_len = crypter.Decrypt((BYTE*)data, 11, length-12, iter->second.skey, pbRet, 2000);
if (out_len <= 0)
{
OutputDebugStringA("0xcd(LAN2WAN): decrypt error.\n");
return USER_CONFIRM; // should change another code, used for QQ alarm
}
if (out_len < 96)
{
OutputDebugStringA("0xcd(LAN2WAN):Invalid receive message.\n");
return USER_CONFIRM;
}
if (pbRet[11] == 0x08) //send to QQ2008
{
USHORT fontname_len = (pbRet[89]<<8) +pbRet[90];
if (pbRet[46] == 0x00 && pbRet[47] == 0x0b && pbRet[93+fontname_len] == 0x01)
{
ULONG remote_account = (pbRet[4]<<24) + (pbRet[5]<<16) + (pbRet[6]<<8) + pbRet[7];
oicq_info->type = TYPE_FRIEND;
oicq_info->local_account = local_account;
oicq_info->remote_account = remote_account;
USHORT message_len = (pbRet[97+fontname_len]<<8) +pbRet[98+fontname_len];
memset(oicq_info->content, 0, 2000);
memcpy(oicq_info->content, &(pbRet[99+fontname_len]), message_len);
#ifdef MSG_ANSI
CDeCode decoder;
decoder.Utf8ToGB2312(oicq_info->content, 1999);
decoder.ReplaceChar("'", "''", oicq_info->content, 1999);
decoder.ReplaceChar("\\", "\\\\", oicq_info->content, 1999);
#endif
return USER_SUCCEED;
}
else
{
return USER_CONFIRM;
}
}
else //send to QQ2009
{
USHORT len = (pbRet[20]<<8) +pbRet[21];
USHORT fontname_len = (pbRet[91+len]<<8) +pbRet[92+len];
if (pbRet[48+len] == 0x00 && pbRet[49+len] == 0x0b && pbRet[95+len+fontname_len] == 0x01)
{
ULONG remote_account = (pbRet[4]<<24) + (pbRet[5]<<16) + (pbRet[6]<<8) + pbRet[7];
oicq_info->type = TYPE_FRIEND;
oicq_info->local_account = local_account;
oicq_info->remote_account = remote_account;
USHORT message_len = (pbRet[99+len+fontname_len]<<8) +pbRet[100+len+fontname_len];
memset(oicq_info->content, 0, 2000);
memcpy(oicq_info->content, &(pbRet[101+len+fontname_len]), message_len);
#ifdef MSG_ANSI
CDeCode decoder;
decoder.Utf8ToGB2312(oicq_info->content, 1999);
decoder.ReplaceChar("'", "''", oicq_info->content, 1999);
decoder.ReplaceChar("\\", "\\\\", oicq_info->content, 1999);
#endif
return USER_SUCCEED;
}
else
{
return USER_CONFIRM;
}
}
}
}
/*************************************************************************************************
* Send Group Message(0x0002): Client --> Server
*************************************************************************************************/
if (direct == LAN2WAN && data[3] == 0x00 && (UCHAR)data[4] == 0x02)
{
ULONG local_account = (((UCHAR)data[7])<<24) + (((UCHAR)data[8])<<16) + (((UCHAR)data[9])<<8) + (UCHAR)data[10];
map<ULONG, SessionKey>::iterator iter = m_mapSessionKey.find(local_account);
if (iter == m_mapSessionKey.end())
{
OutputDebugStringA("0x02(LAN2WAN): Read key by local_account error.\n");
return USER_CONFIRM;
}
else //modify session key
{
BYTE pbRet[2000] = "";
CCrypter crypter;
int out_len = crypter.Decrypt((BYTE*)data, 11, length-12, iter->second.skey, pbRet, 2000);
if (out_len <= 0)
{
OutputDebugStringA("0x02(LAN2WAN): Could not decrypted, this may be caused by the error password.\n");
return USER_CONFIRM; // should change another code, used for QQ alarm
}
if (pbRet[0] == 0x72 && pbRet[1] == 0x00) //sub command: group info
{
ULONG interior_number = (pbRet[2]<<24) + (pbRet[3]<<16) + (pbRet[4]<<8) + pbRet[5]; //interior group number
ULONG exterior_number = (pbRet[6]<<24) + (pbRet[7]<<16) + (pbRet[8]<<8) + pbRet[9];
map<ULONG, ULONG>::iterator iter = m_mapGroupNumber.find(interior_number);
if (iter == m_mapGroupNumber.end())
{
m_mapGroupNumber.insert(map<ULONG, ULONG>::value_type(interior_number, exterior_number));
return USER_CONFIRM;
}
else
{
return USER_CONFIRM;
}
}
else if (pbRet[0] == 0x2a) //sub command: send message
{
if (pbRet[1] == 0x00) //result is 00
{
return USER_CONFIRM;
}
ULONG interior_number = (pbRet[1]<<24) + (pbRet[2]<<16) + (pbRet[3]<<8) + pbRet[4]; //interior group number
ULONG exterior_number = 0;
map<ULONG, ULONG>::iterator iter = m_mapGroupNumber.find(interior_number);
if (iter == m_mapGroupNumber.end())
{
OutputDebugStringA("0x02(LAN2WAN): Find exterior number by interior number error.\n");
//return USER_CONFIRM;
}
else
{
exterior_number = iter->second;
}
oicq_info->type = TYPE_GROUP;
oicq_info->local_account = local_account;
oicq_info->remote_account = exterior_number;
USHORT font_len = (pbRet[41]<<8) + pbRet[42];
USHORT content_len = (pbRet[49+font_len]<<8) + pbRet[50+font_len];
memset(oicq_info->content, 0, 2000);
memcpy(oicq_info->content, &(pbRet[51+font_len]), content_len);
#ifdef MSG_ANSI
CDeCode decoder;
decoder.Utf8ToGB2312(oicq_info->content, 1999);
decoder.ReplaceChar("'", "''", oicq_info->content, 1999);
decoder.ReplaceChar("\\", "\\\\", oicq_info->content, 1999);
#endif
return USER_SUCCEED;
}
else
{
return USER_CONFIRM; //other group command
}
}
}
/*************************************************************************************************
* Receive Message QQ2008 or Receive Group Message QQ2009(0x0017): Server --> Client
*************************************************************************************************/
if (direct == WAN2LAN && data[3] == 0x00 && (UCHAR)data[4] == 0x17)
{
//find local_account
ULONG local_account = 0;
unsigned __int64 ip_port = (((unsigned __int64)(ip_header->destination))<<32) + suad->local_port;
map<unsigned __int64, ULONG>::iterator iter1 = m_mapLocalAccount.find(ip_port);
if (iter1 == m_mapLocalAccount.end())
{
OutputDebugStringA("0x17(WAN2LAN): find local_account error.\n");
return USER_CONFIRM;
}
else
{
local_account = iter1->second;
}
//find key
SessionKey session_key;
map<ULONG, SessionKey>::iterator iter2 = m_mapSessionKey.find(local_account);
if (iter2 == m_mapSessionKey.end())
{
OutputDebugStringA("0x17(WAN2LAN): Read key by local_account error.\n");
return USER_CONFIRM;
}
else
{
session_key = iter2->second;
}
//decrypt packet
BYTE pbRet[2000] = "";
CCrypter crypter;
int out_len = crypter.Decrypt((BYTE*)data, 7, length-8, session_key.skey, pbRet, 2000);
if (out_len <= 0)
{
OutputDebugStringA("0x17(WAN2LAN): decrypt error.\n");
return USER_CONFIRM;
}
/*--------------------- Analysis module-------------------------------*/
//if (pbRet[24] == 0x12 && pbRet[25] == 0x21) //by version
if (pbRet[18] == 0x00 && pbRet[19] == 0x09) //QQ2008: Friend Message, by im type
{
if (out_len < 52)
{
OutputDebugStringA("0x17(WAN2LAN):Invalid receive message.\n");
return USER_CONFIRM;
}
USHORT len = (pbRet[22]<<8) +pbRet[23];
if (pbRet[50+len] == 0x00 && pbRet[51+len] == 0x0b && pbRet[69+len] != 0x14) //not face
{
ULONG remote_account = (pbRet[0]<<24) + (pbRet[1]<<16) + (pbRet[2]<<8) + pbRet[3];
oicq_info->type = TYPE_FRIEND;
oicq_info->local_account = local_account;
oicq_info->remote_account = remote_account;
memset(oicq_info->content, 0, 2000);
strcpy(oicq_info->content, (const char*)&(pbRet[69+len]));
#ifndef MSG_ANSI
CDeCode decoder;
decoder.GB2312ToUtf8(oicq_info->content, 1999);
decoder.ReplaceChar("'", "''", oicq_info->content, 1999);
decoder.ReplaceChar("\\", "\\\\", oicq_info->content, 1999);
#endif
return USER_SUCCEED;
}
else
{
return USER_CONFIRM;
}
}
else if (pbRet[18] == 0x00 && pbRet[19] == 0x2b) //QQ2008 Group message
{
if (out_len < 58)
{
OutputDebugStringA("0x17(WAN2LAN):Invalid receive group message.\n");
return USER_CONFIRM;
}
USHORT len = (pbRet[22]<<8) +pbRet[23];
ULONG remote_account = (pbRet[29]<<24) + (pbRet[30]<<16) + (pbRet[31]<<8) + pbRet[32];
if (remote_account == local_account) //filter
{
return USER_CONFIRM;
}
oicq_info->type = TYPE_GROUP;
oicq_info->local_account = local_account;
oicq_info->remote_account = remote_account;
memset(oicq_info->content, 0, 2000);
strcpy(oicq_info->content, (const char*)&(pbRet[57+len]));
#ifndef MSG_ANSI
CDeCode decoder;
decoder.GB2312ToUtf8(oicq_info->content, 1999);
decoder.ReplaceChar("'", "''", oicq_info->content, 1999);
decoder.ReplaceChar("\\", "\\\\", oicq_info->content, 1999);
#endif
return USER_SUCCEED;
}
else if (pbRet[18] == 0x00 && pbRet[19] == 0x52) //QQ2009: Group Message
{
if (out_len < 92)
{
OutputDebugStringA("0x17(WAN2LAN):Invalid receive group message.\n");
return USER_CONFIRM;
}
else
{
ULONG interior_number = (pbRet[0]<<24) + (pbRet[1]<<16) + (pbRet[2]<<8) + pbRet[3]; //interior group number
ULONG exterior_number = (pbRet[24]<<24) + (pbRet[25]<<16) + (pbRet[26]<<8) + pbRet[27];
//maintain interior-exterior map
map<ULONG, ULONG>::iterator iter = m_mapGroupNumber.find(interior_number);
if (iter == m_mapGroupNumber.end())
{
m_mapGroupNumber.insert(map<ULONG, ULONG>::value_type(interior_number, exterior_number));
}
oicq_info->type = TYPE_GROUP;
//ULONG local_account = (pbRet[4]<<24) + (pbRet[5]<<16) + (pbRet[6]<<8) + pbRet[7];
ULONG remote_account = (pbRet[29]<<24) + (pbRet[30]<<16) + (pbRet[31]<<8) + pbRet[32];
//oicq_info->local_account = exterior_number;
oicq_info->local_account = local_account;
//oicq_info->remote_account = exterior_number;
oicq_info->remote_account = remote_account;
if (remote_account == local_account) //filter
{
return USER_CONFIRM;
}
USHORT font_len = (pbRet[81]<<8) + pbRet[82];
USHORT content_len = (pbRet[89+font_len]<<8) + pbRet[90+font_len];
memset(oicq_info->content, 0, 2000);
memcpy(oicq_info->content, &(pbRet[91+font_len]), content_len);
#ifdef MSG_ANSI
CDeCode decoder;
decoder.Utf8ToGB2312(oicq_info->content, 1999);
decoder.ReplaceChar("'", "''", oicq_info->content, 1999);
decoder.ReplaceChar("\\", "\\\\", oicq_info->content, 1999);
#endif
return USER_SUCCEED;
}
}
else
{
return USER_CONFIRM;
}
}
/*************************************************************************************************
* Receive Friend Message QQ2009(0x00ce): Server --> Client
*************************************************************************************************/
if (direct == WAN2LAN && data[3] == 0x00 && (UCHAR)data[4] == 0xce)
{
//find local_account
ULONG local_account = 0;
unsigned __int64 ip_port = (((unsigned __int64)(ip_header->destination))<<32) + suad->local_port;
map<unsigned __int64, ULONG>::iterator iter1 = m_mapLocalAccount.find(ip_port);
if (iter1 == m_mapLocalAccount.end())
{
OutputDebugStringA("0x17(WAN2LAN): find local_account error.\n");
return USER_CONFIRM;
}
else
{
local_account = iter1->second;
}
//find key
SessionKey session_key;
map<ULONG, SessionKey>::iterator iter2 = m_mapSessionKey.find(local_account);
if (iter2 == m_mapSessionKey.end())
{
OutputDebugStringA("0x17(WAN2LAN): Read key by local_account error.\n");
return USER_CONFIRM;
}
else
{
session_key = iter2->second;
}
//decrypt packet
BYTE pbRet[2000] = "";
CCrypter crypter;
int out_len = crypter.Decrypt((BYTE*)data, 7, length-8, session_key.skey, pbRet, 2000);
if (out_len <= 0)
{
OutputDebugStringA("0x17(WAN2LAN): decrypt error.\n");
return USER_CONFIRM;
}
if (out_len < 98)
{
OutputDebugStringA("0x17(WAN2LAN):Invalid receive message.\n");
return USER_CONFIRM;
}
USHORT len = (pbRet[22]<<8) +pbRet[23];
USHORT fontname_len = (pbRet[93+len]<<8) +pbRet[94+len];
if (pbRet[18] == 0x00 && pbRet[19] == 0xa6 && pbRet[50+len] == 0x00 && pbRet[51+len] == 0x0b && pbRet[97+len+fontname_len] == 0x01)
{
ULONG remote_account = (pbRet[0]<<24) + (pbRet[1]<<16) + (pbRet[2]<<8) + pbRet[3];
oicq_info->type = TYPE_FRIEND;
oicq_info->local_account = local_account;
oicq_info->remote_account = remote_account;
memset(oicq_info->content, 0, 2000);
ULONG message_len = (pbRet[101+len+fontname_len]<<8) +pbRet[102+len+fontname_len];
memcpy(oicq_info->content, &(pbRet[103+len+fontname_len]), message_len);
#ifdef MSG_ANSI
CDeCode decoder;
decoder.Utf8ToGB2312(oicq_info->content, 1999);
decoder.ReplaceChar("'", "''", oicq_info->content, 1999);
decoder.ReplaceChar("\\", "\\\\", oicq_info->content, 1999);
#endif
return USER_SUCCEED;
}
else
{
return USER_CONFIRM;
}
}
//================================================================================================================================
return USER_CONFIRM; // OICQ protocol
}
else
{
return USER_ERROR; // not OICQ protocol
}
}
浙公网安备 33010602011771号