Mercurial > pidgin.yaz
diff libpurple/protocols/qq/qq_base.c @ 24069:dc112387190f
2008.09.29 - ccpaging <ccpaging(at)gmail.com>
* 'Check Password' function for protocol 2007/2008
author | SHiNE CsyFeK <csyfek@gmail.com> |
---|---|
date | Wed, 22 Oct 2008 14:41:13 +0000 |
parents | 87e61a85f5dd |
children | 832178d951ca |
line wrap: on
line diff
--- a/libpurple/protocols/qq/qq_base.c Wed Oct 22 14:40:04 2008 +0000 +++ b/libpurple/protocols/qq/qq_base.c Wed Oct 22 14:41:13 2008 +0000 @@ -34,16 +34,13 @@ #include "qq_crypt.h" #include "group.h" #include "qq_define.h" +#include "qq_network.h" #include "qq_base.h" #include "packet_parse.h" #include "qq.h" #include "qq_network.h" #include "utils.h" -#define QQ_LOGIN_DATA_LENGTH 416 -#define QQ_LOGIN_REPLY_OK_PACKET_LEN 139 -#define QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN 11 - /* generate a md5 key using uid and session_key */ static void get_session_md5(guint8 *session_md5, guint32 uid, guint8 *session_key) { @@ -71,7 +68,13 @@ qd = (qq_data *) gc->proto_data; qq_show_packet("Login reply", data, len); - /* FIXME, check QQ_LOGIN_REPLY_OK_PACKET_LEN here */ + if (len < 139) { + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR, + _("Can not decrypt get server reply")); + return QQ_LOGIN_REPLY_ERR; + } + bytes = 0; bytes += qq_get8(&ret, data + bytes); bytes += qq_getdata(qd->session_key, sizeof(qd->session_key), data + bytes); @@ -134,11 +137,9 @@ tm_local->tm_hour, tm_local->tm_min, tm_local->tm_sec); /* unknow 9 bytes, 0x(00 0a 00 0a 01 00 00 0e 10) */ - if (bytes != QQ_LOGIN_REPLY_OK_PACKET_LEN) { /* fail parsing login info */ - purple_debug_warning("QQ", - "Fail parsing login info, expect %d bytes, read %d bytes\n", - QQ_LOGIN_REPLY_OK_PACKET_LEN, bytes); - } /* but we still go on as login OK */ + if (len > 139) { + purple_debug_warning("QQ", "Login reply more than expected %d bytes, read %d bytes\n", 139, bytes); + } return QQ_LOGIN_REPLY_OK; } @@ -155,6 +156,13 @@ } packet; + if (len < 11) { + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR, + _("Can not decrypt get server reply")); + return QQ_LOGIN_REPLY_ERR; + } + qd = (qq_data *) gc->proto_data; bytes = 0; /* 000-000: reply code */ @@ -166,11 +174,8 @@ /* 009-010: redirected new server port */ bytes += qq_get16(&packet.new_server_port, data + bytes); - if (bytes != QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN) { - purple_debug_error("QQ", - "Fail parsing login redirect packet, expect %d bytes, read %d bytes\n", - QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN, bytes); - return QQ_LOGIN_REPLY_ERR; + if (len > 11) { + purple_debug_error("QQ", "Login redirect more than expected %d bytes, read %d bytes\n", 11, bytes); } /* redirect to new server, do not disconnect or connect here @@ -239,15 +244,15 @@ g_return_if_fail(qd->ld.token != NULL && qd->ld.token_len > 0); - raw_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH); - memset(raw_data, 0, QQ_LOGIN_DATA_LENGTH); + raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16); + memset(raw_data, 0, MAX_PACKET_SIZE - 16); - encrypted = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16); /* 16 bytes more */ + encrypted = g_newa(guint8, MAX_PACKET_SIZE); /* 16 bytes more */ bytes = 0; /* now generate the encrypted data * 000-015 use password_twice_md5 as key to encrypt empty string */ - encrypted_len = qq_encrypt(encrypted, (guint8 *) "", 0, qd->ld.pwd_2nd_md5); + encrypted_len = qq_encrypt(encrypted, (guint8 *) "", 0, qd->ld.pwd_twice_md5); g_return_if_fail(encrypted_len == 16); bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len); @@ -270,8 +275,10 @@ /* 100 bytes unknown */ bytes += qq_putdata(raw_data + bytes, login_100_bytes, 100); /* all zero left */ + memset(raw_data + bytes, 0, 416 - bytes); + bytes = 416; - encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key); + encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.random_key); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); @@ -350,7 +357,7 @@ qd = (qq_data *) gc->proto_data; for (i = 0; i < 4; i++) - qq_send_cmd(gc, QQ_CMD_LOGOUT, qd->ld.pwd_2nd_md5, QQ_KEY_LENGTH); + qq_send_cmd(gc, QQ_CMD_LOGOUT, qd->ld.pwd_twice_md5, QQ_KEY_LENGTH); qd->is_login = FALSE; /* update login status AFTER sending logout packets */ } @@ -502,15 +509,19 @@ g_return_if_fail(gc != NULL && gc->proto_data != NULL); qd = (qq_data *) gc->proto_data; - raw_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH); - memset(raw_data, 0, QQ_LOGIN_DATA_LENGTH); + raw_data = g_newa(guint8, sizeof(qd->redirect_data)); + memset(raw_data, 0, sizeof(qd->redirect_data)); - encrypted = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16); /* 16 bytes more */ + encrypted = g_newa(guint8, sizeof(qd->redirect_data) + 16); /* 16 bytes more */ bytes = 0; - bytes += qq_putdata(raw_data + bytes, (guint8 *)&qd->redirect_data, sizeof(qd->redirect_data)); + bytes += qq_put16(raw_data + bytes, qd->redirect_data.ret); + bytes += qq_put8(raw_data + bytes, qd->redirect_data.b1); + bytes += qq_put32(raw_data + bytes, qd->redirect_data.w1); + bytes += qq_put32(raw_data + bytes, qd->redirect_data.w2); + bytes += qq_putIP(raw_data + bytes, &(qd->redirect_data.ip)); - encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key); + encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.random_key); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); @@ -519,34 +530,44 @@ bytes += qq_putdata(buf + bytes, encrypted, encrypted_len); qd->send_seq++; - qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE); + qq_send_cmd_encrypted(gc, QQ_CMD_GET_SERVER, qd->send_seq, buf, bytes, TRUE); } guint16 qq_process_get_server(PurpleConnection *gc, guint8 *data, gint data_len) { qq_data *qd; - qq_redirect_data *redirect; + gint bytes; g_return_val_if_fail (gc != NULL && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR); qd = (qq_data *) gc->proto_data; g_return_val_if_fail (data != NULL, QQ_LOGIN_REPLY_ERR); - if (data_len < sizeof(qq_redirect_data)) { - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Can not decrypt get server reply")); - return QQ_LOGIN_REPLY_ERR; - } - - redirect = (qq_redirect_data *)data; - if (redirect->ret == 0) { + + /* qq_show_packet("Get Server", data, data_len); */ + bytes = 0; + bytes += qq_get16(&qd->redirect_data.ret, data + bytes); + if (qd->redirect_data.ret == 0) { memset(&qd->redirect_data, 0, sizeof(qd->redirect_data)); qd->redirect_ip.s_addr = 0; return QQ_LOGIN_REPLY_OK; } - g_memmove(&qd->redirect_data, redirect, sizeof(qd->redirect_data)); - g_memmove(&qd->redirect_ip, &redirect->ip, sizeof(qd->redirect_ip)); + if (data_len < 15) { + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR, + _("Can not decrypt get server reply")); + return QQ_LOGIN_REPLY_ERR; + } + + bytes += qq_get8(&qd->redirect_data.b1, data + bytes); + bytes += qq_get32(&qd->redirect_data.w1, data + bytes); + bytes += qq_get32(&qd->redirect_data.w2, data + bytes); + bytes += qq_getIP(&qd->redirect_data.ip, data + bytes); + purple_debug_info("QQ", "Get server %d-%d-%d%d, %s\n", + qd->redirect_data.ret, qd->redirect_data.b1, qd->redirect_data.w1, qd->redirect_data.w2, + inet_ntoa(qd->redirect_data.ip)); + + g_memmove(&qd->redirect_ip, &qd->redirect_data.ip, sizeof(qd->redirect_ip)); return QQ_LOGIN_REPLY_REDIRECT; } @@ -577,7 +598,7 @@ bytes += qq_put8(raw_data + bytes, 0); /* fragment index */ bytes += qq_put16(raw_data + bytes, 0); /* captcha token */ - encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key); + encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.random_key); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); @@ -617,7 +638,7 @@ bytes += qq_put16(raw_data + bytes, qd->captcha.token_len); /* captcha token */ bytes += qq_putdata(raw_data + bytes, qd->captcha.token, qd->captcha.token_len); - encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key); + encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.random_key); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); @@ -662,7 +683,7 @@ bytes += qq_put16(raw_data + bytes, qd->captcha.token_len); /* captcha token */ bytes += qq_putdata(raw_data + bytes, qd->captcha.token, qd->captcha.token_len); - encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key); + encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.random_key); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); @@ -783,8 +804,8 @@ ret = data[0]; bytes = 0; - bytes += qq_get8(&sub_cmd, data + bytes); - bytes += 2; + bytes += qq_get8(&sub_cmd, data + bytes); /* 03: ok; 04: need verifying */ + bytes += 2; /* 0x(00 05) */ bytes += qq_get8(&reply, data + bytes); bytes += qq_get16(&(qd->ld.token_ex_len), data + bytes); @@ -794,7 +815,7 @@ if(reply != 1) { - purple_debug_info("QQ", "Captcha verified\n"); + purple_debug_info("QQ", "Captcha verified, result %d\n", reply); return QQ_LOGIN_REPLY_OK; } @@ -863,8 +884,9 @@ gint bytes; guint8 *encrypted; gint encrypted_len; + gint count; static guint8 header[] = { - 0x00, 0x5F, 0x00, 0x00, 0x08, 0x04, 0x01, 0x0E + 0x00, 0x5F, 0x00, 0x00, 0x08, 0x04, 0x01, 0xE0 }; g_return_if_fail(gc != NULL && gc->proto_data != NULL); @@ -879,39 +901,35 @@ /* Encrypted password and put in encrypted */ bytes = 0; - bytes += qq_putdata(raw_data + bytes, qd->ld.pwd_2nd_md5, sizeof(qd->ld.pwd_2nd_md5)); - bytes += qq_put16(raw_data + bytes, 0); - bytes += qq_put16(raw_data + bytes, 0); + bytes += qq_putdata(raw_data + bytes, qd->ld.pwd_md5, sizeof(qd->ld.pwd_md5)); + bytes += qq_put16(raw_data + bytes, rand() & 0); + bytes += qq_put16(raw_data + bytes, rand() & 0xffff); - encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_4th_md5); - + encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_twice_md5); /* create packet */ bytes = 0; bytes += qq_putdata(raw_data + bytes, header, sizeof(header)); /* token get from qq_process_token_ex */ - bytes += qq_put16(raw_data + bytes, qd->ld.token_ex_len); + bytes += qq_put8(raw_data + bytes, qd->ld.token_ex_len); bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len); /* password encrypted */ bytes += qq_put16(raw_data + bytes, encrypted_len); bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len); - /* some random data */ - bytes += qq_put16(raw_data + bytes, 0x0014); - bytes += qq_put32(raw_data + bytes, rand() & 0xffff); - bytes += qq_put32(raw_data + bytes, rand() & 0xffff); - bytes += qq_put32(raw_data + bytes, rand() & 0xffff); - bytes += qq_put32(raw_data + bytes, rand() & 0xffff); - bytes += qq_put32(raw_data + bytes, rand() & 0xffff); + /* random data, 20 bytes */ + bytes += qq_put16(raw_data + bytes, 0x0014); /* length of next segment*/ + count = 0x14; + while (count--) bytes += qq_put8(raw_data + bytes, rand() & 0xff); /* put length into first 2 bytes */ qq_put16(raw_data, bytes - 2); /* tail */ - bytes += qq_put8(raw_data + bytes, 0); - bytes += qq_put8(raw_data + bytes, 0x03); + bytes += qq_put8(raw_data + bytes, 0); /* length of next segment */ + bytes += qq_put8(raw_data + bytes, 0x03); /* length of next segment */ bytes += qq_put8(raw_data + bytes, 0); - bytes += qq_put8(raw_data + bytes, qd->ld.pwd_2nd_md5[1]); - bytes += qq_put8(raw_data + bytes, qd->ld.pwd_2nd_md5[2]); - + bytes += qq_put8(raw_data + bytes, qd->ld.pwd_md5[1]); + bytes += qq_put8(raw_data + bytes, qd->ld.pwd_md5[2]); + qq_show_packet("QQ", raw_data, bytes); /* Encrypted by random key*/ - encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key); + encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.random_key); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); @@ -920,7 +938,7 @@ bytes += qq_putdata(buf + bytes, encrypted, encrypted_len); qd->send_seq++; - qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE); + qq_send_cmd_encrypted(gc, QQ_CMD_CHECK_PWD, qd->send_seq, buf, bytes, TRUE); } guint8 qq_process_check_pwd_2007( PurpleConnection *gc, guint8 *data, gint data_len) @@ -960,7 +978,7 @@ switch (ret) { - case 0x34: /* invalid password */ + case 0x34: /* invalid password, 2nd byte is 0xc6 */ if (!purple_account_get_remember_password(gc->account)) { purple_account_set_password(gc->account, NULL); } @@ -987,13 +1005,13 @@ } qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len, ">>> [default] decrypt and dump"); - bytes = 1; + bytes = 11; bytes += qq_get16(&msg_len, data + bytes); msg = g_strndup((gchar *)data + bytes, msg_len); msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); - purple_debug_error("QQ", "%s: %s\n", error, msg_utf8); + purple_debug_error("QQ", "%s:\n%s\n", error, msg_utf8); purple_connection_error_reason(gc, reason, msg_utf8); g_free(error); @@ -1100,39 +1118,37 @@ /* Encrypted password and put in encrypted */ bytes = 0; - bytes += qq_putdata(raw_data + bytes, qd->ld.pwd_2nd_md5, sizeof(qd->ld.pwd_2nd_md5)); + bytes += qq_putdata(raw_data + bytes, qd->ld.pwd_md5, sizeof(qd->ld.pwd_md5)); bytes += qq_put16(raw_data + bytes, 0); - bytes += qq_put16(raw_data + bytes, (guint16) (rand() & 0xffff)); + bytes += qq_put16(raw_data + bytes, rand() & 0xffff); - encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_4th_md5); + encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_twice_md5); /* create packet */ bytes = 0; bytes += qq_putdata(raw_data + bytes, header, sizeof(header)); /* token get from qq_request_token_ex */ - bytes += qq_put16(raw_data + bytes, qd->ld.token_ex_len); + bytes += qq_put8(raw_data + bytes, qd->ld.token_ex_len); bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len); - bytes += qq_put8(raw_data + bytes, 0); /* password encrypted */ bytes += qq_put16(raw_data + bytes, encrypted_len); bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len); - bytes += qq_put8(raw_data + bytes, 0); /* len of unknown + len of CRC32 */ - bytes += qq_put8(raw_data + bytes, sizeof(unknown) + 4); + bytes += qq_put16(raw_data + bytes, sizeof(unknown) + 4); bytes += qq_putdata(raw_data + bytes, unknown, sizeof(unknown)); bytes += qq_put32( raw_data + bytes, crc32(0xFFFFFFFF, unknown, sizeof(unknown))); /* put length into first 2 bytes */ qq_put16(raw_data, bytes - 2); /* tail */ - bytes += qq_put8(raw_data + bytes, 0); - bytes += qq_put8(raw_data + bytes, 0x03); + bytes += qq_put16(raw_data + bytes, 0x0003); bytes += qq_put8(raw_data + bytes, 0); - bytes += qq_put8(raw_data + bytes, qd->ld.pwd_2nd_md5[1]); - bytes += qq_put8(raw_data + bytes, qd->ld.pwd_2nd_md5[2]); + bytes += qq_put8(raw_data + bytes, qd->ld.pwd_md5[1]); + bytes += qq_put8(raw_data + bytes, qd->ld.pwd_md5[2]); + qq_show_packet("Check password", raw_data, bytes); /* Encrypted by random key*/ - encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key); + encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.random_key); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); @@ -1141,7 +1157,7 @@ bytes += qq_putdata(buf + bytes, encrypted, encrypted_len); qd->send_seq++; - qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE); + qq_send_cmd_encrypted(gc, QQ_CMD_CHECK_PWD, qd->send_seq, buf, bytes, TRUE); } void qq_request_login_2007(PurpleConnection *gc) @@ -1184,11 +1200,11 @@ /* Encrypted password and put in encrypted */ bytes = 0; - bytes += qq_putdata(raw_data + bytes, qd->ld.pwd_2nd_md5, sizeof(qd->ld.pwd_2nd_md5)); + bytes += qq_putdata(raw_data + bytes, qd->ld.pwd_md5, sizeof(qd->ld.pwd_md5)); bytes += qq_put16(raw_data + bytes, 0); bytes += qq_put16(raw_data + bytes, 0xffff); - encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_4th_md5); + encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_twice_md5); /* create packet */ bytes = 0; @@ -1196,8 +1212,8 @@ /* password encrypted */ bytes += qq_put16(raw_data + bytes, encrypted_len); bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len); - /* put data which NULL string encrypted by key pwd_4th_md5 */ - encrypted_len = qq_encrypt(encrypted, (guint8 *) "", 0, qd->ld.pwd_4th_md5); + /* put data which NULL string encrypted by key pwd_twice_md5 */ + encrypted_len = qq_encrypt(encrypted, (guint8 *) "", 0, qd->ld.pwd_twice_md5); g_return_if_fail(encrypted_len == 16); bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len); /* unknow fill */ @@ -1337,11 +1353,11 @@ /* Encrypted password and put in encrypted */ bytes = 0; - bytes += qq_putdata(raw_data + bytes, qd->ld.pwd_2nd_md5, sizeof(qd->ld.pwd_2nd_md5)); + bytes += qq_putdata(raw_data + bytes, qd->ld.pwd_md5, sizeof(qd->ld.pwd_md5)); bytes += qq_put16(raw_data + bytes, 0); bytes += qq_put16(raw_data + bytes, 0xffff); - encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_4th_md5); + encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_twice_md5); /* create packet */ bytes = 0; @@ -1350,8 +1366,8 @@ /* password encrypted */ bytes += qq_put16(raw_data + bytes, encrypted_len); bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len); - /* put data which NULL string encrypted by key pwd_4th_md5 */ - encrypted_len = qq_encrypt(encrypted, (guint8 *) "", 0, qd->ld.pwd_4th_md5); + /* put data which NULL string encrypted by key pwd_twice_md5 */ + encrypted_len = qq_encrypt(encrypted, (guint8 *) "", 0, qd->ld.pwd_twice_md5); g_return_if_fail(encrypted_len == 16); bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len); /* unknow 19 bytes zero filled*/