It's no secret that Mail.ru Agent has become quite a popular IM project. Here you and support for ICQ, XMPP, voice calls and even sending SMS, only now the company Mail.ru completely forgot about the developers.
The official documentation of the Mail.ru Data Exchange Protocol Agent describes the protocol version 1.7 implemented in 2008. At the moment the server uses protocol version 1.24.
A bit of theory
At first glance, writing a network client is nothing complicated, but there are many “pitfalls” in network programming. Without understanding the details of how TCP / IP works, it’s almost impossible to write an effective and stable application.
Data integrity
As you know, TCP is a streaming protocol, and although data is transmitted in IP packets, the packet size is not directly related to the amount of data transmitted by TCP. Therefore, it is impossible to say with confidence that when calling recv we will get the specified number of bytes.
To get data of a given length, I use this function
#define SEND 0 #define RECV 1 int (__stdcall *tcp_func)(SOCKET s,char* buf,int len,int flags); // / len int tcp_rs(unsigned char type,SOCKET s, void *buf, int len, int flags) { int total = 0; int n; *(void* *)&tcp_func=(type==SEND)?&send:&recv; while(total < len) { n = tcp_func(s, (char *)buf+total, len-total, flags); if(n>0) { total += n; } else if(n == 0) { closesocket(s); return 0; } else { n=WSAGetLastError(); closesocket(s); return (!n+1); } } return total; }
which, if successful, returns the number of received / transmitted bytes equal to len, 0 if the connection was terminated or closed, and (minus) the error number if the call to the send / recv function fails.
Network outages
It is also necessary to remember that TCP does not poll the connection. In the case of blocking sockets, if the server crashes (disconnection, failure), we will wait for a response “forever”, the program will simply “hang”.
One way to determine if a connection is broken is a keep-alive timer.
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) #pragma pack(push,1) // typedef struct tcp_keepalive { DWORD onoff; DWORD keepalivetime; DWORD keepaliveinterval; } tcp_keepalive; #pragma pack(pop) // keep-alive struct tcp_keepalive alive; DWORD dwSize; alive.onoff = 1; alive.keepalivetime = 5000; alive.keepaliveinterval = 1000; WSAIoctl(my_sock, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),NULL, 0, &dwSize, NULL, NULL);
In our case, if the connection is not active for 5 seconds, a service message will be sent, if there is no answer to it, the connection will be closed.
')
About protocol
MMP binary asynchronous protocol. Binary means that data is transmitted in the form of packets of a certain structure:
// typedef struct mrim_packet_header_t { unsigned int magic; // Magic unsigned int proto; // unsigned int seq; // Sequence unsigned int msg; // unsigned int dlen; // unsigned int from; // unsigned int fromport; // unsigned char reserved[16]; // } mrim_packet_header_t; // , MFC, Delphi typedef struct LPS { unsigned int len; unsigned char *str; } LPS;
Asynchrony here is characterized by the fact that the server, maintaining a constant connection at different time intervals, sends data packets to the client, having received which the client can (and in some cases should) respond and send a response to the server.
The client initializes the connection, before this it is necessary to get the address of the “free” MMP server in text format
ip: port , simply by connecting to
mrim.mail.ru. The official client version 5.9 uses the following ports for connection: 2024, 80, 5190, 1863, 25, 110, 443.
As stated in the official documentation, after connecting to the recommended address, the client must send the package MRIM_CS_HELLO, wait for MRIM_CS_HELLO_ACK, then send the authorization package, then the most interesting begins.
In fact
Starting with version 1.22 (Mail.ru agent 5.7), the authorization method has changed. Now for authorization you need to send a package
0x1078 (MRIM_CS_LOGIN3) with parameters
LPS ## login ## login user email
LPS ## md5 password ## password encrypted in md5
Ffffffff
and 1391 bytes identifying the Mail.ru client
At the moment (protocol version 1.24) the protocol supports mandatory encryption. After receiving the MRIM_CS_HELLO_ACK packet, the client sends the 0x1086 packet and receives the 0x1087 response, after which the SSL connection is initialized.
But so far no one forbids us to use earlier versions of the protocol.
An important feature of the client’s work is that the client can send its requests only after receiving the package MRIM_CS_CONTACT_LIST2 from the server, which in turn is sent after successful authorization.
Projects
All the client's MMP code would take up a lot of space, so I suggest you download and study it yourself. The archive
MMPclient_sample.25.04.2011.rar , are the source code in the C language and the project Visual Studio.
UPD: source on github
To study the protocol was written by a small SOCKS 5 server. It allows you to track the message chain of the client and the server in a convenient way.
Server sources and project can be downloaded here.
And:
- Mail.ru Get Key - a program for obtaining a web-authorization key, which can be used to log into the box using the md5 password hash
- Mail.ru SMS sender - program for sending SMS messages
- Bruteforce MMP - password selection service Mail.ru
Links
All versions of Mail.ru Agent
Official protocol documentation
Tutorial games on WINSOCK
Detecting a broken TCP connection
Efficient TCP / IP programming