ZeroAccess plugin P2P или спецификация сетевого протокола как руководство для разработки Общее Представляет из себя простой P2P загрузчик. Реализован в ZeroAccess виде плагина. P2P сеть строится следующим образом. Каждый бот имеет свой список пар <IP, time> других ботов. И периодически обменивается с другими ботами своими актуальными IP. Кроме списка IP бот может получать сначала информацию о файле имеющуюся у другого бота, а потом сам файл. Все общение между ботами производится по UDP протоколу, лишь запрос информации и скачивание файлов TCP Протокол При старте бот начинает слушать порты UDP, TCP 16464 Введу некоторое обозначение: Code: typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; Бот считывает список нод из файла, формат файла: Code: struct CFG_NODE{ [INDENT]uint32 ip; uint32 time;[/INDENT] }; Все сообщения имеют заголовок формат: Code: struct HEAD{ [INDENT]uint32 crc32; uint32 cmd; uint32 hop; uint32 data;[/INDENT] }; За хидером следуют данные зависящие от команды cmd. Команд всего 3и: Code: getL - запросить список нод retL - отдать список нод newL - публикация ноды данные за хидером шифруются таким алгоритмом: Code: void encrypt(uint8 *data, int len_data){ uint32 *p = (uint32*)data; uint32 count=len_data>>2; uint32 key = 'ftp2'; [INDENT]do{ [INDENT]*p ^= key; key = ROL(key, 1); p++; --count;[/INDENT] }while ( count );[/INDENT] } Команда getL Бот считывает ноды из файла и с периодом в 1с рассылает сообщение вида: Code: struct HEAD{ [INDENT]uint32 crc32; uint32 cmd; // 'getL' uint32 hop; // количество прыжков 0 uint32 data; // сессия, случайное число sess[/INDENT] }; HEAD head; Нода получает это сообщение и в ответ оправляет информацию о своих нодах и файлах retL. И если hop=0, то выполняет проверку на внешний IP бота отправителя. Для этого отправляет пакет: Code: struct HEAD{ [INDENT]uint32 crc32; uint32 cmd; // 'getL' uint32 hop; // количество прыжков 1 uint32 data; // ip отправителя[/INDENT] }; HEAD head; замете количество прыжков стало равно 1, это сообщение доходит в том случае если бот имеет внешний IP. Команда retL Отправляет в ответ на getL Code: struct HEAD{ [INDENT]uint32 crc32; uint32 cmd; // 'retL' uint32 hop; // значение из входящего сообщения (0 или 1) uint32 data; // sess из входящего пакета[/INDENT] }; struct BLOCK_NODE{ [INDENT]uint32 ip; uint32 time_delta;[/INDENT] }; struct BLOCK_SIGN{ [INDENT]uint32 name_file; //имя в виде числа 32 бита uint32 time; uint32 size; uint8 sign[128];[/INDENT] }; HEAD head; uint32 count_node; //количество нод не более 16 BLOCK_NODE node[count_node]; uint32 count_sign; //количество файлов не более 16 BLOCK_SIGN sign[count_sign]; Ноды в BLOCK_NODE выбираются в зависимости от времени CFG_NODE.time. При этом ноды сначала упорядочиваются по убыванию. Самое большое значение CFG_NODE.time считается самым актуальным. Выбирается не более 16и самых актуальных нод. И выполняется формирование пакетов BLOCK_NODE, причем время рассчитывается так: Определяется дельта для от текущей даты: Code: BLOCK_NODE.time_delta=now()-CFG_NODE.time При приеме пакета retL время восстанавливается: Code: CFG_NODE.time =now()-BLOCK_NODE.time_delta Новые ноды добавляются к имеющемуся списку, упорядочиваются, выбираются и сохраняются те которые не старше 32 дней. Если во входящем пакете hop=1, то бот считает себя нодой с внешним IP (супернодой), и выполняет отправку пакета newL 16 нодам из своего конфига CFG_NODE Команда newL Формируется в ответ на retL с hop=1 или newL Code: struct HEAD{ [INDENT]uint32 crc32; uint32 cmd; // 'newL' uint32 hop; // 8 прыжков или hop-1 из входящего uint32 data; // ip отправителя[/INDENT] }; HEAD head; Сообщение рассылается 16и нодам из конфига бота. При получении ботами newL сообщения, извлекается HEAD.data (ip ноды), и проверяется наличие этого ip с имеющимся списком. Если такого ip не оказалось, то производится его добавление. И повторная рассылка 16и нодам с HEAD.hop - 1, так продолжается пока HEAD.hop не станет равным нулю или ip не будет известен всем нодам. Загрузка файлов В пакетах retL имеется количество count_sign и BLOCK_SIGN. Это информация о файлах которая имеется у бота. При получении такого пакета бот проверяет цифровую подпись BLOCK_SIGN.sign, затем смотрит есть ли у него имя файла BLOCK_SIGN.name_file, если такое имя имеется то выполняется проверка времени. При выполнении всех этих условий выполняется tcp соединение, и отправляется пакет: Code: struct BLOCK_FILE{ [INDENT]uint32 name_file; uint32 time; uint32 size;[/INDENT] }; BLOCK_FILE info; В ответ приходит файл зашифрованный RC4 с ключом md5(info). Файл расшифровывается и проверяется цифровая подпись, которая берётся из ресурсов принятого файла. Если все прошло успешно, то файл сохраняется. Дополнительная литература Старая версия протокола p2p модуля, и самого ZeroAccess hxxp://www.kindsight.net/sites/default/files/Kindsight_Malware_Analysis-ZeroAcess-Botnet-final.pdf p.s Хочу заметить что этот протокол рассчитан лишь на загрузку файлов на машины юзеров. Но его можно немного модифицировать, добавить код который сможет туннелировать трафик. В качестве одного из файлов раздавать список IP на которые будут стучаться боты. А те боты на которые происходит обращение будут переправлять траф на наш CC. В результате между ботами и СС, будет прокладка в виде тех же ботов.