头文件:
/********************************************************************************************** * 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 } }