всем привет, на днях решил вспомнить пыхыпы и написать немного о icq протоколе и с чем его едят.
за основу своих трудов взял несколько готовых icq классов (рабочих) и пару пачек пельменей.
разберу основные моменты (реализацию проксей не сделал правда - времени мало), но конечный код можно будет использовать, как минимум, для проверки номеров на валидность.
вся реализация будет происходить через сокеты, это оптимальный вариант авторизации на icq.com

1. начало.
для начала зададим параметры подключения:

Код:
$uin = "122211"; # номер icq
$password = "bazzinga"; # соответственно пароль

далее установим соединение с сервером авторизации (lоgin.iсq.соm):

Код:
$socket = @fsockopen("login.icq.com", 5190);


q: а почему бы для скорости не сделать случайную выборку сервера?
a: на личном опыте убедился, что быстрее сервера авторизации, чем этот - нет. да и в инете полно дохлых. поэтому это реализуется только при наличие работающих и быстрых серверов.
2. первые flap и snac.
после создания подключения, считаем ответ сервера - flap и snac (о них можно почитать в гугле). эта функция чтения ответа сервера будет постоянно, но выделять как отдельную функцию не стал.

Код:
$flap = @fread($socket, 6);    
list(, $length) = @unpack("n", substr($flap, 4, 2));
$snac = @fread($socket, $length);

3. подготовка данных перед отправкой на сервер.
теперь перед нами стоит задача, сделать наши данные такие, чтобы их смог понять сервер авторизации (uin просто пакуем,а пароль - xor'им).
выделять xor пароля в отдельную функцию тоже не стал:

Код:
$data = base64_decode("8yabxdmg25jxo7nmu3qvfa==");
for ($i=0; $i<strlen($password); $i++) @$out .= chr(ord($data[$i]) ^ ord($password[$i]));

теперь у нас всё готово, осталось данные упаковать в flap и snac:

Код:
$snac = base64_decode('aaaaaq==').pack("nna*", 0x01, strlen($uin), $uin).pack("nna*", 0x02, strlen($out), $out).base64_decode('aamacelduujhc2ljabyaagekabcaa  gababgaagaaabkaagaaaboaagababqabaaaafuadwaczw4adga  cdxm=');
$flap = pack("ccnn", 0x2a, 1, $random=rand(0x0000, 0xffff), strlen($snac)); $random++;


я сделал за вас всю грязную работу, упаковав постоянные данные в base64, также убрал возможности смены версии клиента, поставив кошерную, ибо сервер ругается ссылками на icq7, если там поставить свой
и, собсна, сама отправка:

Код:
@fwrite($socket, $flap.$snac);

4. прием ответа.
для считывания ответа сервера и данных и bos-сервере (bos-сервер -- сервер, на который перенаправляет нас центр авторизации при верно введенном uin'e+пароле. собственно так мы и будем определять, верные данные отправили или нет.

Код:
$flap = @fread($socket, 6);
list(, $length) = @unpack("n", substr($flap, 4, 2));    
$snac = @fread($socket, $length);    
    while (strlen($snac) > 0) {
        list(, $type, $length) = unpack("n2", substr($snac, 0, 4));
        $tlv[$type] = substr($snac, 4, $length);
        $snac = substr($snac, 4+$length);
                }


у нас образовался массив $tlv, (type, length, value - ничто иное, как указание числового идентификатора типа данных, их длины, и, собственно, самих данных (с)destym)
в своём труде я добавил парочку проверок для блокировку ip (из-за частых подключений), неверный uin/пароль и на кривой сервер авторизации.
также, если вы хотите сделать из этого чеккер, в результате собственных наблюдений установил, что задержку между uin'ами нужно делать примерно так:


Код:
sleep(rand(4,5));


это позволяет не схватить временный бан ip при использовании только одного сервера авторизации.

Код:
$uin = "uin"; 
$password = "pwd"; 
$socket = @fsockopen("login.icq.com", 5190); 
    if ($socket)  
    { 
        $start = getmicrotime(); 
        $flap = @fread($socket, 6);     
        list(, $length) = @unpack("n", substr($flap, 4, 2)); 
        $snac = @fread($socket, $length);  
        $data = base64_decode("8yabxdmg25jxo7nmu3qvfa=="); 
        for ($i=0; $i<strlen($password); $i++) @$out .= chr(ord($data[$i]) ^ ord($password[$i])); 
        $snac = base64_decode('aaaaaq==').pack("nna*", 0x01, strlen($uin), $uin).pack("nna*", 0x02, strlen($out), $out).base64_decode('aamacelduujhc2ljabyaagekabcaa  gababgaagaaabkaagaaaboaagababqabaaaafuadwaczw4adga  cdxm='); 
        $flap = pack("ccnn", 0x2a, 1, $random=rand(0x0000, 0xffff), strlen($snac)); $random++; 
        @fwrite($socket, $flap.$snac); 
        $flap = @fread($socket, 6); 
        list(, $length) = @unpack("n", substr($flap, 4, 2));     
        $snac = @fread($socket, $length);     
        while (strlen($snac) > 0) { 
            list(, $type, $length) = unpack("n2", substr($snac, 0, 4)); 
            $tlv[$type] = substr($snac, 4, $length); 
            $snac = substr($snac, 4+$length); 
                    } 
        echo "<br>"; echo $uin.":".$password." - "; 
        if ( @trim($tlv[0x04]) == 'http://www.aol.com?ccode=us&lang=en' ) $debug = 'слишком быстро...';  
        else if( @strstr( $tlv[0x04], 'mismatch_passwd' ) ) $debug = 'неверный пароль.'; 
        else if (!(@$tlv[0x05] && @$tlv[0x06])) $debug = 'ошибка при авторизации: не выдан bos-сервер (слишком много переподключений или выбран корявый сервер).';  
        else $debug = 'пароль соответствует uin\'у.'; 

        @fclose($socket); echo "<b>".$debug."</b>", "  (time: ".substr((getmicrotime()-$start), 0, 4)." s.)", "<br><br>"; 
    } else echo $debug = 'невозможно создать подключение с сервером :('; 

function getmicrotime() 
{ 
$mt = explode(" ", microtime() ); 
return ((float)$mt[0] + (float)$mt[1]); 
}




5. выведение номера в on-line.
для выведения номера в онлайн, придётся сделать следующиее:
- закрыть подключение с сервером авторизации
- подключиться к bos-серверу
- отправить cookies
- отправить пакет для готовности работы
- выполнить необходимые действия и завершить работу закрыванием соединения
реализация:


Код:
{
                echo '<br>подключаемся...'; # выведем сообщение, что всё ок и сейчас подключимся
                list( $server, $port ) = explode( ':', $tlv[0x05] );
                $socket = @fsockopen($server, $port); # создаем подключение с выданным нам bos-сервером
                if( !$socket ) die('<b>bos-сервер  ( </b>'.$tlv[0x05].'<b> )  недоступен.попробуйте ещё раз.</b>'); # выведем сообщение, если bos-сервер недоступен
                $snac = base64_decode("aaaaaq==").pack("nna*", 0x06, strlen($tlv[0x06]), $tlv[0x06]); # отдаём запакованые cookies
                $flap = pack("ccnn", 0x2a, 1, $random, strlen($snac)); $random++; # создаем flap для этих данных
                @fwrite($socket, $flap.$snac); # отправляем данные серверу
                $snac = base64_decode("aaeaagaaaaaaagabaambeakkaaiaaqebaooaawabaracigavaa  ebeakkaaqaaqeqaooabgabaracigajaaebeakkaaoaaqeqaoo=  "); # опять делаю всю грязную работу, т.е. отсылаем серверу пакет о готовности работы
                $flap = pack("ccnn", 0x2a, 2, $random, strlen($snac)); # создаем flap для этих данных
                @fwrite($socket, $flap.$snac); # отправляем данные серверу
                /*  цикл  */

                    for( $i=0; $i <= 3; $i++) # цикл для работы с номером
                    {
                        sleep(1);
                    }

                /*  конец цикла  */
                @fclose($socket); # закрываем соединение, работа с icq номером завершена.
            }

конечный код, с выведением номера в онлайн:

Код:
$uin = "uin"; 
$password = "pwd"; 
$socket = @fsockopen("login.icq.com", 5190); 
    if ($socket)  
    { 
        $start = getmicrotime(); 
        $flap = @fread($socket, 6);     
        list(, $length) = @unpack("n", substr($flap, 4, 2)); 
        $snac = @fread($socket, $length);  
        $data = base64_decode("8yabxdmg25jxo7nmu3qvfa=="); 
        for ($i=0; $i<strlen($password); $i++) @$out .= chr(ord($data[$i]) ^ ord($password[$i])); 
        $snac = base64_decode('aaaaaq==').pack("nna*", 0x01, strlen($uin), $uin).pack("nna*", 0x02, strlen($out), $out).base64_decode('aamacelduujhc2ljabyaagekabcaa  gababgaagaaabkaagaaaboaagababqabaaaafuadwaczw4adga  cdxm='); 
        $flap = pack("ccnn", 0x2a, 1, $random=rand(0x0000, 0xffff), strlen($snac)); $random++; 
        @fwrite($socket, $flap.$snac); 
        $flap = @fread($socket, 6); 
        list(, $length) = @unpack("n", substr($flap, 4, 2));     
        $snac = @fread($socket, $length);     
        while (strlen($snac) > 0) { 
            list(, $type, $length) = unpack("n2", substr($snac, 0, 4)); 
            $tlv[$type] = substr($snac, 4, $length); 
            $snac = substr($snac, 4+$length); 
                    } 
        echo "<br>"; echo $uin.":".$password." - "; 
        if ( @trim($tlv[0x04]) == 'http://www.aol.com?ccode=us&lang=en' ) $debug = 'слишком быстро...';  
        else if( @strstr( $tlv[0x04], 'mismatch_passwd' ) ) $debug = 'неверный пароль.'; 
        else if (!(@$tlv[0x05] && @$tlv[0x06])) $debug = 'ошибка при авторизации: не выдан bos-сервер (слишком много переподключений или выбран корявый сервер).';  
        else $debug = 'пароль соответствует uin\'у.'; 

        @fclose($socket); echo "<b>".$debug."</b>", "(time: ".substr((getmicrotime()-$start), 0, 4)." s.)", "<br><br>"; 
            if( $debug == 'пароль соответствует uin\'у.') # проверяем на валидность uin 
            { 
                echo '<br>подключаемся...'; # выведем сообщение, что всё ок и сейчас подключимся 
                list( $server, $port ) = explode( ':', $tlv[0x05] ); 
                $socket = @fsockopen($server, $port); # создаем подключение с выданным нам bos-сервером 
                if( !$socket ) die('<b>bos-сервер  ( </b>'.$tlv[0x05].'<b> )  недоступен.попробуйте ещё раз.</b>'); # выведем сообщение, если bos-сервер недоступен 
                $snac = base64_decode("aaaaaq==").pack("nna*", 0x06, strlen($tlv[0x06]), $tlv[0x06]); # отдаём запакованые cookies 
                $flap = pack("ccnn", 0x2a, 1, $random, strlen($snac)); $random++; # создаем flap для этих данных 
                @fwrite($socket, $flap.$snac); # отправляем данные серверу 
                $snac = base64_decode("aaeaagaaaaaaagabaambeakkaaiaaqebaooaawabaracigavaa  ebeakkaaqaaqeqaooabgabaracigajaaebeakkaaoaaqeqaoo=  "); # опять делаю всю грязную работу, т.е. отсылаем серверу пакет о готовности работы 
                $flap = pack("ccnn", 0x2a, 2, $random, strlen($snac)); # создаем flap для этих данных 
                @fwrite($socket, $flap.$snac); # отправляем данные серверу 
                /*  цикл  */ 

                    for( $i=0; $i <= 3; $i++) # цикл для работы с номером 
                    { 
                        sleep(1); 
                    } 

                /*  конец цикла  */ 
                @fclose($socket); # закрываем соединение, работа с icq номером завершена. 

            } 
    } else echo $debug = 'невозможно создать подключение с сервером :('; 

function getmicrotime() 
{ 
$mt = explode(" ", microtime() ); 
return ((float)$mt[0] + (float)$mt[1]); 
}

Автор : Daga