Protocols/YMSG
YMSG Protocol |
Introduction • Packet Structure |
YMSG was the network protocol used by Yahoo! Messenger for almost everything, including login, messaging and presence. It was a proprietary, homegrown solution created at Yahoo.
If you have anything to contribute, or can see an error to correct in any of the information here, do not hesitate to contribute. Instructions are on the main page of the wiki.
General structure
YMSG packets are binary-based. They consist of a magic string, version code, vendor ID, packet length, service code, status code, session ID, and an optional payload.
The first field in a YMSG packet is the magic string YMSG at offset 0x00, which is 4 bytes in length.
The second field is the version number of the protocol the client wants to use for the current YMSG session packed as a short on offset 0x04, and is 2 bytes long. For server-side packets, this field is usually 0.
The third field, on offset 0x06, is the vendor ID of the client connecting to the YMSG server, which is a 2-byte long short-packed number. Supported values for the vendor ID are 0 (\x00\x00; Windows/NULL) and 100 (\x00\x64; Macintosh). For server-side packets, this value is usually set to 0, but we are not sure of this yet. Prior to YMSG16, it was believed that the vendor ID was part of the version code, effectively making the version a DWORD.
The fourth field is the length of the packet's payload packed as a short, which is located on offset 0x08 and is also 2 bytes long.
The fifth field is the service code the packet requests the server to execute the payload with. It is located on offset 0x0a and is 2 bytes long. There are a variety of services that a YMSG packet can utilize, and it has been observed that Yahoo! Messenger can swap protocol versions, meaning that features can be used on YMSG protocol versions that initially didn't support those features. Whether this mean older clients can potentially receive packets with services not recognized by their understanding of the protocol version they use hasn't been confirmed.
The sixth field is the status code, which is a packed DWORD located at offset 0x0c and is 4 bytes long. This status code doesn't correspond to the logged in user's status, and is moreso used as a subcommand for most packet services. Interestingly enough, most of the status code in YMSG packets corresponds to the status codes used for contact presence. During authentication, this is used to determine if the user wants to log in under invisible mode. There are 19 YMSG statuses (that we've recorded as of now) that may or may not be used for contact statuses:
AVAILABLE/REQUEST: 0x00000000 BRB/RESPONSE: 0x00000001 BUSY: 0x00000002 NOTATHOME/BADUSERNAME: 0x00000003 NOTATDESK: 0x00000004 NOTINOFFICE/OFFLINEMSG/MULTIPACKET: 0x00000005 ONPHONE: 0x00000006 ONVACATION: 0x00000007 OUTTOLUNCH: 0x00000008 STEPPEDOUT: 0x00000009 INVISIBLE: 0x0000000C BAD: 0x0000000D LOCKED: 0x0000000E TYPING: 0x00000016 CUSTOM: 0x00000063 IDLE: 0x000003E7 WEBLOGIN: 0x5A55AA55 OFFLINE: 0x5A55AA56 LOGINERROR: 0xFFFFFFFF
The seventh field is the session ID, which is also a packed DWORD. It is located at offset 0x10 and is also 4 bytes long. The purpose of this field is to identify sessions and to verify if a user has the greenlight to use the main YMSG services (anything after authentication). It is believed that the official YMSG servers verified the session ID after authentication, but there is no hard evidence of this being the case, considering YMSG by design didn't validate the payloads of most services.
The eighth, optional field is the payload for the service the packet wants to request. The payload is located at offset 0x14 and is variable-length or null. If not null, payloads are formatted in a generic key/value format, with the key usually being numeric. The key and value are separated by the delimiter \xc0\x80. An example of this format is below:
1[\xc0\x80]yahoo.id[\xc0\x80]
1 is the key and yahoo.id is the value of the key in this example.
There is no limit to the amount of key/value pairs that can make up the payload, but due to the packet length in the packet's header being short-packed, the payload is limited to 65,535 bytes.
YMSG8
YMSG8 is the first known version of the protcol. Versions of Yahoo! Messenger 5.0 and below use it.
Auth
1. Client sends GET request to
http://msg.edit.yahoo.com/config/ncclogin?.src=bl&login=[username]&passwd=[password]&n=1
2. Server responds with cookie Y and body:
OK BEGIN BUDDYLIST [contact category]:[comma separated list of Yahoo! IDs associated with the contact category] END BUDDYLIST BEGIN IGNORELIST [comma separated list of Yahoo IDs in the user's ignore list] END IGNORELIST BEGIN IDENTITIES [comma-separated list of user's main and alternate usernames go here] END IDENTITIES Mail=1 Login=[username]
3. Client opens a connection to a YMSG server via port 5050 and sends:
Service: \x00\x01 (LOGON) Status: \x5A\x55\xAA\x55 (WEBLOGON) Payload: '0' -> [YahooId] '6' -> [md5-crypt(3)'d password] '1' -> [YahooId]
4. If the verification of the password goes well, the server responds with:
Service: \x00\x01 (LOGON) Status: \x00\x00\x00\x00 (0; [AVAILABLE]/REQUEST)
Payload: '0' -> [YahooId] '1' -> [YahooId]
YMSG9
YMSG9 is the second revision of the protocol, used by Yahoo! Messenger versions 5.0 through 5.4.
Auth
1. Client opens a connection to a YMSG server via port 5050 and sends:
Service: \x00\x4C (76; HANDSHAKE) Status: \x00\x00\x00\x00 (0; AVAILABLE/[REQUEST])
2. Server responds with:
Service: \x00\x4C (76; HANDSHAKE) Status: \x00\x00\x00\x01 (1; BRB/[RESPONSE])
3. Client sends:
Service: \x00\x57 (87; AUTH) Status: \x00\x00\x00\x00 (0; AVAILABLE/[REQUEST])
Payload: '1' -> [YahooId]
4. On successful verification of the username, the server responds with the following packet (this is also when the server generates the session ID the client should use for the whole server session):
Service: \x00\x57 (87; AUTH) Status: \x00\x00\x00\x01 (1; BRB/[RESPONSE])
Payload: '1' -> [YahooId] '94' -> [24-byte Yahoo64-encoded challenge string] ('AA.BBCCDDEEGGHHIIH_HII--')
5. The client then crafts two response strings with the challenge strings (details will be added onto later).
6. After the client is done crafting the two response strings, the client responds with:
Service: \x00\x54 (54; AUTHRESP) Status: [Status the user wants to log in as; usually either AVAILABLE or INVISIBLE]
Payload: '0' -> [YahooId] '6' -> [Challenge response string 1] ('AA.BBCCDDEEGGHHIIH_HII--') '96' -> [Challenge response string 2] ('AA.BBCCDDEEGGHHIIH_HII--') '2' -> '1' '1' -> [YahooId]
7. Server verifies the first and second response strings, and if all is well, responds with this:
Service: \x00\x55 (85; LIST) Status: \x00\x00\x00\x00
Payload: '87' -> '[contact category]:[comma separated list of Yahoo! IDs associated with the contact category]\x0A' '88' -> [comma separated list of Yahoo IDs in the user's ignore list] '89' -> [comma-separated list of user's main and alternate usernames go here] '59' -> 'Y\x09[data of "Y" cookie]' '59' -> 'T\x09[data of "T" cookie]' '59' -> 'C\x09mg=1' '3' -> [YahooId] '100' -> '0' '101' -> (blank) '102' -> (blank) '93' -> '86400' If the contact, ignore, or identity list were too large for the server's taste, then multiple LIST packets would be sent with status 0x00000005 (NOTINOFFICE) containing chunks of the key-value pair for one type of list each before sending the rest of the LIST packet.
8. The server will also send you a LOGON packet containing structures of your contacts statuses and the number of them contained:
Service: \x00\x01 (LOGON) Status: \x00\x00\x00\x00 Payload: '0' -> [YahooId] '1' -> [YahooId] '8' -> # of contact structures --- This collection of key-value pairs are added times the number specified in key 8 --- '7' -> Contact's Yahoo ID '10' -> Contact's YMSG status in integer format (99 (CUSTOM) if using a PSM or 0 (AVAILABLE) if offline) '11' -> Contact's YMSG session ID in uppercase hexadecimal '19' -> Contact's PSM (key-value pair only included if status == 99 (CUSTOM)) '47' -> Flag for if contact's PSM is an away message or not (key-value pair only included if status == 99 (CUSTOM)) '17' -> Contact is online on Yahoo! Chat (1 for yes, 0 for no; apparently this was only set to 1 if you were on Yahoo Chat's own protocol) '13' -> Contact is online on Yahoo! Messenger service (1 for yes, 0 for no)
The responses detailed in 7 and 8 will also be sent if the client queries the LIST service itself.
9. If any, the server will send packets containing the logged on user's OIMs (TODO: packet structure)
Presence
When a user logs on successfully, their status set in the AUTHRESP packet will automatically be dispatched to their contacts.
When a user wants to change their status to something other than online (this includes going invisible), Yahoo! Messenger will send an ISAWAY packet containing the following info:
Service: \x00\x03 (ISAWAY) Status: 0x00000000 (0; AVAILABLE/[REQUEST])
Payload: '10' -> Numerical YMSG status (99 for CUSTOM) '19' -> PSM (only included if status == 99) '47' -> Going away? (usually 1)
If a user wants to go back as online, the client will send this:
Service: \x00\x04 (ISBACK) Status: 0x00000000 (0; AVAILABLE/[REQUEST])
Payload: (None)
No responses are sent to the user setting their status for either service.
When contact statuses are dispatched to other users, the server sends the same contact structure with the appropriate info with various services depending on the status the remote contact is on:
Service: Various (LOGON if remote contact status is "offline -> online"; ISAWAY if remote contact status is "any available (no PSM)/idle status -> any available (with PSM)/idle status"; ISBACK if remote contact status is "any available (with PSM)/idle status -> regular available (no PSM) status") Status 0x00000001 (1; BRB/RESPONSE)
Payload: '0' -> [Receiver's Yahoo ID] (only included if service != LOGOFF) '7' -> Contact's Yahoo ID '10' -> Contact's YMSG status in integer format (99 (CUSTOM) if using a PSM or 0 (AVAILABLE) if offline) '11' -> Contact's YMSG session ID in uppercase hexadecimal '19' -> Contact's PSM (key-value pair only included if status == 99 (CUSTOM)) '47' -> Flag for if contact's PSM is an away message or not (key-value pair only included if status == 99 (CUSTOM)) '17' -> Contact is online on Yahoo! Chat (1 for yes, 0 for no; apparently this was only set to 1 if you were on Yahoo Chat's own protocol) '13' -> Contact is online on Yahoo! Messenger service (1 for yes, 0 for no)
YMSG10 - 14
We don't currently know what in specific was changed between each of these protocol versions.
YMSG10 is used by Yahoo! Messenger 5.5
YMSG11 is used by Yahoo! Messenger 5.6
YMSG12 is used by Yahoo! Messenger 6.0
We currently do not know what versions used YMSG13 or YMSG14
Auth
1. (Same as YMSG9 steps 1 to 3; in version 11 the version field is now in the correct (network) endianness). 2. Server responds with:
Service: \x00\x57(W) (87; AUTH)
Status: \x00\x00\x00\x01 (1; BRB/[RESPONSE])
Payload: '1' -> [YahooId] '94' -> [mathematical expression-like challenge string (64 bytes without parentheses)] ('g|i/p^h&z-d+2%v%x&j|e+(m^k-i%h*(s+8%a/u/x*(b-4*i%h^g^j|m^n-r*f+p+j)))') '13' -> '1'
3. Other, more complicated stuff ensues: https://web.archive.org/web/20031206174432if_/http://venkydude.com:80/articles/yahooencription.htm.
4. After crafting the two response strings, the client sends:
Service \x00\x57(W) (87; AUTH) Status: \x5A\x55\xAA\x55
Payload: '6' -> [First response string consisting of comma and semicolon separated "X=YZ" values] ('X=7e,H=je,H=j7;m=Cj,H=Cc,E=33;Q=ml;H=37;F=gg;w=F5;') '96' -> [Second response string also consisting of comma and semicolon separated "X=YZ" values] ('N=ah,m=F1,m=3A,Q=A2;T=Al,Z=Ep,h=he,S=0o;r=1B,C=h2;') '0' -> [YahooId] '2' -> '1' '1' -> [YahooId]
5. The rest is same as YMSG9's post-auth (to our understanding)
a. After the initial LOGON packet and before the OIM packets, the server will also send ping configuration in the form of a "tick" and "tock" interval that the official client uses to send pings:
Service: \x00\x12 (PINGCONFIGURATION) Status: \x00\x00\x00\x00 Payload: '143' -> Tick interval (usually 60) '144' -> Tock interval (usually 13)
YMSG15-16
As before, we are not certain what clients specifically used YMSG15 and YMSG16
We're under the assumption YMSG15 was used by Yahoo! Messenger 8.0, and that YMSG16 was used by Yahoo! Messenger 9.0
1. (YMSG16 only)
a. Client gets vcs1.msg.yahoo.com/capacity, which responds with
COLO_CAPACITY=1 CS_IP_ADDRESS=[IP address to YMSG server]
b. If COLO_CAPACITY is != 0, Y!M will try connecting to the specified IP.
2. (Same as YMSG10-14 steps 1 to 3.)
3. Server responds with:
Service: \x00\x57(W) (87; AUTH) Status: \x00\x00\x00\x00 (0; AVAILABLE)
Payload: '1' -> [YahooId] '13' -> '2' '94' -> [mathematical expression-like challenge string (64 bytes without parentheses)] ('g|i/p^h&z-d+2%v%x&j|e+(m^k-i%h*(s+8%a/u/x*(b-4*i%h^g^j|m^n-r*f+p+j)))')
4. Now the client just sends that stuff over to an HTTPS auth server to do the heavy lifting at https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=&login=[username]&passwd=[password]&chal=[challenge string]. If the password and Yahoo! ID are correct, the following response is returned:
0 ymsgr=[token] partnerid=[partnerid]
5. Client now grabs the token and GET requests https://login.yahoo.com/pwtoken_login?src=ymsgr&ts=&token=[token], which sets the Y, T, and B cookies, and replies with:
0 crumb=[crumb] Y=[Y cookie] T=[T cookie] cookievalidfor=86400 [a day in seconds] SSL=[SSL cookie]
if the token is correct.
6. The client retrieves the Y, T, and B cookies, along with the crumb, and then does the following: concatenates the crumb and challenge string sent; MD5 hashes the concatenation; and finally Yahoo64 encodes the hash. Let's call the resulting data "response".
7. The client finally responds with this humongous packet:
Service: \x00\x54(T) (84; AUTHRESP)
Payload: '1' -> [YahooId] '0' -> [YahooId] '277' -> [Contents of the "Y" cookie] '278' -> [Contents of the "T" cookie] '307' -> [The "response" variable the client had crafted] '244' -> [The client's build ID] '2' -> [YahooId] '2' -> '1' '59' -> [Contents of the "B" cookie] '98' -> [Locale] '135' -> [Client version]