ANTICHAT.XYZ    VIDEO.ANTICHAT.XYZ    НОВЫЕ СООБЩЕНИЯ    ФОРУМ  
Баннер 1   Баннер 2
Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей. Здесь обсуждаются безопасность, программирование, технологии и многое другое. Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz
Вернуться   Форум АНТИЧАТ > ИНФО > Статьи > Авторские статьи
   
 
 
Опции темы Поиск в этой теме Опции просмотра

@ mrim.pl: Написание скриптов, работающих по протоколу MMP
  #1  
Старый 16.04.2007, 04:11
Аватар для Digimortal
Digimortal
Banned
Регистрация: 22.08.2006
Сообщений: 608
Провел на форуме:
6144796

Репутация: 1095


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

@ 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



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

Последний раз редактировалось Digimortal; 16.04.2007 в 13:42..
 
Ответить с цитированием
 





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT.XYZ