comparison libpurple/protocols/qq/qq_base.c @ 24137:87e61a85f5dd

2008.09.28 - ccpaging <ccpaging(at)gmail.com> * The source is only for debug, not for user: 1. Implement new QQ protocol 2007/2008, include login and change status 2. Check 2005's login reply packet, get last 3 login time. 3. Server's notice and news is displayed in self buddy (The new buddy created in buddy list). 4. The notice messages when adding/removing QQ Qun's buddy displayed in char conversation. They are displayed as purple notify windows in the past. 5. The notice messages when adding/removing buddy displayed in self buddy's conversation. They are displayed as purple notify windows in the past. 6. Client version can be selected in account option. Now only qq2005 is working, other new version is only for debug.
author SHiNE CsyFeK <csyfek@gmail.com>
date Wed, 22 Oct 2008 14:40:04 +0000
parents dbc7a9742f8d
children dc112387190f
comparison
equal deleted inserted replaced
24136:fc546485fae7 24137:87e61a85f5dd
57 } 57 }
58 58
59 /* process login reply which says OK */ 59 /* process login reply which says OK */
60 static gint8 process_login_ok(PurpleConnection *gc, guint8 *data, gint len) 60 static gint8 process_login_ok(PurpleConnection *gc, guint8 *data, gint len)
61 { 61 {
62 qq_data *qd;
62 gint bytes; 63 gint bytes;
63 qq_data *qd; 64
64 65 guint8 ret;
65 struct { 66 guint32 uid;
66 guint8 result; 67 struct in_addr ip;
67 guint8 session_key[QQ_KEY_LENGTH]; 68 guint16 port;
68 guint32 uid; 69 struct tm *tm_local;
69 struct in_addr client_ip; /* those detected by server */ 70
70 guint16 client_port; 71 qd = (qq_data *) gc->proto_data;
71 struct in_addr server_ip; 72 qq_show_packet("Login reply", data, len);
72 guint16 server_port; 73
73 time_t login_time;
74 guint8 unknown1[26];
75 struct in_addr unknown_server1_ip;
76 guint16 unknown_server1_port;
77 struct in_addr unknown_server2_ip;
78 guint16 unknown_server2_port;
79 guint16 unknown2; /* 0x0001 */
80 guint16 unknown3; /* 0x0000 */
81 guint8 unknown4[32];
82 guint8 unknown5[12];
83 struct in_addr last_client_ip;
84 time_t last_login_time;
85 guint8 unknown6[8];
86 } packet;
87
88 qd = (qq_data *) gc->proto_data;
89 /* FIXME, check QQ_LOGIN_REPLY_OK_PACKET_LEN here */ 74 /* FIXME, check QQ_LOGIN_REPLY_OK_PACKET_LEN here */
90 bytes = 0; 75 bytes = 0;
91 76 bytes += qq_get8(&ret, data + bytes);
92 /* 000-000: reply code */ 77 bytes += qq_getdata(qd->session_key, sizeof(qd->session_key), data + bytes);
93 bytes += qq_get8(&packet.result, data + bytes); 78 get_session_md5(qd->session_md5, qd->uid, qd->session_key);
94 /* 001-016: session key */
95 bytes += qq_getdata(packet.session_key, sizeof(packet.session_key), data + bytes);
96 purple_debug_info("QQ", "Got session_key\n"); 79 purple_debug_info("QQ", "Got session_key\n");
97 /* 017-020: login uid */ 80 bytes += qq_get32(&uid, data + bytes);
98 bytes += qq_get32(&packet.uid, data + bytes); 81 if (uid != qd->uid) {
99 /* 021-024: server detected user public IP */ 82 purple_debug_warning("QQ", "My uid in login reply is %d, not %d\n", uid, qd->uid);
100 bytes += qq_getIP(&packet.client_ip, data + bytes); 83 }
101 /* 025-026: server detected user port */ 84 bytes += qq_getIP(&qd->my_ip, data + bytes);
102 bytes += qq_get16(&packet.client_port, data + bytes); 85 bytes += qq_get16(&qd->my_port, data + bytes);
103 /* 027-030: server detected itself ip 127.0.0.1 ? */ 86 purple_debug_info("QQ", "Internet IP: %s, %d\n", inet_ntoa(qd->my_ip), qd->my_port);
104 bytes += qq_getIP(&packet.server_ip, data + bytes); 87
105 /* 031-032: server listening port */ 88 bytes += qq_getIP(&qd->my_local_ip, data + bytes);
106 bytes += qq_get16(&packet.server_port, data + bytes); 89 bytes += qq_get16(&qd->my_local_port, data + bytes);
107 /* 033-036: login time for current session */ 90 purple_debug_info("QQ", "Local IP: %s, %d\n", inet_ntoa(qd->my_local_ip), qd->my_local_port);
108 bytes += qq_getime(&packet.login_time, data + bytes); 91
109 /* 037-062: 26 bytes, unknown */ 92 bytes += qq_getime(&qd->login_time, data + bytes);
110 bytes += qq_getdata((guint8 *) &packet.unknown1, 26, data + bytes); 93 tm_local = localtime(&qd->login_time);
111 /* 063-066: unknown server1 ip address */ 94 purple_debug_info("QQ", "Login time: %d-%d-%d, %d:%d:%d\n",
112 bytes += qq_getIP(&packet.unknown_server1_ip, data + bytes); 95 (1900 +tm_local->tm_year), (1 + tm_local->tm_mon), tm_local->tm_mday,
113 /* 067-068: unknown server1 port */ 96 tm_local->tm_hour, tm_local->tm_min, tm_local->tm_sec);
114 bytes += qq_get16(&packet.unknown_server1_port, data + bytes); 97 /* skip unknown 2 bytes, 0x(03 0a) */
115 /* 069-072: unknown server2 ip address */ 98 bytes += 2;
116 bytes += qq_getIP(&packet.unknown_server2_ip, data + bytes); 99 /* skip unknown 24 bytes, maybe token to access Qun shared files */
117 /* 073-074: unknown server2 port */ 100 bytes += 24;
118 bytes += qq_get16(&packet.unknown_server2_port, data + bytes); 101 /* unknow ip and port */
119 /* 075-076: 2 bytes unknown */ 102 bytes += qq_getIP(&ip, data + bytes);
120 bytes += qq_get16(&packet.unknown2, data + bytes); 103 bytes += qq_get16(&port, data + bytes);
121 /* 077-078: 2 bytes unknown */ 104 purple_debug_info("QQ", "Unknow IP: %s, %d\n", inet_ntoa(ip), port);
122 bytes += qq_get16(&packet.unknown3, data + bytes); 105 /* unknow ip and port */
123 /* 079-110: 32 bytes unknown */ 106 bytes += qq_getIP(&ip, data + bytes);
124 bytes += qq_getdata((guint8 *) &packet.unknown4, 32, data + bytes); 107 bytes += qq_get16(&port, data + bytes);
125 /* 111-122: 12 bytes unknown */ 108 purple_debug_info("QQ", "Unknow IP: %s, %d\n", inet_ntoa(ip), port);
126 bytes += qq_getdata((guint8 *) &packet.unknown5, 12, data + bytes); 109 /* unknown 4 bytes, 0x(00 81 00 00)*/
127 /* 123-126: login IP of last session */ 110 bytes += 4;
128 bytes += qq_getIP(&packet.last_client_ip, data + bytes); 111 /* skip unknown 32 bytes, maybe key to access QQ Home */
129 /* 127-130: login time of last session */ 112 bytes += 32;
130 bytes += qq_getime(&packet.last_login_time, data + bytes); 113 /* skip unknown 16 bytes, 0x(00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00) */
131 /* 131-138: 8 bytes unknown */ 114 bytes += 16;
132 bytes += qq_getdata((guint8 *) &packet.unknown6, 8, data + bytes); 115 /* time */
116 bytes += qq_getime(&qd->last_login_time[0], data + bytes);
117 tm_local = localtime(&qd->last_login_time[0]);
118 purple_debug_info("QQ", "Last login time: %d-%d-%d, %d:%d:%d\n",
119 (1900 +tm_local->tm_year), (1 + tm_local->tm_mon), tm_local->tm_mday,
120 tm_local->tm_hour, tm_local->tm_min, tm_local->tm_sec);
121 /* unknow time */
122 g_return_val_if_fail(sizeof(qd->last_login_time) / sizeof(time_t) > 1, QQ_LOGIN_REPLY_OK);
123 bytes += qq_getime(&qd->last_login_time[1], data + bytes);
124 tm_local = localtime(&qd->last_login_time[1]);
125 purple_debug_info("QQ", "Time: %d-%d-%d, %d:%d:%d\n",
126 (1900 +tm_local->tm_year), (1 + tm_local->tm_mon), tm_local->tm_mday,
127 tm_local->tm_hour, tm_local->tm_min, tm_local->tm_sec);
128
129 g_return_val_if_fail(sizeof(qd->last_login_time) / sizeof(time_t) > 2, QQ_LOGIN_REPLY_OK);
130 bytes += qq_getime(&qd->last_login_time[2], data + bytes);
131 tm_local = localtime(&qd->last_login_time[2]);
132 purple_debug_info("QQ", "Time: %d-%d-%d, %d:%d:%d\n",
133 (1900 +tm_local->tm_year), (1 + tm_local->tm_mon), tm_local->tm_mday,
134 tm_local->tm_hour, tm_local->tm_min, tm_local->tm_sec);
135 /* unknow 9 bytes, 0x(00 0a 00 0a 01 00 00 0e 10) */
133 136
134 if (bytes != QQ_LOGIN_REPLY_OK_PACKET_LEN) { /* fail parsing login info */ 137 if (bytes != QQ_LOGIN_REPLY_OK_PACKET_LEN) { /* fail parsing login info */
135 purple_debug_warning("QQ", 138 purple_debug_warning("QQ",
136 "Fail parsing login info, expect %d bytes, read %d bytes\n", 139 "Fail parsing login info, expect %d bytes, read %d bytes\n",
137 QQ_LOGIN_REPLY_OK_PACKET_LEN, bytes); 140 QQ_LOGIN_REPLY_OK_PACKET_LEN, bytes);
138 } /* but we still go on as login OK */ 141 } /* but we still go on as login OK */
139
140 memcpy(qd->session_key, packet.session_key, sizeof(qd->session_key));
141 get_session_md5(qd->session_md5, qd->uid, qd->session_key);
142
143 qd->my_ip.s_addr = packet.client_ip.s_addr;
144
145 qd->my_port = packet.client_port;
146 qd->login_time = packet.login_time;
147 qd->last_login_time = packet.last_login_time;
148 qd->last_login_ip = g_strdup( inet_ntoa(packet.last_client_ip) );
149
150 return QQ_LOGIN_REPLY_OK; 142 return QQ_LOGIN_REPLY_OK;
151 } 143 }
152 144
153 /* process login reply packet which includes redirected new server address */ 145 /* process login reply packet which includes redirected new server address */
154 static gint8 process_login_redirect(PurpleConnection *gc, guint8 *data, gint len) 146 static gint8 process_login_redirect(PurpleConnection *gc, guint8 *data, gint len)
253 encrypted = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16); /* 16 bytes more */ 245 encrypted = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16); /* 16 bytes more */
254 246
255 bytes = 0; 247 bytes = 0;
256 /* now generate the encrypted data 248 /* now generate the encrypted data
257 * 000-015 use password_twice_md5 as key to encrypt empty string */ 249 * 000-015 use password_twice_md5 as key to encrypt empty string */
258 encrypted_len = qq_encrypt(raw_data + bytes, (guint8 *) "", 0, qd->ld.pwd_2nd_md5); 250 encrypted_len = qq_encrypt(encrypted, (guint8 *) "", 0, qd->ld.pwd_2nd_md5);
259 g_return_if_fail(encrypted_len == 16); 251 g_return_if_fail(encrypted_len == 16);
260 bytes += encrypted_len; 252 bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len);
261 253
262 /* 016-016 */ 254 /* 016-016 */
263 bytes += qq_put8(raw_data + bytes, 0x00); 255 bytes += qq_put8(raw_data + bytes, 0x00);
264 /* 017-020, used to be IP, now zero */ 256 /* 017-020, used to be IP, now zero */
265 bytes += qq_put32(raw_data + bytes, 0x00000000); 257 bytes += qq_put32(raw_data + bytes, 0x00000000);
428 420
429 default: 421 default:
430 qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len, 422 qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len,
431 ">>> [default] decrypt and dump"); 423 ">>> [default] decrypt and dump");
432 error = g_strdup_printf( 424 error = g_strdup_printf(
433 _("Unknow reply code when checking password (0x%02X)"), 425 _("Unknow reply code when login (0x%02X)"),
434 ret ); 426 ret );
435 reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR; 427 reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
436 break; 428 break;
437 } 429 }
438 430
869 qq_data *qd; 861 qq_data *qd;
870 guint8 *buf, *raw_data; 862 guint8 *buf, *raw_data;
871 gint bytes; 863 gint bytes;
872 guint8 *encrypted; 864 guint8 *encrypted;
873 gint encrypted_len; 865 gint encrypted_len;
874 static guint8 header[] = { 0x00, 0x5F, 0x00, 0x00, 0x08, 0x04, 0x01, 0x0E }; 866 static guint8 header[] = {
867 0x00, 0x5F, 0x00, 0x00, 0x08, 0x04, 0x01, 0x0E
868 };
875 869
876 g_return_if_fail(gc != NULL && gc->proto_data != NULL); 870 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
877 qd = (qq_data *) gc->proto_data; 871 qd = (qq_data *) gc->proto_data;
878 872
879 g_return_if_fail(qd->ld.token != NULL && qd->ld.token_len > 0); 873 g_return_if_fail(qd->ld.token != NULL && qd->ld.token_len > 0);
892 encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_4th_md5); 886 encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_4th_md5);
893 887
894 /* create packet */ 888 /* create packet */
895 bytes = 0; 889 bytes = 0;
896 bytes += qq_putdata(raw_data + bytes, header, sizeof(header)); 890 bytes += qq_putdata(raw_data + bytes, header, sizeof(header));
897 /* token get from qq_request_token_ex */ 891 /* token get from qq_process_token_ex */
898 bytes += qq_put16(raw_data + bytes, qd->ld.token_ex_len); 892 bytes += qq_put16(raw_data + bytes, qd->ld.token_ex_len);
899 bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len); 893 bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len);
900 /* password encrypted */ 894 /* password encrypted */
901 bytes += qq_put16(raw_data + bytes, encrypted_len); 895 bytes += qq_put16(raw_data + bytes, encrypted_len);
902 bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len); 896 bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len);
1084 qq_data *qd; 1078 qq_data *qd;
1085 guint8 *buf, *raw_data; 1079 guint8 *buf, *raw_data;
1086 gint bytes; 1080 gint bytes;
1087 guint8 *encrypted; 1081 guint8 *encrypted;
1088 gint encrypted_len; 1082 gint encrypted_len;
1089 static guint8 header[] = { 0x00, 0x5F, 0x00, 0x00, 0x08, 0x04, 0x01, 0xE0 }; 1083 static guint8 header[] = {
1090 static guint8 unknown[] = { 0xDB, 0xB9, 0xF3, 0x0B, 0xF9, 0x13, 0x87, 0xB2, 1084 0x00, 0x5F, 0x00, 0x00, 0x08, 0x04, 0x01, 0xE0
1091 0xE6, 0x20, 0x43, 0xBE, 0x53, 0xCA, 0x65, 0x03 }; 1085 };
1086 static guint8 unknown[] = {
1087 0xDB, 0xB9, 0xF3, 0x0B, 0xF9, 0x13, 0x87, 0xB2,
1088 0xE6, 0x20, 0x43, 0xBE, 0x53, 0xCA, 0x65, 0x03
1089 };
1092 1090
1093 g_return_if_fail(gc != NULL && gc->proto_data != NULL); 1091 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
1094 qd = (qq_data *) gc->proto_data; 1092 qd = (qq_data *) gc->proto_data;
1095 1093
1096 g_return_if_fail(qd->ld.token != NULL && qd->ld.token_len > 0); 1094 g_return_if_fail(qd->ld.token != NULL && qd->ld.token_len > 0);
1144 1142
1145 qd->send_seq++; 1143 qd->send_seq++;
1146 qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE); 1144 qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE);
1147 } 1145 }
1148 1146
1149 /* 1147 void qq_request_login_2007(PurpleConnection *gc)
1150 static void qq_send_packet_login2007(PurpleConnection *gc) 1148 {
1151 { 1149 qq_data *qd;
1152 qq_data *qd; 1150 guint8 *buf, *raw_data;
1153 guint8 *buf, *cursor, *cursor_verify_data; 1151 gint bytes;
1154 guint16 seq_ret; 1152 guint8 *encrypted;
1155 gint encrypted_len, bytes; 1153 gint encrypted_len;
1156 gint pos, bodyOffset, encrypted_data_bytes, tail_offset, body_length, temp_pos; 1154 static const guint8 login_1_16[] = {
1157 guint8 verifyData[QQ_LOGIN_DATA_LENGTH], raw_data[QQ_LOGIN_ENCRYPT_BUFFER], encrypted_data[QQ_LOGIN_DATA_LENGTH]; 1155 0x56, 0x4E, 0xC8, 0xFB, 0x0A, 0x4F, 0xEF, 0xB3,
1158 1156 0x7A, 0x5D, 0xD8, 0x86, 0x0F, 0xAC, 0xE5, 0x1A
1159 memset(raw_data, 0, QQ_LOGIN_ENCRYPT_BUFFER); 1157 };
1160 memset(verifyData, 0, QQ_LOGIN_DATA_LENGTH); 1158 static const guint8 login_2_16[] = {
1161 memset(encrypted_data, 0, QQ_LOGIN_DATA_LENGTH); 1159 0x5E, 0x22, 0x3A, 0xBE, 0x13, 0xBF, 0xDA, 0x4C,
1162 qd = (qq_data *) gc->proto_data; 1160 0xA9, 0xB7, 0x0B, 0x43, 0x63, 0x51, 0x8E, 0x28
1161 };
1162 static const guint8 login_3_83[] = {
1163 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
1164 0x00, 0x00, 0x01, 0x40, 0x01, 0x01, 0x58, 0x83,
1165 0xD0, 0x00, 0x10, 0x9D, 0x14, 0x64, 0x0A, 0x2E,
1166 0xE2, 0x11, 0xF7, 0x90, 0xF0, 0xB5, 0x5F, 0x16,
1167 0xFB, 0x41, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00,
1168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1170 0x00, 0x00, 0x00, 0x00, 0x02, 0x76, 0x3C, 0xEE,
1171 0x4A, 0x00, 0x10, 0x86, 0x81, 0xAD, 0x1F, 0xC8,
1172 0xC9, 0xCC, 0xCF, 0xCA, 0x9F, 0xFF, 0x88, 0xC0,
1173 0x5C, 0x88, 0xD5
1174 };
1175 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
1176 qd = (qq_data *) gc->proto_data;
1177
1178 g_return_if_fail(qd->ld.token != NULL && qd->ld.token_len > 0);
1179
1180 raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16);
1181 memset(raw_data, 0, MAX_PACKET_SIZE - 16);
1182
1183 encrypted = g_newa(guint8, MAX_PACKET_SIZE); /* 16 bytes more */
1184
1185 /* Encrypted password and put in encrypted */
1186 bytes = 0;
1187 bytes += qq_putdata(raw_data + bytes, qd->ld.pwd_2nd_md5, sizeof(qd->ld.pwd_2nd_md5));
1188 bytes += qq_put16(raw_data + bytes, 0);
1189 bytes += qq_put16(raw_data + bytes, 0xffff);
1190
1191 encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_4th_md5);
1192
1193 /* create packet */
1194 bytes = 0;
1195 bytes += qq_put16(raw_data + bytes, 0);
1196 /* password encrypted */
1197 bytes += qq_put16(raw_data + bytes, encrypted_len);
1198 bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len);
1199 /* put data which NULL string encrypted by key pwd_4th_md5 */
1200 encrypted_len = qq_encrypt(encrypted, (guint8 *) "", 0, qd->ld.pwd_4th_md5);
1201 g_return_if_fail(encrypted_len == 16);
1202 bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len);
1203 /* unknow fill */
1204 memset(raw_data + bytes, 0, 19);
1205 bytes += 19;
1206 bytes += qq_putdata(raw_data + bytes, login_1_16, sizeof(login_1_16));
1207
1208 bytes += qq_put8(raw_data + bytes, (guint8)rand() & 0xff);
1209 bytes += qq_put8(raw_data + bytes, qd->login_mode);
1210 /* unknow 10 bytes zero filled*/
1211 memset(raw_data + bytes, 0, 10);
1212 bytes += 10;
1213 /* redirect data, 15 bytes */
1214 bytes += qq_putdata(raw_data + bytes, (guint8 *)&qd->redirect_data, sizeof(qd->redirect_data));
1215 /* unknow fill */
1216 bytes += qq_putdata(raw_data + bytes, login_2_16, sizeof(login_2_16));
1217 /* captcha token get from qq_process_token_ex */
1218 bytes += qq_put8(raw_data + bytes, qd->captcha.token_len);
1219 bytes += qq_putdata(raw_data + bytes, qd->captcha.token, qd->captcha.token_len);
1220 /* unknow fill */
1221 bytes += qq_putdata(raw_data + bytes, login_3_83, sizeof(login_3_83));
1222 memset(raw_data + bytes, 0, 332 - sizeof(login_3_83));
1223 bytes += 332 - sizeof(login_3_83);
1224
1225 encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.login_key);
1226
1163 buf = g_newa(guint8, MAX_PACKET_SIZE); 1227 buf = g_newa(guint8, MAX_PACKET_SIZE);
1164 1228 memset(buf, 0, MAX_PACKET_SIZE);
1165 cursor = buf; 1229 bytes = 0;
1166 bytes = 0; 1230 /* logint token get from qq_process_check_pwd_2007 */
1167 bytes += _create_packet_head_seq(buf, &cursor, gc, QQ_CMD_LOGIN, TRUE, &seq_ret); 1231 bytes += qq_put16(buf + bytes, qd->ld.login_token_len);
1168 bytes += create_packet_dw(buf, &cursor, qd->uid); 1232 bytes += qq_putdata(buf + bytes, qd->ld.login_token, qd->ld.login_token_len);
1169 1233 bytes += qq_putdata(buf + bytes, encrypted, encrypted_len);
1170 bodyOffset = bytes; 1234
1171 1235 qd->send_seq++;
1172 bytes += create_packet_w(buf, &cursor, qd->passport_key_lenght); 1236 qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE);
1173 bytes += create_packet_data(buf, &cursor, qd->passport_key, qd->passport_key_lenght); 1237 }
1174 bytes += create_packet_w(buf, &cursor, 0); 1238
1175 pos = bytes; 1239 /* process the login reply packet */
1176 bytes += 2; 1240 guint8 qq_process_login_2007( PurpleConnection *gc, guint8 *data, gint data_len)
1177 cursor += 2; 1241 {
1178 1242 qq_data *qd;
1179 encrypted_data_bytes = 0; 1243 gint bytes;
1180 cursor_verify_data = verifyData; 1244 guint8 ret;
1181 encrypted_data_bytes += create_packet_data(verifyData, &cursor_verify_data, qd->pwkey, QQ_KEY_LENGTH); 1245 gchar *error;
1182 encrypted_data_bytes += create_packet_b(verifyData, &cursor_verify_data, 0); 1246 guint32 uid;
1183 encrypted_data_bytes += create_packet_b(verifyData, &cursor_verify_data, 0); 1247
1184 encrypted_data_bytes += create_packet_b(verifyData, &cursor_verify_data, 255); 1248 g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR);
1185 encrypted_data_bytes += create_packet_b(verifyData, &cursor_verify_data, 255); 1249
1186 // encrypted_data_bytes += create_packet_w(verifyData, &cursor_verify_data, 0); 1250 qd = (qq_data *) gc->proto_data;
1187 1251
1188 qq_encrypt(verifyData, encrypted_data_bytes, qd->pwkey_double, encrypted_data, &encrypted_len); 1252 bytes = 0;
1189 bytes += create_packet_data(buf, &cursor, encrypted_data, encrypted_len); 1253 bytes += qq_get8(&ret, data + bytes);
1190 1254 if (ret != 0) {
1191 temp_pos = bytes; 1255 qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len,
1192 bytes = pos; 1256 ">>> [default] decrypt and dump");
1193 cursor = buf+bytes; 1257 error = g_strdup_printf(
1194 bytes += create_packet_w(buf, &cursor, encrypted_len); 1258 _("Unknow reply code when login (0x%02X)"),
1195 bytes = temp_pos; 1259 ret );
1196 cursor = buf+bytes; 1260 purple_connection_error_reason(gc,
1197 1261 PURPLE_CONNECTION_ERROR_OTHER_ERROR,
1198 qq_encrypt((guint8 *) "", 0, qd->pwkey_double, raw_data, &encrypted_len); 1262 error);
1199 bytes += create_packet_data(buf, &cursor, raw_data, encrypted_len); 1263 g_free(error);
1200 1264 return QQ_LOGIN_REPLY_ERR;
1201 g_memmove(buf+bytes, kQQFixedContent1_35, 35); 1265 }
1202 bytes += 35; 1266
1203 cursor = buf+bytes; 1267 bytes += qq_getdata(qd->session_key, sizeof(qd->session_key), data + bytes);
1204 1268 purple_debug_info("QQ", "Got session_key\n");
1205 bytes += create_packet_b(buf, &cursor, g_random_int_range (0,255)); 1269 get_session_md5(qd->session_md5, qd->uid, qd->session_key);
1206 bytes += create_packet_b(buf, &cursor, qd->login_mode); 1270
1207 1271 bytes += qq_get32(&uid, data + bytes);
1208 bytes += create_packet_dw(buf, &cursor, 0); 1272 if (uid != qd->uid) {
1209 bytes += create_packet_dw(buf, &cursor, 0); 1273 purple_debug_warning("QQ", "My uid in login reply is %d, not %d\n", uid, qd->uid);
1210 bytes += create_packet_w(buf, &cursor, 0); 1274 }
1211 1275 bytes += qq_getIP(&qd->my_ip, data + bytes);
1212 bytes += create_packet_data(buf, &cursor, qd->selected_server, qd->selected_server_lenght); 1276 bytes += qq_get16(&qd->my_port, data + bytes);
1213 1277 bytes += qq_getIP(&qd->my_local_ip, data + bytes);
1214 g_memmove(buf+bytes, kQQFixedContent2_16, 16); 1278 bytes += qq_get16(&qd->my_local_port, data + bytes);
1215 bytes += 16; 1279 bytes += qq_getime(&qd->login_time, data + bytes);
1216 cursor = buf+bytes; 1280 /* skip unknow 50 byte */
1217 1281 bytes += 50;
1218 bytes += create_packet_b(buf, &cursor, qd->login_token_lenght); 1282 /* skip client key 32 byte */
1219 bytes += create_packet_data(buf, &cursor, qd->login_token, qd->login_token_lenght); 1283 bytes += 32;
1220 1284 /* skip unknow 12 byte */
1221 g_memmove(buf+bytes, kQQFixedContent3_332, 332); 1285 bytes += 12;
1222 bytes += 332; 1286 /* last login */
1223 cursor = buf+bytes; 1287 bytes += qq_getIP(&qd->last_login_ip, data + bytes);
1224 1288 bytes += qq_getime(&qd->last_login_time[0], data + bytes);
1225 tail_offset = bytes; 1289 purple_debug_info("QQ", "Last Login: %s, %s\n",
1226 body_length = tail_offset - bodyOffset; 1290 inet_ntoa(qd->last_login_ip), ctime(&qd->last_login_time[0]));
1227 1291 return QQ_LOGIN_REPLY_OK;
1228 memset(raw_data, 0, QQ_LOGIN_ENCRYPT_BUFFER);
1229 encrypted_len = body_length;
1230 // qq_encrypt(buf+passport_length+2+11, body_length-passport_length-2 , qd->pwkey, raw_data, &encrypted_len);
1231 qq_encrypt(buf+qd->passport_key_lenght+2+11, body_length-qd->passport_key_lenght-2 , qd->login_key, raw_data, &encrypted_len);
1232 bytes = qd->passport_key_lenght+2+11;
1233 cursor = buf+bytes;
1234 bytes += create_packet_data(buf, &cursor, raw_data, encrypted_len);
1235 bytes += create_packet_b(buf, &cursor, QQ_PACKET_TAIL);
1236
1237 if (bytes == (cursor - buf)) // packet creation OK
1238 _qq_send_packet(gc, buf, bytes, QQ_CMD_LOGIN);
1239 else
1240 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail create login packet\n");
1241
1242 }
1243 */
1244 void qq_request_login_2007(PurpleConnection *gc)
1245 {
1246 } 1292 }
1247 1293
1248 void qq_request_login_2008(PurpleConnection *gc) 1294 void qq_request_login_2008(PurpleConnection *gc)
1249 { 1295 {
1250 } 1296 qq_data *qd;
1297 guint8 *buf, *raw_data;
1298 gint bytes;
1299 guint8 *encrypted;
1300 gint encrypted_len;
1301 guint8 index, count;
1302
1303 static const guint8 login_1_16[] = {
1304 0xD2, 0x41, 0x75, 0x12, 0xC2, 0x86, 0x57, 0x10,
1305 0x78, 0x57, 0xDC, 0x24, 0x8C, 0xAA, 0x8F, 0x4E
1306 };
1307
1308 static const guint8 login_2_16[] = {
1309 0x94, 0x0B, 0x73, 0x7A, 0xA2, 0x51, 0xF0, 0x4B,
1310 0x95, 0x2F, 0xC6, 0x0A, 0x5B, 0xF6, 0x76, 0x52
1311 };
1312 static const guint8 login_3_18[] = {
1313 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
1314 0x00, 0x00, 0x01, 0x40, 0x01, 0x1b, 0x02, 0x84,
1315 0x50, 0x00
1316 };
1317 static const guint8 login_4_16[] = {
1318 0x2D, 0x49, 0x15, 0x55, 0x78, 0xFC, 0xF3, 0xD4,
1319 0x53, 0x55, 0x60, 0x9C, 0x37, 0x9F, 0xE9, 0x59
1320 };
1321 static const guint8 login_5_6[] = {
1322 0x02, 0x68, 0xe8, 0x07, 0x83, 0x00
1323 };
1324 static const guint8 login_6_16[] = {
1325 0x3B, 0xCE, 0x43, 0xF1, 0x8B, 0xA4, 0x2B, 0xB5,
1326 0xB3, 0x51, 0x57, 0xF7, 0x06, 0x4B, 0x18, 0xFC
1327 };
1328 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
1329 qd = (qq_data *) gc->proto_data;
1330
1331 g_return_if_fail(qd->ld.token != NULL && qd->ld.token_len > 0);
1332
1333 raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16);
1334 memset(raw_data, 0, MAX_PACKET_SIZE - 16);
1335
1336 encrypted = g_newa(guint8, MAX_PACKET_SIZE); /* 16 bytes more */
1337
1338 /* Encrypted password and put in encrypted */
1339 bytes = 0;
1340 bytes += qq_putdata(raw_data + bytes, qd->ld.pwd_2nd_md5, sizeof(qd->ld.pwd_2nd_md5));
1341 bytes += qq_put16(raw_data + bytes, 0);
1342 bytes += qq_put16(raw_data + bytes, 0xffff);
1343
1344 encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_4th_md5);
1345
1346 /* create packet */
1347 bytes = 0;
1348 bytes += qq_put16(raw_data + bytes, 0); /* Unknow */
1349 bytes += qq_put8(raw_data + bytes, 0); /* Separator */
1350 /* password encrypted */
1351 bytes += qq_put16(raw_data + bytes, encrypted_len);
1352 bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len);
1353 /* put data which NULL string encrypted by key pwd_4th_md5 */
1354 encrypted_len = qq_encrypt(encrypted, (guint8 *) "", 0, qd->ld.pwd_4th_md5);
1355 g_return_if_fail(encrypted_len == 16);
1356 bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len);
1357 /* unknow 19 bytes zero filled*/
1358 memset(raw_data + bytes, 0, 19);
1359 bytes += 19;
1360 bytes += qq_putdata(raw_data + bytes, login_1_16, sizeof(login_1_16));
1361
1362 index = rand() % 3; /* can be set as 1 */
1363 for( count = 0; count < encrypted_len; count++ )
1364 index ^= encrypted[count];
1365 for( count = 0; count < sizeof(login_1_16); count++ )
1366 index ^= login_1_16[count];
1367 bytes += qq_put8(raw_data + bytes, index); /* random in QQ 2007*/
1368
1369 bytes += qq_put8(raw_data + bytes, qd->login_mode);
1370 /* unknow 10 bytes zero filled*/
1371 memset(raw_data + bytes, 0, 10);
1372 bytes += 10;
1373 /* redirect data, 15 bytes */
1374 bytes += qq_putdata(raw_data + bytes, (guint8 *)&qd->redirect_data, sizeof(qd->redirect_data));
1375 /* unknow fill */
1376 bytes += qq_putdata(raw_data + bytes, login_2_16, sizeof(login_2_16));
1377 /* captcha token get from qq_process_token_ex */
1378 bytes += qq_put8(raw_data + bytes, qd->captcha.token_len);
1379 bytes += qq_putdata(raw_data + bytes, qd->captcha.token, qd->captcha.token_len);
1380 /* unknow fill */
1381 bytes += qq_putdata(raw_data + bytes, login_3_18, sizeof(login_3_18));
1382 bytes += qq_put8(raw_data + bytes , sizeof(login_4_16));
1383 bytes += qq_putdata(raw_data + bytes, login_4_16, sizeof(login_4_16));
1384 /* unknow 10 bytes zero filled*/
1385 memset(raw_data + bytes, 0, 10);
1386 bytes += 10;
1387 /* redirect data, 15 bytes */
1388 bytes += qq_putdata(raw_data + bytes, (guint8 *)&qd->redirect_data, sizeof(qd->redirect_data));
1389 /* unknow fill */
1390 bytes += qq_putdata(raw_data + bytes, login_5_6, sizeof(login_5_6));
1391 bytes += qq_put8(raw_data + bytes , sizeof(login_6_16));
1392 bytes += qq_putdata(raw_data + bytes, login_6_16, sizeof(login_6_16));
1393 /* unknow 249 bytes zero filled*/
1394 memset(raw_data + bytes, 0, 249);
1395 bytes += 249;
1396
1397 encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.login_key);
1398
1399 buf = g_newa(guint8, MAX_PACKET_SIZE);
1400 memset(buf, 0, MAX_PACKET_SIZE);
1401 bytes = 0;
1402 /* logint token get from qq_process_check_pwd_2007 */
1403 bytes += qq_put16(buf + bytes, qd->ld.login_token_len);
1404 bytes += qq_putdata(buf + bytes, qd->ld.login_token, qd->ld.login_token_len);
1405 bytes += qq_putdata(buf + bytes, encrypted, encrypted_len);
1406
1407 qd->send_seq++;
1408 qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE);
1409 }
1410
1411 guint8 qq_process_login_2008( PurpleConnection *gc, guint8 *data, gint data_len)
1412 {
1413 qq_data *qd;
1414 gint bytes;
1415 guint8 ret;
1416 gchar *error;
1417 guint32 uid;
1418
1419 g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR);
1420
1421 qd = (qq_data *) gc->proto_data;
1422
1423 bytes = 0;
1424 bytes += qq_get8(&ret, data + bytes);
1425 if (ret != 0) {
1426 qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len,
1427 ">>> [default] decrypt and dump");
1428 error = g_strdup_printf(
1429 _("Unknow reply code when login (0x%02X)"),
1430 ret );
1431 purple_connection_error_reason(gc,
1432 PURPLE_CONNECTION_ERROR_OTHER_ERROR,
1433 error);
1434 g_free(error);
1435 return QQ_LOGIN_REPLY_ERR;
1436 }
1437
1438 bytes += qq_getdata(qd->session_key, sizeof(qd->session_key), data + bytes);
1439 purple_debug_info("QQ", "Got session_key\n");
1440 get_session_md5(qd->session_md5, qd->uid, qd->session_key);
1441
1442 bytes += qq_get32(&uid, data + bytes);
1443 if (uid != qd->uid) {
1444 purple_debug_warning("QQ", "My uid in login reply is %d, not %d\n", uid, qd->uid);
1445 }
1446 bytes += qq_getIP(&qd->my_ip, data + bytes);
1447 bytes += qq_get16(&qd->my_port, data + bytes);
1448 bytes += qq_getIP(&qd->my_local_ip, data + bytes);
1449 bytes += qq_get16(&qd->my_local_port, data + bytes);
1450 bytes += qq_getime(&qd->login_time, data + bytes);
1451 /* skip 1 byte, always 0x03 */
1452 /* skip 1 byte, login mode */
1453 bytes = 131;
1454 bytes += qq_getIP(&qd->last_login_ip, data + bytes);
1455 bytes += qq_getime(&qd->last_login_time[0], data + bytes);
1456 purple_debug_info("QQ", "Last Login: %s, %s\n",
1457 inet_ntoa(qd->last_login_ip), ctime(&qd->last_login_time[0]));
1458 return QQ_LOGIN_REPLY_OK;
1459 }