PDA

Просмотр полной версии : @ mrim.pl: Написание скриптов, работающих по протоколу MMP


Digimortal
16.04.2007, 04:11
@ mrim.pl: Написание скриптов,
работающих по протоколу MMP

by Digimortal



[ intr0 ]

Что такое Mail.Ru Агент, я думаю, знают все. Для тех кто не в курсе, это асикуподобный мессенджер с поддержкой разнообразных дополнительных возможностей, вроде отправки смс, голосового общения, игр и пр. В этой статье я достаточно подробно опишу основные моменты работы с протоколом, который испульзует Мэйл.ру Агент, что поможет тебе в написании различных тулз, работающих с этой системой (ни в коем случае не пишите смс-флудеры, МАгент-спаммеры или сборщики почтовых баз mail.ru!!! ;)) Как уже можно было понять из названия, примеры кода, приводящиеся в статье, будут написаны на самом классном скриптовом языке программирования :).


[ протокол MMP ]

Mail.Ru Агент использует собственный протокол - MMP, или mrim, который является частично открытым. На сайте agent.mail.ru выложено краткое описание протокола. В данном cписании присутствует только информация по основным возможностям мессенджера, но вооружившись сниффером пакетов, выяснить значения заголовков пакетов, например, для отправки смс, не составит труда. Помимо описания там присутствует С-хидер, с значениями полей, флагов и т.п. Я посчитал, что будет удобней объединить описание пакетов и этот заголовочный файл в один txt-файл, что и я сделал (смотри в ссылках). В дальнейшем думаю внести туда описания некоторых пакетов, которые не вошли в официальное описание.

MMP действует поверх установленного tcp-соединения. Клиент инициализирует соединение с сервером, и далее взаимодействие происходит путем обмена сообщениями, причем сообщения могут отпарвляться как клиентом так и сервером.

MMP является бинарным протоколом, кроме того, данные передаются не в общепринятом сетевом формате, а в little-endian'е, т.е. старший байт идет впереди. Основные типы данных, описанные в протоколе это:
- UL;
- LPS;
- UIDL.

Типом UL разработчики обозначили u_long или двойное слово, т.е. 4 байта.
LPS - это составной тип, в который кодируются текстовые строки. Он представляет собой идущий впереди UL, в котором содержится длина строки, и саму строку. Строки представлены в windows-1251 кодировке.
UIDL используется гораздо реже первых двух и в статье затрагиваться не будет. Представлен последовательностью из 8 символов из множества [a-z A-Z 0-9 _ - = +].


[ Структура пакетов ]

Рассмотрим теперь структуру пакетов протокола. Как и полагается, пакет состоит из заголовка и данных (данные могут и отсутствовать). Поля хидера:


<-4bytes->
,----------.
| magic | мэйджик
+----------+
| proto | версия протокола
+----------+
| seq | номер сообщения в текущем соединении (ответ будет иметь тот же номер)
+----------+
| msg | тип пакета
+----------+
| dlen | длина данных (без учета заголовка)
+----------+
| from | ip отправителя в inet_aton() формате
+----------+
| fromport | порт отправителя
+----------+
| | зарезервированные 16 байт, которые
+- -+ в текущих версиях протокола не используются
| reserved |
+- -+
| |
+- -+
| |
+==========+
| data | далее идут данные (если есть)...
'~~~~~~~~~~'


Самым важным для нас полем является "тип пакета". "Мэйджик" и "версия" у нас постоянны. "Номер сообщения" и "длина данных" подсчитуются по ходу дела, а правильный ip и port, как я понял, передавать вообще не обязательно, поэтому не спрашуй у меня, почему я заполняю их нулями (с значением поля seq тоже дозволены некоторые вольности).

Тип пакета - это команды (или ответы на них), которыми обмениваются между собой клиент и сервер. Команды могут иметь параметры, передающиеся как данные пакета. Значения этих команд и параметров иможно взять из того файла, что прикрепил к статье. Я сразу приведу здесь те, что будут использоваться в приводимых далее примерах:


my $CS_MAGIC = 0xDEADBEEF; ## Клиентский Magic
my $PROTO_VERSION = 0x1000A; ## Версия протокола

my $MRIM_CS_HELLO = 0x1001; ## C->S, empty
my $MRIM_CS_HELLO_ACK = 0x1002; ## S->C, UL mrim_connection_params_t

my $MRIM_CS_LOGIN2 = 0x1038; ## C->S, LPS login, LPS password, UL status, LPS uagent
my $MRIM_CS_LOGIN_ACK = 0x1004; ## S->C, empty
my $MRIM_CS_LOGIN_REJ = 0x1005; ## S->C, LPS reason

my $MRIM_CS_PING = 0x1006; ## C->S, empty

my $MRIM_CS_USER_STATUS = 0x100F; ## S->C, UL status, LPS user
my $STATUS_ONLINE = 0x00000001;

my $MRIM_CS_MESSAGE = 0x1008; ## S->C, UL flags, LPS to, LPS message, LPS rtf-message
my $MESSAGE_FLAG_NORECV = 0x00000004;


Пишем саб, формирующий пакет (правильнее будет сказать, формирующий его хидер - данные, которые ему передаются, должны быть уже заранее правильно сформированы):


sub make_mrim_packet
{
my ($msg, $data) = @_; ## получаем параметры
my ($magic, $proto, $seq, $from, $fromport) = ($CS_MAGIC, $PROTO_VERSION, $seq_real, 0, 0);
my $dlen = 0; ## длина данных равна 0 или
$dlen = length($data) if $data; ## если есть данные, то рассчитывается их длина
my $mrim_packet = pack("L11", $magic, $proto, $seq, $msg, $dlen, $from, $fromport, 0, 0, 0, 0);
## пакуем заголовок шаблоном "L"
$mrim_packet .= $data if $data; ## добавляем данные, если они есть
return $mrim_packet; ## возвращаем готовый к отправке пакет
}



[ Взаимодействие client <-> server ]

Для того, чтоб устаовить соединение с mrim-сервером, нужно прежде получить его ip и port. Для этого необходимо установить tcp-соединение с mrim.mail.ru:2042 или mrim.mail.ru:443. Проделав это, клиент получает рекомендуемый для соединения ip-адрес и порт. Итак, вот саб, возвращающий ip:port для коннекта:


sub get_host_port
{
my $sock1 = new IO::Socket::INET
(
PeerAddr => 'mrim.mail.ru',
PeerPort => 2042, ## как вариант можно использовать 443
PeerProto => 'tcp',
TimeOut => 10
);

sysread ($sock1, my $answ, 18);
close $sock1;
chomp $answ;
return split /:/, $answ;
}


Получив ip-адрес и порт, мы можем создавать соединение с сервером для прохождения авторизации, которая происходит следующим образом:


,---. ,---.
| C |---------MRIM_CS_HELLO------->| S |
| L |<------MRIM_CS_HELLO_ACK------| E |
| I | | R |
| E |--------MRIM_CS_LOGIN2------->| V |
| N |<------MRIM_CS_LOGIN_ACK------| E |
| T |(или <---MRIM_CS_LOGIN_REJ---)| R |
`---' `---'


Клиент посылает пакет "HELLO", в ответ получает "HELLO_ACK" с данными (UL) в которых содержится ожидаемая частота пинга (ping_period). Клиент должен пинговать сервер специальным пакетом через интервал, равный ping_period секунд. Сервер может изменять ping_period, посылая специальный пакет клиенту, но обычно ping_period равен 30 секундам. Напишем саб для отпавления HELLO-пакета и получения значения ping_period из него:


sub hello
{
print $sock make_mrim_packet($MRIM_CS_HELLO);
sysread ($sock, my $ack, 48); ## принимаем 48 байт (44 - хидер, 4 - данные)
my ($magic, $proto, $seq, $msg, $dlen, $from, $fromport, $r1, $r2, $r3, $r4, $data) = unpack ("L12", $ack);
$ping_period = $data; ## получаем значение ping_period
$seq_real++; ## $seq_real - это в моем коде счетчик seq
print "[+] connected..\n" if $data;
}


Заодно напишем и саб для осуществления пинга сервера. Он будет очень простым:


sub ping
{
print $sock make_mrim_packet($MRIM_CS_PING);
$seq_real++;
}


Теперь нужно переслать серверу пакет MRIM_CS_LOGIN2, который содержит информацию, необходимую для авторизации: LPS login, LPS password, UL status и LPS user_agent. login и password - это, понятно что, статус - тоже, а user_agent - это описание клиента, может быть любым. При удачной авторизации сервер отвечает нам пакетом MRIM_CS_LOGIN_ACK, при неудачной - MRIM_CS_LOGIN_REJ, в данных которого содержится причина отказа в авторизации. Теперь воплотим это в коде:


sub login
{
my $data = pack ("L", length($login)) . $login . ## упаковываем LPS-данные
pack ("L", length($password)) . $password .
pack ("L", $status) . ## а вот так UL
pack ("L", length($user_agent)) . $user_agent;

print "[~] try to login as $login:$password\n";
print $sock make_mrim_packet($MRIM_CS_LOGIN2, $data); ## посылаем пакет
$seq_real++; ## не забывая про счетчик сообщений
sysread ($sock, my $ack, 48); ## считываем ответ
my ($magic, $proto, $seq, $msg, $dlen, $from, $fromport, $r1, $r2, $r3, $r4, $data_ack) = unpack ("L12", $ack);
## и распаковываем его
if ($msg == $MRIM_CS_LOGIN_ACK) ## проверяем удачно ли прошла авторизация
{
print "[+] authorization succesfull\n";
}
elsif ($msg == $MRIM_CS_LOGIN_REJ)
{
print "[-] bad authorization:$data_ack\n";
}
else
{
print "[!] something wrong!\n";
}
}



[ Ложки нету =) ]

По сути, у нас есть уже все необходимое, чтоб вывести в онлайн наш mrim.pl. Но просто висящий в онлайне скрипт - это совсем неинтересно, и я решил добавить в статью код, отправяляющий сообщение на указанный адрес. Саб этот я упростил до безобразия, не сделав возможность устанавливать флаги, не сделав проверку на получение адресатом сообщения и еще многие вещи, которые можно было бы сделать (впрочем, практически во всех вышеприведенных сабах стоило бы доработать некоторые моменты).

Данные которые должен содержать пакет сообщения: UL flags, LPS to, LPS message, LPS rtf-message. Установив нужные флаги, можно указать тип сообщения (например, указать, что пересылаемые данные являются списком контактов). Я установил только флаг, означающий отсутствие необходимости присылать пакет о подтверждении доставки сообщения. Сообщение можно оформить и в rtf-формате, но мне это нафиг не нужно, потому в rtf-message отправляется ноль. Итак саб, отправляющий сообщение:


sub message
{
my ($to, $text) = @_; ## получаем мыло адресата и текст сообщения
my $data = pack ("L", $MESSAGE_FLAG_NORECV) . ## выставим нужный флаг
pack ("L", length($to)) . $to .
pack ("L", length($text)) . $text .
pack ("L", '0');

print $sock make_mrim_packet($MRIM_CS_MESSAGE, $data);
$seq_real++;

}


Теперь соберем все это воедино, добавив основной код:


#!/usr/bin/perl

use strict;
use warnings;
use IO::Socket::INET;


## config ##

my $login = 'anti@mail.ru'; ## логин
my $password = 'g00dp4ss'; ## пасс
my $user_agent = 'mrim.pl'; ## описание агента


## constants ## ниже вставь константы из первой врезки с кодом

< ...constants here... >

## vars ##

my $seq_real = 0; ## счетчик комманд
my $ping_period = 30; ## интервал для пинга
my $status = $STATUS_ONLINE; ## статус


## main ##

my ($host, $port) = get_host_port(); ## берем хост:порт
print "[~] connecting to $host:$port..\n";

my $sock = new IO::Socket::INET ## коннектимся
(
PeerAddr => $host,
PeerPort => $port,
PeerProto => 'tcp',
TimeOut => 10
);


hello(); ## хеллоу и ..
login(); ## логинимся
sleep $ping_period; ## просто повисим в онлайне с полминуты
ping(); ## пинг
message('matrix@bk.ru', 'There is no spoon, Neo..');
## отправляем сообщение на matrix@bk.ru
sleep $ping_period; ## продолжаем еще некоторое время на-
ping(); ## ходиться в онлайне
sleep 10;

## subs ## а ниже добавь все сабы, которые присутствовали в статье

< ...subs here... >

## eof..


Запускаем:


D:\perl-mrim>perl mrim.pl
[~] connecting to 194.67.57.244:2041..
[+] connected..
[~] try to login as anti@mail.ru:g00dp4ss..
[+] authorization succesfull


Наблюдая за anti@mail.ru из официального mrim-клиента, видим как он выходит в онлайн, а затем получаем от него сообщение: "There is no spoon, Neo.." =)


[ outr0 ]

На этом все, т.к. приведенной информации уже вполне достаточно для того, чтоб ты мог начать писать свои тулзы, взаимодействующие с системой МАгент. Жду теперь интересных релизов по этой теме..


[ Links ]

http://agent.mail.ru - официальный сайт Mail.ru Агент
http://agent.mail.ru/dev-license.html - официальное описание протокола MMP
http://digimortal.0x48k.cc/articlz/mrim-packets.txt - отредактированное мной описание пакетов mrim
http://hellknights.void.ru - сайт моей тимы
http://0x48k.cc - форум DarkSide ResearcherZ



Специально для форума Античат..

x-treem
16.04.2007, 12:13
кста, посоветуйте хороший сниффер

Digimortal
16.04.2007, 13:18
кста, посоветуйте хороший сниффер
wireshark (он же ethereal)..

KSURi
16.04.2007, 13:48
Весьма познавательно)
Насчет кода: я никак не пойму, зачем многие люди юзают sysread/write ? Ты вроде юзаешь IO::Socket, так почему нельзя обойти просто $sock->send/recv ? Тем более, что sysread/write могут вызывать проблемы в некоторых ситуациях...

ЗЫ:

*** (20:22:04 2/04/2007)
но протокол магента писали бляди какие-то
-
*** (20:22:41 2/04/2007)
нет ну нах им надо делать при получении кл стока полей и писать, чтобы мы ИГНОРИРОВАЛИ ИХ
-
*** (20:25:30 2/04/2007)
нахуя им строки длиной в размер DWORD?
-
*** (20:25:36 2/04/2007)
этоже более 2 гб даты)
-
*** (20:26:29 2/04/2007)
нахуя они шлют норм мессаги "как надо", а оффлайн мессаги в формате рфц, т.е. бля получать сообщения - легко, а вот переделать этот двиг под офф мессаги за 5 мин никак

Тем не менее, этот человек разобрался в протоколе довольно глубоко)

x-treem
16.04.2007, 14:29
KSURi упорно подражает Perl Underground)))
шутко
зачем ты придераешься к коду? ведь фишка статьи обьяснить работу протокола а не показать примеры красивого кода. Обычный пример.
я думаю ты излишне строг.

fucker"ok
16.04.2007, 14:33
Хорошо. Многим будет интересно. В своё время разобрался в этом протоколе и очень полезный опыт получил. Никогда до того бинарными протоколами не занимался.

Digimortal
16.04.2007, 14:36
Насчет кода: я никак не пойму, зачем многие люди юзают sysread/write ? Ты вроде юзаешь IO::Socket, так почему нельзя обойтись просто $sock->send/recv ? Тем более, что sysread/write могут вызывать проблемы в некоторых ситуациях...

тут ты прав.. немного позже поправлю код.. (у меня почему-то уже вошло в привычку использовать IO::Socket тока для открытия сокета =/)..


KSURi упорно подражает Perl Underground)))
шутко
зачем ты придераешься к коду? ведь фишка статьи обьяснить работу протокола а не показать примеры красивого кода. Обычный пример.
я думаю ты излишне строг.
да нет, KSURi все верно говорит.. ) и Perl Underground - это тру ).. если не обращать внимание на "мелкие" погрешности в своем коде, то они со временем становятся привычкой, и каждый твой скрипт будет в итоге говном.. а код просто обязан быть красивым, имхо =)

KSURi
16.04.2007, 14:43
KSURi упорно подражает Perl Underground)))
шутко
зачем ты придераешься к коду? ведь фишка статьи обьяснить работу протокола а не показать примеры красивого кода. Обычный пример.
я думаю ты излишне строг.
Не совсем верно. Я взял себе за правило писать на более-менее хорошем тоне, а не подражать Perl Underground. Езин всего лишь толкает хороший тон в массы, он его не изобрел.

А по поводу sysread/write:
It bypasses
buffered IO, so mixing this with reads (other than sysread()), "print", "write", "seek", "tell", or "eof" may cause confusion because the perlio and stdio layers usually buffers data.

Т.е. при использовнии sysread и print (или syswrite и while <$sock>) могут получиться проблемы.

За исследование протокола я уже сказал спасибо в виде +мах. Жду исследований на тему отправки смс ;)

x-treem
16.04.2007, 17:32
MRIM_CS_HELLO_ACK:
EF BE AD DE 0D 00 01 00 00 00 00 00 02 10 00 00 я╛н▐............
04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
48 58 EB 0E 74 34 BF BF D8 EE BE BF 1E 00 00 00 HXы.t4┐┐╪ю╛┐....
[48 bytes]

такс. стоп. где в этом пакете время пинга($ping_period)? не могу найти

Digimortal
16.04.2007, 17:41
1E 00 00 00 - так вот оно )
1Eh = 30d

x-treem
16.04.2007, 18:20
хех, я после того как запостил сам ужо сообразил)

Digimortal
16.04.2007, 18:41
кстати, я тока щас обратил внимание на то, что зарезервированные поля похоже все же используются в текущей версии протокола:


EF BE AD DE 0D 00 01 00 00 00 00 00 02 10 00 00 я╛н▐............
04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
B8 21 E7 0E 44 65 86 BF A8 1F 86 BF 1E 00 00 00 ╕!ч.DeЖ┐и.Ж┐....

EF BE AD DE 0D 00 01 00 01 00 00 00 04 10 00 00 я╛н▐............
00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 ................
1F 00 00 00 0A 00 00 2B 07 F8 00 00 .......+.°..

x-treem
16.04.2007, 18:55
А не знаете ещё сниферов, что б видеть трафф только одной проги, а не всех?
и кста, не могу найти в пакете место где находится номер пакета (в коде $seq_real)

Digimortal
16.04.2007, 19:02
А не знаете ещё сниферов, что б видеть трафф только одной проги, а не всех?
там же фильтры настраиваются.. : /

а номер пакета с 9-го по 12-й байт включительно занимает..

x-treem
16.04.2007, 19:19
угу, спасибо
вот ещё фишка
когда в клиент мессдж идёт, надо выслать потверждение.
знаешь как?
что то я пока не разберусь

Digimortal
16.04.2007, 19:34
гляди в описании пакетов, там все это расписано.. и если ты вникнешь в содержимое статьи, то все будет предельно ясно:

[ Доставка сообщения (sc): MRIM_CS_MESSAGE_ACK = 0x1009 ]

UL msg_id ## Номер пакета (Sequence) этого сообщения для отправителя
UL flags ## Возможные значения описаны в MRIM_CS_MESSAGE
LPS from ## Адрес отправителя
LPS message ## текстовая версия сообщения
LPS rtf-message ## форматированная версия сообщения



[ Подтверждение получения сообщения (cs): MRIM_CS_MESSAGE_RECV = 0x1011 ]

LPS from
UL msg_id

~Отправляется получателем сообщения сразу после прихода MRIM_CS_MESSAGE_ACK, если флаги MRIM_CS_MESSAGE_ACK не содержали MESSAGE_FLAG_NORECV. from и msg_id должны быть скопированы из MRIM_CS_MESSAGE_ACK и имеют то же значение.

тоесть, получив сообщение (MRIM_CS_MESSAGE_ACK), ты должен вытащить из данных LPS from, UL msg_id и отправить их как данные в пакете MRIM_CS_MESSAGE_RECV. Все это можно сделать по аналогии с уже приведенными в статье примерами кода..

x-treem
16.04.2007, 20:10
мне сразу несколько приходит
EF BE AD DE 0D 00 01 00 03 00 00 00 09 10 00 00 я╛н▐............
1A 01 00 00 00 00 00 00 00 00 00 00 78 ED BE BF ............xэ╛┐
20 45 57 48 49 44 2D 2D 2D 00 00 00 EWHID---...
[44 bytes]

08 00 00 00 80 00 00 00 12 00 00 00 6D 61 7A 61 ....А.......maza
67 61 6E 64 6F 6E 40 6D 61 69 6C 2E 72 75 08 00 gandon@mail.ru..
00 00 6C 6C 6C 6C 6C 6C 6C 6C EC 00 ..llllllllь.
[44 bytes]

00 00 65 4E 70 56 54 30 6B 4F 67 7A 41 4D 6A 4B ..eNpVT0kOgzAMjK
71 65 6B 50 67 44 54 30 68 43 4F 46 52 38 6F 30 qekPgDT0hCOFR8o0
64 66 51 68 61 49 6D 69 5A 56 43 4F dfQhaImiZVCO
[44 bytes]

30 42 38 64 49 2B 68 68 71 36 53 4C 58 6B 6B 61 0B8dI+hhq6SLXkka
57 78 5A 38 59 48 51 73 67 54 65 34 61 55 4C 51 WxZ8YHQsgTe4aULQ
4D 5A 52 72 65 44 75 76 57 4D 4E 77 MZRreDuvWMNw
[44 bytes]

79 30 73 5A 5A 75 36 47 58 6F 47 52 57 6E 47 57 y0sZZu6GXoGRWnGW
77 4D 4F 58 63 65 42 77 6F 32 4F 41 39 57 44 54 wMOXceBwo2OA9WDT
4B 4E 4A 74 50 71 4C 49 64 34 6C 65 KNJtPqLId4le
[44 bytes]

32 43 48 50 76 6E 4F 42 55 2F 64 69 6D 4C 47 56 2CHPvnOBU/dimLGV
54 30 4D 61 46 4D 31 55 49 79 6D 6A 63 4E 39 4D T0MaFM1UIymjcN9M
6D 59 51 4B 48 7A 6B 36 45 74 37 73 mYQKHzk6Et7s
[44 bytes]

44 64 6D 63 66 46 42 53 31 67 55 67 78 75 4D 6D DdmcfFBS1gUgxuMm
6C 51 71 50 74 4F 55 74 66 51 37 51 6C 47 4C 69 lQqPtOUtfQ7QlGLi
72 2F 4B 66 69 6D 33 50 7A 78 6F 43 r/Kfim3PzxoC
[44 bytes]

78 51 35 34 6A 76 72 65 74 4B 58 6C 4C 6C 55 4E xQ54jvretKXlLlUN
6B 3D k=
[18 bytes]


и хз откуда выдирать.
точнее думаю с первого, но не могу догнать что за остальные пакеты.

Digimortal
16.04.2007, 20:32
это все один пакет )
просто в примерах в статье я всегда знал сколько будет размер получаемого пакета и выставлял его в sysread, но в твоем случае размер пакета заранее неизвестен - ведь данные могут быть различной длины.. у тебя первое - это заголовок - из него можно взять длину данных 1A 01 00 00 = 11Ah = 282 байта, а затем принять эти 282 байта - это будут данные пакета.. из этих данных и брать нужные значения..

x-treem
16.04.2007, 20:34
наверное я идиот(

x-treem
16.04.2007, 22:44
вот посмотри подалуйсто:


EF BE AD DE 0D 00 01 00 03 00 00 00 09 10 00 00 я╛н▐............
18 01 00 00 00 00 00 00 00 00 00 00 18 87 9A BF .............ЗЪ┐
20 45 57 48 49 44 2D 2D 2D 00 00 00 05 00 00 00 EWHID---.......
80 00 00 00 12 00 00 00 6D 61 7A 61 67 61 6E 64 А.......mazagand
6F 6E 40 6D 61 69 6C 2E 72 75 06 00 00 00 61 73 on@mail.ru....as
64 61 73 64 EC 00 00 00 65 4E 70 56 54 38 73 4B dasdь...eNpVT8sK
67 7A 41 51 44 4B 55 6E 77 58 2F 77 45 35 49 59 gzAQDKUnwX/wE5IY
44 38 58 66 36 48 45 76 4D 51 38 4E 54 61 4D 6B D8Xf6HEvMQ8NTaMk
73 54 32 49 48 39 71 76 73 61 75 6C 68 63 4C 75 sT2IH9qvsaulhcLu
73 44 44 44 7A 4F 79 4A 45 50 4C 43 58 53 42 6D sDDDzOyJEPLCXSBm
79 30 43 47 35 41 35 51 55 38 39 34 77 30 41 62 y0CG5A5QU894w0Ab
61 2B 6D 4F 58 6F 61 65 55 58 46 5A 77 49 34 68 a+mOXoaeUXFZwI4h
35 38 37 6A 51 63 45 47 35 38 47 71 51 63 5A 6B 587jQcEG58GqQcZk
4D 71 32 75 63 68 6A 76 73 6C 32 52 59 2F 38 63 Mq2uchjvsl2RY/8c
70 2B 4C 48 72 6D 57 78 67 42 72 39 47 4E 47 6D p+LHrmWxgBr9GNGm
61 69 45 61 7A 5A 73 47 2B 6D 68 4D 6F 4E 44 35 aiEazZsG+mhMoND5
32 64 41 57 4E 66 42 77 35 6E 6C 7A 51 51 75 59 2dAWNfBw5nlzQQuY
46 59 4E 4A 52 67 30 4B 66 54 39 4E 36 68 71 36 FYNJRg0KfT9N6hq6
6F 30 48 69 6F 70 4A 4A 34 38 43 33 34 35 36 4F o0HiopJJ48C3456O
38 72 4A 41 6C 7A 4D 2B 74 32 30 62 65 51 4F 6D 8rJAlzM+t20beQOm
55 45 2F 6E UE/n
[324 bytes]


сначало вроде всё понятно, но вот что такое

eNpVT8sK
gzAQDKUnwX/wE5IY
D8Xf6HEvMQ8NTaMk
sT2IH9qvsaulhcLu
sDDDzOyJEPLCXSBm
y0CG5A5QU894w0Ab
a+mOXoaeUXFZwI4h
587jQcEG58GqQcZk
Mq2uchjvsl2RY/8c
p+LHrmWxgBr9GNGm
aiEazZsG+mhMoND5
2dAWNfBw5nlzQQuY
FYNJRg0KfT9N6hq6
o0HiopJJ48C3456O
8rJAlzM+t20beQOm
UE/n


это ведь не просто мусор?

Digimortal
16.04.2007, 22:54
>> это ведь не просто мусор?

нет конечно, это rtf-текст твоего сообщения, упакованный gzip и закодированный base64..
прочитай в описании пакетов про MRIM_CS_MESSAGE: http://digimortal.0x48k.cc/articlz/mrim-packets.txt

x-treem
16.04.2007, 23:14
это я читал))) толбко я не могу понять для чего он нужен

Digimortal
16.04.2007, 23:22
вы МАгентом пользовались хоть раз? там можно пересылать отформатированный в формате rtf текст (фон цветной, шрифт ит.д.) - это я думаю вам нафик не надо, если конечно вы свой мрим-клиент не собрались писать.. )

x-treem
17.04.2007, 08:53
пользовался... раз пять... надо наверное поюзать

x-treem
17.04.2007, 11:23
вот дампы пакетов:
мой:

EF BE AD DE 0A 00 01 00


серва

EF BE AD DE 0D 00 01 00


версия протокола это именно 0D 00 01 00
так почему они различаются?
неужели мэил уже успели изменить протокол?

Digimortal
17.04.2007, 16:01
ну да, а что в этом удивительного?
в МАгенте постоянно появляются новые возможности, а следовательно и новые версии протокола появляются..

x-treem
17.04.2007, 19:02
ну всё равно как - то...
для меня немног времени прошло, а уже на три еденички протокол поменяли
всмысле три раза
я думаю мэилпрото не станет таким как асику.
тоесть не будет делать так, что клиенты работающие по старому протоколу, не смогут дажо залогинитсо.

x-treem
18.04.2007, 15:29
хм, строю пакет, вот дамп

EF BE AD DE 0A 00 01 00 02 00 00 00 08 10 00 00 я╛н▐............
3D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =...............
00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 ............@...
12 00 00 00 6D 61 7A 61 67 61 6E 64 6F 6E 40 6D ....mazagandon@m
61 69 6C 2E 72 75 1B 00 00 00 54 68 65 72 65 20 ail.ru....There
69 73 20 6E 6F 20 73 70 6F 6F 6E 2C 20 4E 65 6F is no spoon, Neo
2E 2E 21 21 21 00 00 00 00 ..!!!....
[105 bytes]


не могу понять почему не доходит.
если поставить NORECV (04 00 00 00), мессага прекрасно идёт, а если rtf, то не доходит.
плюс нету потвержения.
помогите

и кста, если не трудно, преведите пример потверждения получения мессаги.
никак не могу понять как он строитсо

Digimortal
18.04.2007, 18:37
ну, чтоб ставить флаг rtf, надо саму rtf-часть наверно в сообщение вкладывать.. а зачем тебе это? поставь просто в значение флага 0..
а собрать пакет для подтверждения очень просто:

sub message_recv
{
my ($from, $msg_id) = @_;
my $data = pack ("L", length($from)) . $from .
pack ("L", $msg_id);

print $sock make_mrim_packet( $MRIM_CS_MESSAGE_RECV, $data);
$seq_real++;
}

x-treem
18.04.2007, 18:52
хех, если бы всё так просто
просто не так выразился, я имел ввиду дамп а не сабу.
сорри.
тут вот в чём вопрос:
from - это мыло отправителя или его айпи?
msg_id - это seq пакета с мессаджем котороый пришёл?

вот это у мну и составило проблему.

Digimortal
18.04.2007, 19:12
>> from - это мыло отправителя или его айпи?

мыло конечно..

>> msg_id - это seq пакета с мессаджем котороый пришёл?

нет.. это поле msg_id в данных пакета..

x-treem
19.04.2007, 10:04
хммм, вот посмотри какой пакет потверждения получился:

EF BE AD DE 0A 00 01 00 05 00 00 00 11 10 00 00 я╛н▐............
1A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 12 00 00 00 ................
6D 61 7A 61 67 61 6E 64 6F 6E 40 6D 61 69 6C 2E mazagandon@mail.
72 75 03 00 00 00 ru....
[70 bytes]


а пакет мессажа вот так выглядит

EF BE AD DE 0D 00 01 00 03 00 00 00 09 10 00 00 я╛н▐............
24 01 00 00 00 00 00 00 00 00 00 00 18 87 9A BF $............ЗЪ┐
20 45 57 48 49 44 2D 2D 2D 00 00 00 C3 00 00 00 EWHID---...├...
80 00 00 00 12 00 00 00 6D 61 7A 61 67 61 6E 64 А.......mazagand
6F 6E 40 6D 61 69 6C 2E 72 75 0E 00 00 00 61 73 on@mail.ru....as
64 61 73 64 73 64 61 73 64 73 61 64 F0 00 00 00 dasdsdasdsadЁ...
65 4E 70 56 6A 30 30 4B 67 7A 41 51 68 55 50 70 eNpVj00KgzAQhUPp
53 76 41 4F 48 69 47 4A 63 56 47 38 52 70 65 7A SvAOHiGJcVG8Rpez
69 66 6D 78 6F 57 6D 55 4A 4C 59 4C 38 62 41 39 ifmxoWmUJLYL8bA9
69 52 32 56 46 67 6F 7A 6A 34 45 33 38 2F 6A 6D iR2VFgozj4E38/jm
52 41 68 35 59 38 38 51 73 32 55 67 51 33 4B 37 RAh5Y88Qs2UgQ3K7
71 4C 46 6E 76 47 47 67 6A 62 56 30 55 79 39 44 qLFnvGGgjbV0Uy9D
7A 36 69 34 7A 47 43 48 6B 48 50 6E 63 61 42 67 z6i4zGCHkHPncaBg
67 2F 4E 67 31 55 33 47 5A 44 4B 74 72 76 49 32 g/Ng1U3GZDKtrvI2
50 47 53 37 6F 4D 66 2B 50 55 37 46 7A 31 33 4B PGS7oMf+PU7Fz13K
59 67 59 31 2B 43 46 69 54 4E 56 43 4E 4A 6F 33 YgY1+CFiTNVCNJo3
44 66 54 52 6D 45 43 68 38 35 4F 68 4C 65 37 41 DfTRmECh85OhLe7A
30 35 6E 58 33 51 55 74 59 46 49 4D 52 68 6B 31 05nX3QUtYFIMRhk1
4B 4D 77 39 53 4F 6F 61 75 70 30 67 63 56 48 4A KMw9SOoaup0gcVHJ
70 4C 45 4F 6B 52 71 2B 72 42 73 46 6E 70 55 46 pLEOkRq+rBsFnpUF
70 70 33 78 79 58 56 64 79 51 64 53 77 46 4D 32 pp3xyXVdyQdSwFM2
[336 bytes]


но он ничего не потверждает(
не могу понять

Digimortal
19.04.2007, 16:09
ты должен отпраялять не тот seq, что в заголовке MRIM_CS_MESSAGE_ACK, а тот что в msg_id этого пакета.. у тебя он равен C3 00 00 00 .. а ты отправляешь 03 00 00 00 .. (это я, наверно, своим предыдущим ответом немного сбил тебя с толку - msg_id отпраляется не тот что получает получатель сообщения, а тот, что передает отправитель.. )

x-treem
01.06.2007, 17:21
вот смотрел старые скрипты. много думал. наткнулся на скрипты свзяаные с мэил агентом.
вспомнил)) и вот значит вспомнил что хотел бота написать. тока думал как же сделать посылку этого гадостного пинга (пакет уходящий каждые 30 секунд). додумался. и забыл.
а сейчас вспомнил. значит можно просто использовать потоки(модуль threads). то есть запускаем бота. и выделяем отдельный поток, который будет слать пинг, а затем спать 30 секунд. вот вообщем то и все. написал потому, что в определённый момнет это составило для мну проблему. надеюсь что кому то помогу.

Digimortal
01.06.2007, 18:50
у меня в черновом варианте кода, рядом с функцией пинга комментарий даже стоит: типа, запустить отдельный тред и пинговать из него... )

yxactuk
05.10.2007, 22:36
http://digimortal.0x48k.cc/articlz/mrim-packets.txt - отредактированное мной описание пакетов а можно куда-нибудь перезалить, если у кого-нить остался, ато ссылка битая.

GreenBear
05.10.2007, 22:47
http://agent.mail.ru/developers/

yxactuk
06.10.2007, 15:53
http://agent.mail.ru/developers/ Вообще не в тему. Если раскрыть глаза и вчитаться в пост то там написано -
http://digimortal.0x48k.cc/articlz/mrim-packets.txt - отредактированное мной описание пакетов. Я и хотел бы посматреть, что именно автор там писал, может чего-нибудь новенькое или поподробней.

Digimortal
06.10.2007, 19:25
да ниче особо нового там не было.. я тока написал немного своих наблюдений по некоторым пакетам, добавил описания пакетов, необходимых для отправки смс, написал кое-какие идеи по этому поводу, и привел это все в более удобный (по моему мнению) вид.. сорри, но у меня щас нету возможности выложить тот файл..

sumr
09.11.2007, 15:27
да ниче особо нового там не было.. я тока написал немного своих наблюдений по некоторым пакетам, добавил описания пакетов, необходимых для отправки смс, написал кое-какие идеи по этому поводу, и привел это все в более удобный (по моему мнению) вид.. сорри, но у меня щас нету возможности выложить тот файл..

Интересует именно отправка СМС -
дайте пож информацию! :(

C!klodoL
09.11.2007, 17:06
Интересует именно отправка СМС -
дайте пож информацию! :(
автор статьи выкладывал скрипт смс флудера, его можно найти в поиске, но теперь он не работает

Digimortal
10.03.2008, 04:46
скачал щас с cpan'a модуль для работы с МАгентом: http://search.cpan.org/~aau/Net-MRIM/
обнаружил, что он весьма разросся с того момента, как я его в последний раз видел (но кусочки кода из моей статьи в нем все еще проглядуются +) ).. вобщем, там вроде уже и отправка смс есть.. т.ч. я подумал, что стоит и свой модуль выложить, может, кому пригодится - он в отличие от того, что на cpan'е очень прост и легок, т.к., собственно, только для отправки смс по MMP и служит.. )
пускай примером к статье будет.. +) вобщем, вот:
package MMPSMS;

$VERSION = '0.1';

=pod

=head1 NAME

MMPSMS - sends sms messages using MMP proto.

=head1 DESCRIPTION

Read about Mail.ru Agent SMS functionality here:
http://agent.mail.ru/help/3/1.html

=head1 SYNOPSIS

To construct object and login to mrim-server:

my $mmpsms = MMPSMS->new('matrix@mail.ru', 'password');

To add a phone number to contact list:

my $cid = $mmpsms->add_contact('no_spoon', '+79123456789');

To remove a phone number from contact list:

$mmpsms->delete_contact($cid, 'no_spoon', '+79123456789');

To send sms:

$mmpsms->send_sms('no_spoon', 'sms_text_here');

Ping:

$mmpsms->ping();

Disconnecting:

$mmpsms->close();


=head1 AUTHOR

Digimortal

=head1 COPYRIGHT

Copyright (c) 2007 Digimortal. 0x48k Crew.

=cut



use IO::Socket::INET;

use constant {

CS_MAGIC => 0xDEADBEEF,
PROTO_VERSION => 0x10008,

MRIM_CS_HELLO => 0x1001,
MRIM_CS_HELLO_ACK => 0x1002,

MRIM_CS_LOGIN2 => 0x1038,
MRIM_CS_LOGIN_ACK => 0x1004,
MRIM_CS_LOGIN_REJ => 0x1005,
MRIM_CS_LOGOUT => 0x1013,

MRIM_CS_PING => 0x1006,

MRIM_CS_USER_STATUS => 0x100f,
STATUS_OFFLINE => 0,

MRIM_CS_ADD_CONTACT => 0x1019,
CONTACT_FLAG_REMOVED => 1,
CONTACT_FLAG_SMS => 0x100000,

MRIM_CS_ADD_CONTACT_ACK => 0x101A,
CONTACT_OPER_SUCCESS => 0,
CONTACT_OPER_ERROR => 1,
CONTACT_OPER_INTERR => 2,
CONTACT_OPER_INVALID_INFO => 4,

MRIM_CS_MODIFY_CONTACT => 0x101B,
MRIM_CS_MODIFY_CONTACT_ACK => 0x101C,

MRIM_CS_CONTACT_LIST2 => 0x1037,

MRIM_CS_SMS => 0x1039,
MRIM_CS_SMS_ACK => 0x1040,

MRIM_UA => 'MRA 5.0 (build 2094);',

MRIM_ADDR => 'mrim.mail.ru',
MRIM_PORT => 2042
};

$|++;


############################
## Основные методы класса ##
############################


sub new {

my ($pkgname, $login, $password, $debug) = @_;

my $self = {};

$self->{_seq_real} = 1;
$self->{_debug} = $debug;

bless $self;

## получаем хост и порт:

my $sock1 = IO::Socket::INET->new(

PeerAddr => MRIM_ADDR,
PeerPort => MRIM_PORT,
PeerProto => 'tcp',
TimeOut => 5 );

if (!defined $sock1) {

_debug($self, 'error: can\'t connect to mrim.mail.ru');
return 0;
}

$sock1->recv(my $answ, 18);
close $sock1;
chomp $answ;

my ($host, $port) = split /:/, $answ;

## коннектимся на полученный хост:

$self->{_sock} = IO::Socket::INET->new(

PeerAddr => $host,
PeerPort => $port,
PeerProto => 'tcp',
TimeOut => 5 );

if (!defined $self->{_sock}) {

_debug($self, "error: can\'t connect to $host:$port");
return 0;
}

## посылаем пакет HELLO:

$self->{_sock}->send(_make_mrim_packet($self, MRIM_CS_HELLO));

_recv_packet($self);

## логинимся:

my $data = _lps($login)
. _lps($password)
. pack('L', STATUS_OFFLINE)
. _lps(MRIM_UA);

$self->{_sock}->send(_make_mrim_packet($self, MRIM_CS_LOGIN2, $data));

my ($msg, $data_rcv) = _recv_packet($self);

if ($msg != MRIM_CS_LOGIN_ACK) {

_debug($self, "auth error: $data_rcv");
return 0;
}

return $self;
}



sub send_sms {

my ($self, $phone, $sms_text) = @_;

my $data = pack('L', 0)
. _lps($phone)
. _lps($sms_text);

$self->{_sock}->send(_make_mrim_packet($self, MRIM_CS_SMS, $data));

my ($msg, $data_rcv) = _recv_packet($self);

return(unpack('L', $data_rcv));
}



sub add_contact {

my ($self, $name, $phone) = @_;

my $data = pack('L2', CONTACT_FLAG_SMS, 0x67)
. _lps('phone')
. _lps($name)
. _lps($phone)
. pack('L', 0);

$self->{_sock}->send(_make_mrim_packet($self, MRIM_CS_ADD_CONTACT, $data));

my ($msg, $data_rcv) = _recv_packet($self);

my ($status, $cid) = unpack('L2', $data_rcv);

if ($status == CONTACT_OPER_SUCCESS) { return $cid }

elsif ($status == CONTACT_OPER_ERROR) {
_debug($self, 'add_contact error: incorrect contact data');
}
elsif ($status == CONTACT_OPER_INTERR) {
_debug($self, 'add_contact error: internal server error');
}
elsif ($status == CONTACT_OPER_INVALID_INFO) {
_debug($self, 'add_contact error: incorrect username');
}

return 0;
}



sub delete_contact {

my ($self, $contact_id, $name, $phone) = @_;

my $flag = (CONTACT_FLAG_SMS | CONTACT_FLAG_REMOVED);

my $data = pack("L3", $contact_id, $flag, 0x67)
. _lps('phone')
. _lps($name)
. _lps($phone);

$self->{_sock}->send(_make_mrim_packet($self, MRIM_CS_MODIFY_CONTACT, $data));

my ($msg, $data_rcv) = _recv_packet($self);

my $status = unpack('L', $data_rcv);

if ($status == CONTACT_OPER_SUCCESS) { return 1 }

elsif ($status == CONTACT_OPER_ERROR) {
_debug($self, 'delete_contact error: incorrect contact data');
}
elsif ($status == CONTACT_OPER_INTERR) {
_debug($self, 'delete_contact error: internal server error');
}
elsif ($status == CONTACT_OPER_INVALID_INFO) {
_debug($self, 'delete_contact error: incorrect username');
}

return 0;
}



sub ping {

my $self = shift;

$self->{_sock}->send(_make_mrim_packet($self, MRIM_CS_PING));

_recv_packet($self);

return 1;
}



sub close {

my $self = shift;

$self->{_sock}->close;

return 1;
}



#############################
## Приватные методы класса ##
#############################


## создание пакета:

sub _make_mrim_packet {

my ($self, $msg, $data) = @_;

my $dlen = 0;
$dlen = length($data) if $data;

my $mrim_packet = pack('L5', CS_MAGIC, PROTO_VERSION,
++$self->{_seq_real}, $msg, $dlen)
. pack('L', 0) x 6;

$mrim_packet .= $data if $data;

return $mrim_packet;
}


## LPS

sub _lps { return pack('L', length $_[0]) . $_[0]; }


## получение пакета c текущим значением seq_real:

sub _recv_packet {

my ($self) = shift;

while (1) {

$self->{_sock}->recv(my $ack, 44);

my ($magic, $proto, $seq, $msg, $dlen, @other) = unpack('L11', $ack);

my $data;

$self->{_sock}->recv($data, $dlen) if $dlen;

return($msg, $data) if ($seq == $self->{_seq_real});
}
}


## вывод отладочной информации:

sub _debug {

my ($self, $msg) = @_;

print "$msg\n" if $self->{_debug};
}


return 1;

Digimortal
10.03.2008, 04:49
использовать примерно так +) :
#!/usr/bin/perl

use strict;
use warnings;

use MMPSMS;


my $user = 'matrix@mail.ru';
my $pass = 'passw00rd';

my $text = 'смско! смско! смско!';

my $name = 'lalala';
my $phone = '+7998xxxxxxx';



my $sms = MMPSMS->new($user, $pass, 1);

my $id = $sms->add_contact($name, $phone);

$sms->send_sms($phone, $text);

$sms->delete_contact($id, $name, $phone);

$sms->close();

btrfly
07.04.2008, 19:37
Кто-нибудь может мне уделить часик и помочь разобраться с протоколом?
тоже самое,только на плюсах,так как с perl'om не знаком,поэтому и спрашиваю.
з.ы.
Если никто по доброте душевной не хочет,
то с меня символическое вознаграждение размером в 10-20$ :)
icq 445408977

-Hormold-
11.05.2008, 20:01
Может кто выложить рабочий протокол, желательно на php =)

-Hormold-
25.05.2008, 22:15
http://hormold.ru/index.php?newsid=69
Вот у меня на сайте, class на php.

iluxa77
28.05.2008, 16:54
http://digimortal.0x48k.cc/articlz/mrim-packets.txt - отредактированное мной описание пакетов mrim

у когонибудь осталос????? :confused: очень хочеться знать как смс отправить правильно... а то у меня с некоторых акков почемуто неотправляеться :confused:

BEGINER
17.08.2008, 05:43
Привет. В перле вообще ничего не понимаю.
Кто-нибудь знает как заполнить заголовок пакета для М-агента, используя С?
Получаю адрес и порт сервера, отправляю Нелло и жду ответа, ответа нет, может что делаю не так?
код:
SOCKET nMailSocket;
struct mrim_packet_header_t header;
char* pheader=(char*)&header;
char buf[255];

header.magic=PROTO_VERSION;
header.proto=MRIM_CS_HELLO;
header.seq=1;
header.msg=1;
header.dlen=0;
header.from=0;
header.fromport=0;

send(nMailSocket, pheader, (int)sizeof(struct mrim_packet_header_t), 0);
memset(buf, 0, 255);
recv(nMailSocket, (LPSTR)buf, 48, 0);
cout<<buf<<endl;