📄 yahoo.c
字号:
* plus 3 bytes. The 3 bytes are found by looping, and they represent the offsets * into particular functions we'll later call to potentially alter the magic key. * * %-) */ magic_cnt = 1; x = 0; do { unsigned int bl = 0; unsigned int cl = magic[magic_cnt++]; if (magic_cnt >= magic_len) break; if (cl > 0x7F) { if (cl < 0xe0) bl = cl = (cl & 0x1f) << 6; else { bl = magic[magic_cnt++]; cl = (cl & 0x0f) << 6; bl = ((bl & 0x3f) + cl) << 6; } cl = magic[magic_cnt++]; bl = (cl & 0x3f) + bl; } else bl = cl; comparison_src[x++] = (bl & 0xff00) >> 8; comparison_src[x++] = bl & 0xff; } while (x < 20); /* First four bytes are magic key. */ memcpy(&magic_key_char[0], comparison_src, 4); magic_4 = magic_key_char[0] | (magic_key_char[1]<<8) | (magic_key_char[2]<<16) | (magic_key_char[3]<<24); /* * Magic: Phase 4. Determine what function to use later by getting outside/inside * loop values until we match our previous buffer. */ for (x = 0; x < 65535; x++) { int leave = 0; for (y = 0; y < 5; y++) { unsigned char test[3]; /* Calculate buffer. */ test[0] = x; test[1] = x >> 8; test[2] = y; purple_cipher_context_reset(md5_ctx, NULL); purple_cipher_context_append(md5_ctx, magic_key_char, 4); purple_cipher_context_append(md5_ctx, test, 3); purple_cipher_context_digest(md5_ctx, sizeof(md5_digest), md5_digest, NULL); if (!memcmp(md5_digest, comparison_src+4, 16)) { leave = 1; break; } } if (leave == 1) break; } /* If y != 0, we need some help. */ if (y != 0) { unsigned int updated_key; /* Update magic stuff. * Call it twice because Yahoo's encryption is super bad ass. */ updated_key = yahoo_auth_finalCountdown(magic_4, 0x60, y, x); updated_key = yahoo_auth_finalCountdown(updated_key, 0x60, y, x); magic_key_char[0] = updated_key & 0xff; magic_key_char[1] = (updated_key >> 8) & 0xff; magic_key_char[2] = (updated_key >> 16) & 0xff; magic_key_char[3] = (updated_key >> 24) & 0xff; } enc_pass = yahoo_string_encode(gc, pass, NULL); /* Get password and crypt hashes as per usual. */ purple_cipher_context_reset(md5_ctx, NULL); purple_cipher_context_append(md5_ctx, (const guchar *)enc_pass, strlen(enc_pass)); purple_cipher_context_digest(md5_ctx, sizeof(md5_digest), md5_digest, NULL); to_y64(password_hash, md5_digest, 16); crypt_result = yahoo_crypt(enc_pass, "$1$_2S43d5f$"); g_free(enc_pass); enc_pass = NULL; purple_cipher_context_reset(md5_ctx, NULL); purple_cipher_context_append(md5_ctx, (const guchar *)crypt_result, strlen(crypt_result)); purple_cipher_context_digest(md5_ctx, sizeof(md5_digest), md5_digest, NULL); to_y64(crypt_hash, md5_digest, 16); /* Our first authentication response is based off of the password hash. */ for (x = 0; x < (int)strlen(password_hash); x++) pass_hash_xor1[cnt++] = password_hash[x] ^ 0x36; if (cnt < 64) memset(&(pass_hash_xor1[cnt]), 0x36, 64-cnt); cnt = 0; for (x = 0; x < (int)strlen(password_hash); x++) pass_hash_xor2[cnt++] = password_hash[x] ^ 0x5c; if (cnt < 64) memset(&(pass_hash_xor2[cnt]), 0x5c, 64-cnt); /* * The first context gets the password hash XORed with 0x36 plus a magic value * which we previously extrapolated from our challenge. */ purple_cipher_context_append(sha1_ctx1, pass_hash_xor1, 64); if (y >= 3) purple_cipher_context_set_option(sha1_ctx1, "sizeLo", GINT_TO_POINTER(0x1ff)); purple_cipher_context_append(sha1_ctx1, magic_key_char, 4); purple_cipher_context_digest(sha1_ctx1, sizeof(digest1), digest1, NULL); /* * The second context gets the password hash XORed with 0x5c plus the SHA-1 digest * of the first context. */ purple_cipher_context_append(sha1_ctx2, pass_hash_xor2, 64); purple_cipher_context_append(sha1_ctx2, digest1, 20); purple_cipher_context_digest(sha1_ctx2, sizeof(digest2), digest2, NULL); /* * Now that we have digest2, use it to fetch characters from an alphabet to construct * our first authentication response. */ for (x = 0; x < 20; x += 2) { unsigned int val = 0; unsigned int lookup = 0; char byte[6]; memset(&byte, 0, 6); /* First two bytes of digest stuffed together. */ val = digest2[x]; val <<= 8; val += digest2[x+1]; lookup = (val >> 0x0b); lookup &= 0x1f; if (lookup >= strlen(alphabet1)) break; sprintf(byte, "%c", alphabet1[lookup]); strcat(resp_6, byte); strcat(resp_6, "="); lookup = (val >> 0x06); lookup &= 0x1f; if (lookup >= strlen(alphabet2)) break; sprintf(byte, "%c", alphabet2[lookup]); strcat(resp_6, byte); lookup = (val >> 0x01); lookup &= 0x1f; if (lookup >= strlen(alphabet2)) break; sprintf(byte, "%c", alphabet2[lookup]); strcat(resp_6, byte); lookup = (val & 0x01); if (lookup >= strlen(delimit_lookup)) break; sprintf(byte, "%c", delimit_lookup[lookup]); strcat(resp_6, byte); } /* Our second authentication response is based off of the crypto hash. */ cnt = 0; memset(&digest1, 0, 20); memset(&digest2, 0, 20); for (x = 0; x < (int)strlen(crypt_hash); x++) crypt_hash_xor1[cnt++] = crypt_hash[x] ^ 0x36; if (cnt < 64) memset(&(crypt_hash_xor1[cnt]), 0x36, 64-cnt); cnt = 0; for (x = 0; x < (int)strlen(crypt_hash); x++) crypt_hash_xor2[cnt++] = crypt_hash[x] ^ 0x5c; if (cnt < 64) memset(&(crypt_hash_xor2[cnt]), 0x5c, 64-cnt); purple_cipher_context_reset(sha1_ctx1, NULL); purple_cipher_context_reset(sha1_ctx2, NULL); /* * The first context gets the password hash XORed with 0x36 plus a magic value * which we previously extrapolated from our challenge. */ purple_cipher_context_append(sha1_ctx1, crypt_hash_xor1, 64); if (y >= 3) { purple_cipher_context_set_option(sha1_ctx1, "sizeLo", GINT_TO_POINTER(0x1ff)); } purple_cipher_context_append(sha1_ctx1, magic_key_char, 4); purple_cipher_context_digest(sha1_ctx1, sizeof(digest1), digest1, NULL); /* * The second context gets the password hash XORed with 0x5c plus the SHA-1 digest * of the first context. */ purple_cipher_context_append(sha1_ctx2, crypt_hash_xor2, 64); purple_cipher_context_append(sha1_ctx2, digest1, 20); purple_cipher_context_digest(sha1_ctx2, sizeof(digest2), digest2, NULL); /* * Now that we have digest2, use it to fetch characters from an alphabet to construct * our first authentication response. */ for (x = 0; x < 20; x += 2) { unsigned int val = 0; unsigned int lookup = 0; char byte[6]; memset(&byte, 0, 6); /* First two bytes of digest stuffed together. */ val = digest2[x]; val <<= 8; val += digest2[x+1]; lookup = (val >> 0x0b); lookup &= 0x1f; if (lookup >= strlen(alphabet1)) break; sprintf(byte, "%c", alphabet1[lookup]); strcat(resp_96, byte); strcat(resp_96, "="); lookup = (val >> 0x06); lookup &= 0x1f; if (lookup >= strlen(alphabet2)) break; sprintf(byte, "%c", alphabet2[lookup]); strcat(resp_96, byte); lookup = (val >> 0x01); lookup &= 0x1f; if (lookup >= strlen(alphabet2)) break; sprintf(byte, "%c", alphabet2[lookup]); strcat(resp_96, byte); lookup = (val & 0x01); if (lookup >= strlen(delimit_lookup)) break; sprintf(byte, "%c", delimit_lookup[lookup]); strcat(resp_96, byte); } purple_debug_info("yahoo", "yahoo status: %d\n", yd->current_status); pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->current_status, 0); yahoo_packet_hash(pack, "sssss", 0, name, 6, resp_6, 96, resp_96, 1, name, 135, "6,0,0,1710"); if (yd->picture_checksum) yahoo_packet_hash_int(pack, 192, yd->picture_checksum); yahoo_packet_send_and_free(pack, yd); purple_cipher_context_destroy(md5_ctx); purple_cipher_context_destroy(sha1_ctx1); purple_cipher_context_destroy(sha1_ctx2); g_free(password_hash); g_free(crypt_hash);}static void yahoo_process_auth(PurpleConnection *gc, struct yahoo_packet *pkt){ char *seed = NULL; char *sn = NULL; GSList *l = pkt->hash; int m = 0; gchar *buf; while (l) { struct yahoo_pair *pair = l->data; if (pair->key == 94) seed = pair->value; if (pair->key == 1) sn = pair->value; if (pair->key == 13) m = atoi(pair->value); l = l->next; } if (seed) { switch (m) { case 0: yahoo_process_auth_old(gc, seed); break; case 1: case 2: /* This case seems to work, could probably use testing */ yahoo_process_auth_new(gc, seed); break; default: buf = g_strdup_printf(_("The Yahoo server has requested the use of an unrecognized " "authentication method. You will probably not be able " "to successfully sign on to Yahoo. Check %s for updates."), PURPLE_WEBSITE); purple_notify_error(gc, "", _("Failed Yahoo! Authentication"), buf); g_free(buf); yahoo_process_auth_new(gc, seed); /* Can't hurt to try it anyway. */ } }}static void ignore_buddy(PurpleBuddy *buddy) { PurpleGroup *group; PurpleAccount *account; gchar *name; if (!buddy) return; group = purple_buddy_get_group(buddy); name = g_strdup(buddy->name); account = buddy->account; purple_debug(PURPLE_DEBUG_INFO, "blist", "Removing '%s' from buddy list.\n", buddy->name); purple_account_remove_buddy(account, buddy, group); purple_blist_remove_buddy(buddy); serv_add_deny(account->gc, name); g_free(name);}static void keep_buddy(PurpleBuddy *b) { purple_privacy_deny_remove(b->account, b->name, 1);}static void yahoo_process_ignore(PurpleConnection *gc, struct yahoo_packet *pkt) { PurpleBuddy *b; GSList *l; gchar *who = NULL; gchar *sn = NULL; gchar buf[BUF_LONG]; gint ignore = 0; gint status = 0; for (l = pkt->hash; l; l = l->next) { struct yahoo_pair *pair = l->data; switch (pair->key) { case 0: who = pair->value; break; case 1: sn = pair->value; break; case 13: ignore = strtol(pair->value, NULL, 10); break; case 66: status = strtol(pair->value, NULL, 10); break; default: break; } } switch (status) { case 12: b = purple_find_buddy(gc->account, who); g_snprintf(buf, sizeof(buf), _("You have tried to ignore %s, but the " "user is on your buddy list. Clicking \"Yes\" " "will remove and ignore the buddy."), who); purple_request_yes_no(gc, NULL, _("Ignore buddy?"), buf, 0, gc->account, who, NULL, b, G_CALLBACK(ignore_buddy), G_CALLBACK(keep_buddy)); break; case 2: case 3: case 0: default: break; }}static void yahoo_process_authresp(PurpleConnection *gc, struct yahoo_packet *pkt){#ifdef TRY_WEBMESSENGER_LOGIN struct yahoo_data *yd = gc->proto_data;#endif GSList *l = pkt->hash; int err = 0; char *msg; char *url = NULL; char *fullmsg; while (l) { struct yahoo_pair *pair = l->data; if (pair->key == 66) err = strtol(pair->value, NULL, 10); if (pair->key == 20) url = pair->value; l = l->next; } switch (err) { case 3: msg = g_strdup(_("Invalid screen name.")); break; case 13:#ifdef TRY_WEBMESSENGER_LOGIN if (!yd->wm) { PurpleUtilFetchUrlData *url_data; yd->wm = TRUE; if (yd->fd >= 0) close(yd->fd); if (gc->inpa) purple_input_remove(gc->inpa); url_data = purple_util_fetch_url(WEBMESSENGER_URL, TRUE, "Purple/" VERSION, FALSE, yahoo_login_page_cb, gc); if (url_data != NULL) yd->url_datas = g_slist_prepend(yd->url_datas, url_data); return; }#endif msg = g_strdup(_("Incorrect password.")); break; case 14: msg = g_strdup(_("Your account is locked, please log in to the Yahoo! website.")); break; default: msg = g_strdup_printf(_("Unknown error number %d. Logging into the Yahoo! website may fix this."), err); } if (url) fullmsg = g_strdup_printf("%s\n%s", msg, url); else fullmsg = g_strdup(msg); gc->wants_to_die = TRUE; purple_connection_error(gc, fullmsg); g_free(msg); g_free(fullmsg);}static void yahoo_process_addbuddy(PurpleConnection *gc, struct yahoo_packet *pkt){ int err = 0; char *who = NULL; char *group = NULL; char *decoded_group; char *buf; YahooFriend *f; GSList *l = pkt->hash; while (l) { struct yahoo_pair *pair = l->data; switch (pair->key) { case 66: err = strtol(pair->value, NULL, 10); break; case 7: who = pair->value; break; case 65: group = pair->value; break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -