![](http://habrastorage.org/getpro/habr/avatars/87c/68a/99d/87c68a99d01801f42336e30f3d62ff65.jpg)
We study the MMP protocol (Mail.ru agent) and write an alternative client
It's not a secret that Mail.ru Agent has become a fairly popular IM project. Here you have support for ICQ, XMPP, voice calls and even sending SMS, only Mail.ru has completely forgotten about the developers.
The official documentation of the Mail.ru data exchange protocol. The agent describes protocol version 1.7 implemented in 2008. At the moment, the server uses protocol version 1.24.
At first glance, writing a network client is not difficult, but there are many pitfalls in network programming. Without understanding the details of TCP / IP, it is almost impossible to write an effective and stable application.
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 certainty that when recv is called, we will get the specified number of bytes.
To get the data of a given length, I use this function,
which, if successful, returns the number of received / transmitted bytes equal to len, 0 if the connection was disconnected or closed and (minus) the error number, if the call to the send / recv function fails.
It is also necessary to remember that TCP does not poll the connection. In the case of blocking sockets, when the server crashes (disconnection, failure), we will wait for an answer “forever”, the program simply “freezes”.
One way to determine if a connection is broken is through a keep-alive timer.
In our case, if the connection is not active within 5 seconds, a service message will be sent, if there is no answer to it, the connection will be closed.
MMP binary asynchronous protocol. Binary means that data is transmitted in the form of packets of a certain structure:
Asynchrony here is characterized by the fact that the server, maintaining a constant connection at various time intervals, sends data packets to the client, receiving which the client can (and in some cases must) respond and send a response to the server.
Initializes Connect client, before it is necessary to get the address of a "free» MMP server in text format the ip: port , just by connecting to the address 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 MRIM_CS_HELLO packet, wait for MRIM_CS_HELLO_ACK, and then send the authorization packet, then the fun begins.
Starting from version 1.22 (Mail.ru agent 5.7), the authorization method has changed. Now for authorization it is necessary to send a packet 0x1078 (MRIM_CS_LOGIN3) with
LPS parameters ## login ## email of the authorized user
LPS ## md5 password ## password encrypted in md5
FFFFFFFF
and 1391 bytes identifying Mail.ru client
Currently (protocol version 1.24) protocol supports mandatory encryption. After receiving the MRIM_CS_HELLO_ACK packet, the client sends a 0x1086 packet and receives a 0x1087 response, after which SSL connection is initialized.
But so far, no one has forbidden 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 from the server the package MRIM_CS_CONTACT_LIST2, which in turn is sent after successful authorization.
All MMP client code would take up a lot of space, so I suggest you download and study it yourself. The MMPclient_sample.25.04.2011.rar archive contains C source codes and a Visual Studio project.
UPD: github source
To study the protocol, a small SOCKS 5 server was written. It allows you to conveniently track the chain of messages of the client and server. Server sources and the project can be downloaded here.
And:
All versions of Mail.ru Agent.
Official documentation on the protocol.
Tutorial for playing WINSOCK.
Detecting a TCP connection.
Effective TCP / IP programming.
The official documentation of the Mail.ru data exchange protocol. The agent describes protocol version 1.7 implemented in 2008. At the moment, the server uses protocol version 1.24.
Bit of theory
At first glance, writing a network client is not difficult, but there are many pitfalls in network programming. Without understanding the details of TCP / IP, it is almost impossible to write an effective and stable application.
Transmit 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 certainty that when recv is called, we will get the specified number of bytes.
To get the 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 disconnected 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, when the server crashes (disconnection, failure), we will wait for an answer “forever”, the program simply “freezes”.
One way to determine if a connection is broken is through 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 within 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 various time intervals, sends data packets to the client, receiving which the client can (and in some cases must) respond and send a response to the server.
Initializes Connect client, before it is necessary to get the address of a "free» MMP server in text format the ip: port , just by connecting to the address 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 MRIM_CS_HELLO packet, wait for MRIM_CS_HELLO_ACK, and then send the authorization packet, then the fun begins.
In fact
Starting from version 1.22 (Mail.ru agent 5.7), the authorization method has changed. Now for authorization it is necessary to send a packet 0x1078 (MRIM_CS_LOGIN3) with
LPS parameters ## login ## email of the authorized user
LPS ## md5 password ## password encrypted in md5
FFFFFFFF
and 1391 bytes identifying Mail.ru client
Currently (protocol version 1.24) protocol supports mandatory encryption. After receiving the MRIM_CS_HELLO_ACK packet, the client sends a 0x1086 packet and receives a 0x1087 response, after which SSL connection is initialized.
But so far, no one has forbidden 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 from the server the package MRIM_CS_CONTACT_LIST2, which in turn is sent after successful authorization.
Projects
All MMP client code would take up a lot of space, so I suggest you download and study it yourself. The MMPclient_sample.25.04.2011.rar archive contains C source codes and a Visual Studio project.
UPD: github source
To study the protocol, a small SOCKS 5 server was written. It allows you to conveniently track the chain of messages of the client and server. Server sources and the project can be downloaded here.
And:
- Mail.ru Get Key - a program for obtaining a web authorization key, which can be used to enter the box, by md5 password hash
- Mail.ru SMS sender - program for sending SMS messages
- Bruteforce MMP - mail.ru service password selection
References
All versions of Mail.ru Agent.
Official documentation on the protocol.
Tutorial for playing WINSOCK.
Detecting a TCP connection.
Effective TCP / IP programming.