From: mid Date: Thu, 29 Mar 2001 01:02:40 +0000 (+0000) Subject: - Wed Mar 28 16:51:25 PST 2001 X-Git-Tag: rel_0_99_2~53 X-Git-Url: http://andersk.mit.edu/gitweb/libfaim.git/commitdiff_plain/b1eac25ac75949707e082afcb8e0d702e536cef1 - Wed Mar 28 16:51:25 PST 2001 - I decided it was a good day while I was figuring out that it was a bad day. - See faimtest and login.c::memrequest(). - Hopefully I'm done for a while. --- diff --git a/CHANGES b/CHANGES index bc2bec7..96d26fd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,11 @@ No release numbers ------------------ + - Wed Mar 28 16:51:25 PST 2001 + - I decided it was a good day while I was figuring out that it was a bad day. + - See faimtest and login.c::memrequest(). + - Hopefully I'm done for a while. + - Tue Mar 27 19:15:10 PST 2001 - I haven't decided yet whether today is a good day or a bad day. - Probably both. diff --git a/include/aim.h b/include/aim.h index a0479c8..a5e6e29 100644 --- a/include/aim.h +++ b/include/aim.h @@ -169,7 +169,7 @@ struct client_info_s { long unknown; }; -#define AIM_CLIENTINFO_KNOWNGOOD { \ +#define AIM_CLIENTINFO_KNOWNGOOD_3_5_1670 { \ "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \ 0x0003, \ 0x0005, \ @@ -181,6 +181,28 @@ struct client_info_s { 0x0000002a, \ } +#define AIM_CLIENTINFO_KNOWNGOOD_4_1_2010 { \ + "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \ + 0x0004, \ + 0x0001, \ + 0x07da, \ + "us", \ + "en", \ + 0x0004, \ + 0x0000, \ + 0x0000004b, \ +} + +/* + * I would make 4.1.2010 the default, but they seem to have found + * an alternate way of breaking that one. + * + * 3.5.1670 should work fine, however, you will be subjected to the + * memory test, which may require you to have a WinAIM binary laying + * around. (see login.c::memrequest()) + */ +#define AIM_CLIENTINFO_KNOWNGOOD AIM_CLIENTINFO_KNOWNGOOD_3_5_1670 + #ifndef TRUE #define TRUE 1 #define FALSE 0 @@ -637,7 +659,7 @@ faim_export int aim_oft_getfile_end(struct aim_session_t *sess, struct aim_conn_ #define AIM_CAPS_SAVESTOCKS 0x80 faim_export int aim_0002_000b(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn); -faim_export int aim_0001_0020(struct aim_session_t *sess, struct aim_conn_t *conn); +faim_export int aim_sendmemblock(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf); #define AIM_GETINFO_GENERALINFO 0x00001 #define AIM_GETINFO_AWAYMESSAGE 0x00003 diff --git a/src/bos.c b/src/bos.c index 245b3bc..9a6a0de 100644 --- a/src/bos.c +++ b/src/bos.c @@ -19,34 +19,6 @@ faim_export unsigned long aim_bos_setgroupperm(struct aim_session_t *sess, return aim_genericreq_l(sess, conn, 0x0009, 0x0004, &mask); } -faim_export int aim_0001_0020(struct aim_session_t *sess, struct aim_conn_t *conn) -{ - struct command_tx_struct *tx; - int i = 0; - - if (!sess || !conn) - return 0; - - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+16))) - return -1; - - tx->lock = 1; - - /* Hummm.... */ - i = aim_putsnac(tx->data, 0x0001, 0x0020, 0x0000, sess->snac_nextid++); - i += aimutil_put16(tx->data+i, 0x0010); - i += aimutil_put32(tx->data+i, 0x92bd6757); - i += aimutil_put32(tx->data+i, 0x3722cbd3); - i += aimutil_put32(tx->data+i, 0x2b048ab9); - i += aimutil_put32(tx->data+i, 0xd0b1e4ab); - - tx->commandlen = i; - tx->lock = 0; - aim_tx_enqueue(sess, tx); - - return 0; -} - static int rights(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { rxcallback_t userfunc; diff --git a/src/login.c b/src/login.c index 748823f..1fd031a 100644 --- a/src/login.c +++ b/src/login.c @@ -121,9 +121,9 @@ faim_export int aim_request_login(struct aim_session_t *sess, * * This is the initial login request packet. * - * The password is encoded before transmition, as per - * encode_password(). See that function for their - * stupid method of doing it. + * NOTE!! If you want/need to make use of the aim_sendmemblock() function, + * then the client information you send here must exactly match the + * executable that you're pulling the data from. * * Latest WinAIM: * clientstring = "AOL Instant Messenger (SM), version 4.3.2188/WIN32" @@ -138,6 +138,15 @@ faim_export int aim_request_login(struct aim_session_t *sess, * unknown4a = 0x01 * * Latest WinAIM that libfaim can emulate without server-side buddylists: + * clientstring = "AOL Instant Messenger (SM), version 4.1.2010/WIN32" + * major2 = 0x0004 + * major = 0x0004 + * minor = 0x0001 + * minor2 = 0x0000 + * build = 0x07da + * unknown= 0x0000004b + * + * WinAIM 3.5.1670: * clientstring = "AOL Instant Messenger (SM), version 3.5.1670/WIN32" * major2 = 0x0004 * major = 0x0003 @@ -664,14 +673,107 @@ static int hostversions(struct aim_session_t *sess, aim_module_t *mod, struct co return 0; } + /* - * Stay tuned. I have an explanation for here. + * Starting this past week (26 Mar 2001, say), AOL has started sending + * this nice little extra SNAC. AFAIK, it has never been used until now. + * + * The request contains eight bytes. The first four are an offset, the + * second four are a length. * + * The offset is an offset into aim.exe when it is mapped during execution + * on Win32. So far, AOL has only been requesting bytes in static regions + * of memory. (I won't put it past them to start requesting data in + * less static regions -- regions that are initialized at run time, but still + * before the client recieves this request.) + * + * When the client recieves the request, it adds it to the current ds + * (0x00400000) and dereferences it, copying the data into a buffer which + * it then runs directly through the MD5 hasher. The 16 byte output of + * the hash is then sent back to the server. + * + * If the client does not send any data back, or the data does not match + * the data that the specific client should have, the client will get the + * following message from "AOL Instant Messenger": + * "You have been disconnected from the AOL Instant Message Service (SM) + * for accessing the AOL network using unauthorized software. You can + * download a FREE, fully featured, and authorized client, here + * http://www.aol.com/aim/download2.html" + * The connection is then closed, recieving disconnect code 1, URL + * http://www.aim.aol.com/errors/USER_LOGGED_OFF_NEW_LOGIN.html. + * + * Note, however, that numerous inconsistencies can cause the above error, + * not just sending back a bad hash. Do not immediatly suspect this code + * if you get disconnected. AOL and the open/free software community have + * played this game for a couple years now, generating the above message + * on numerous ocassions. + * + * Anyway, neener. We win again. * */ static int memrequest(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { - return 1; + rxcallback_t userfunc; + unsigned long offset, len; + + offset = aimutil_get32(data); + len = aimutil_get32(data+4); + + faimdprintf(sess, 1, "data at 0x%08lx (%d bytes) requested\n", offset, len); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, offset, len); + + return 0; +} + +faim_export int aim_sendmemblock(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf) +{ + struct command_tx_struct *tx; + int i = 0; + + if (!sess || !conn || ((offset == 0) && !buf)) + return 0; + + if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+16))) + return -1; + + tx->lock = 1; + + i = aim_putsnac(tx->data, 0x0001, 0x0020, 0x0000, sess->snac_nextid++); + i += aimutil_put16(tx->data+i, 0x0010); /* md5 is always 16 bytes */ + + if (buf && (len > 0)) { /* use input buffer */ + md5_state_t state; + + md5_init(&state); + md5_append(&state, (const md5_byte_t *)buf, len); + md5_finish(&state, (md5_byte_t *)(tx->data+i)); + i += 0x10; + + } else { + + if ((offset != 0x00001004) || (len != 0x00000004)) + faimdprintf(sess, 0, "sendmemblock: WARNING: sending bad hash... you will be disconnected soon...\n"); + + /* + * This data is correct for AIM 3.5.1670, offset 0x1004, length 4 + * + * Using this block is as close to "legal" as you can get without + * using an AIM binary. + */ + i += aimutil_put32(tx->data+i, 0x92bd6757); + i += aimutil_put32(tx->data+i, 0x3722cbd3); + i += aimutil_put32(tx->data+i, 0x2b048ab9); + i += aimutil_put32(tx->data+i, 0xd0b1e4ab); + + } + + tx->commandlen = i; + tx->lock = 0; + aim_tx_enqueue(sess, tx); + + return 0; } static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) diff --git a/utils/faimtest/faimtest.c b/utils/faimtest/faimtest.c index 76fc179..35ca6a2 100644 --- a/utils/faimtest/faimtest.c +++ b/utils/faimtest/faimtest.c @@ -75,7 +75,7 @@ static char *dprintf_ctime(void) int faimtest_parse_oncoming(struct aim_session_t *, struct command_rx_struct *, ...); int faimtest_parse_offgoing(struct aim_session_t *, struct command_rx_struct *, ...); int faimtest_parse_login_phase3d_f(struct aim_session_t *, struct command_rx_struct *, ...); -int faimtest_parse_authresp(struct aim_session_t *, struct command_rx_struct *, ...); +static int faimtest_parse_authresp(struct aim_session_t *, struct command_rx_struct *, ...); int faimtest_parse_incoming_im(struct aim_session_t *, struct command_rx_struct *command, ...); int faimtest_parse_userinfo(struct aim_session_t *, struct command_rx_struct *command, ...); int faimtest_handleredirect(struct aim_session_t *, struct command_rx_struct *command, ...); @@ -148,6 +148,7 @@ static char *msgerrreasons[] = { "Not while on AOL"}; static int msgerrreasonslen = 25; +static char *aimbinarypath = NULL; static char *screenname,*password,*server=NULL; static char *proxy = NULL, *proxyusername = NULL, *proxypass = NULL; static char *ohcaptainmycaptain = NULL; @@ -331,7 +332,7 @@ int main(int argc, char **argv) listingpath = getenv("LISTINGPATH"); - while ((i = getopt(argc, argv, "u:p:a:U:P:A:l:c:hoO")) != EOF) { + while ((i = getopt(argc, argv, "u:p:a:U:P:A:l:c:hoOb:")) != EOF) { switch (i) { case 'u': screenname = optarg; break; case 'p': password = optarg; break; @@ -343,6 +344,7 @@ int main(int argc, char **argv) case 'c': ohcaptainmycaptain = optarg; break; case 'o': faimtest_mode = 1; break; /* half old interface */ case 'O': faimtest_mode = 2; break; /* full old interface */ + case 'b': aimbinarypath = optarg; break; case 'h': default: printf("faimtest\n"); @@ -408,7 +410,6 @@ int main(int argc, char **argv) if (connected && ((time(NULL) - lastnop) > 30)) { lastnop = time(NULL); - dprintf("sending NOP\n"); aim_flap_nop(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS)); } @@ -796,7 +797,75 @@ int faimtest_handleredirect(struct aim_session_t *sess, struct command_rx_struct return 1; } -int faimtest_parse_authresp(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int getaimdata(unsigned char *buf, int buflen, unsigned long offset) +{ + FILE *f; + + if (!(f = fopen(aimbinarypath, "r"))) { + dperror("memrequest: fopen"); + return -1; + } + + if (fseek(f, offset, SEEK_SET) == -1) { + dperror("memrequest: fseek"); + fclose(f); + return -1; + } + + if (fread(buf, buflen, 1, f) != 1) { + dperror("memrequest: fread"); + fclose(f); + return -1; + } + + fclose(f); + + return buflen; +} + +/* + * This will get an offset and a length. The client should read this + * data out of whatever AIM.EXE binary the user has provided (hopefully + * it matches the client information thats sent at login) and pass a + * buffer back to libfaim so it can hash the data and send it to AOL for + * inspection by the client police. + */ +static int faimtest_memrequest(struct aim_session_t *sess, struct command_rx_struct *command, ...) +{ + va_list ap; + unsigned long offset, len; + unsigned char *buf; + + va_start(ap, command); + offset = va_arg(ap, unsigned long); + len = va_arg(ap, unsigned long); + va_end(ap); + + if (!(buf = malloc(len))) { + dperror("memrequest: malloc"); + return 0; + } + + if (aimbinarypath && (getaimdata(buf, len, offset) == len)) { + + dvprintf("memrequest: sending %ld bytes from 0x%08lx in %s...\n", len, offset, aimbinarypath); + + aim_sendmemblock(sess, command->conn, offset, len, buf); + + } else { + + dprintf("memrequest: unable to use AIM binary, sending defaults...\n"); + + aim_sendmemblock(sess, command->conn, offset, len, NULL); + + } + + free(buf); + + return 1; +} + +static int faimtest_parse_authresp(struct aim_session_t *sess, struct command_rx_struct *command, ...) { va_list ap; struct aim_conn_t *bosconn = NULL; @@ -893,6 +962,7 @@ int faimtest_parse_authresp(struct aim_session_t *sess, struct command_rx_struct aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, faimtest_parse_connerr, 0); + aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, faimtest_memrequest, 0); aim_conn_addhandler(sess, bosconn, 0xffff, 0xffff, faimtest_parse_unknown, 0); aim_auth_sendcookie(sess, bosconn, cookie); @@ -1540,10 +1610,6 @@ int faimtest_parse_motd(struct aim_session_t *sess, struct command_rx_struct *co aim_0002_000b(sess, command->conn, sess->sn); #endif - /* As of 26 Mar 2001 you need to send this to keep from getting kicked off */ - aim_0001_0020(sess, command->conn); - - return 1; }