Я – хакер! Хроника потерянного поколения - Дмитрий Артимович
Шрифт:
Интервал:
Закладка:
Отключив CRT, я сразу лишился стандартных функций malloc/free — выделение/освобождение памяти, без которых программировать крайне сложно. Также не были доступны функции работы со строками, которые требовались модулю спама.
В ядре операционной системы память делится на два типа: выгружаемые страницы и невыгружаемые. Выгружаемые страницы, как следует из их названия, могут выгрузиться ядром ОС на диск, в файл подкачки. Невыгружаемые всегда остаются в памяти. Если процессор обращается по адресу страницы, отсутствующему в данный момент в памяти, генерируется прерывание (Interrupt Request — IRQ[30]). Прерывание перехватывает ядро ОС и подгружает нужную страничку в память. Все внешние устройства уведомляют ОС через прерывания. Хитрость заключается в том, что у каждого прерывания есть приоритет, и прерывание с более высоким приоритетом вытесняет прерывание с более низким. Теперь представьте, что случится, если сработает прерывание с приоритетом выше прерывания на подгрузку странички памяти, а обработчик этого прерывания находится на выгруженной страничке в файле подкачки. Всё, операционной системе — хана. Такие детали постоянно нужно держать в голове.
Я реализовал свои операции выделения памяти из двух пулов выгружаемых и невыгружаемых страниц. Под каждый пул выделялся сегмент памяти, а в нем уже выделялись ячейки памяти. Алгоритм использовал связанные списки и деревья для эффективного менеджмента памяти. Детальные описания алгоритмов низкоуровнего программирования выходят за рамки этой книги.
Второй сложной задачей стала работа с сетью. В ядре ОС Windows на 2008 год существовало два интерфейса, через которые можно было работать с сетью: NDIS (Network Driver Interface Specification) и TDI (Transport Driver Interface). Первый, NDIS, подразумевал прямое общение с сетевым адаптером и свою реализацию стека протоколов TCP/IP, а TDI — общение с драйвером Windows tcpip.sys и использование существующего стека.
Общение между драйверами происходит путем отправки I/O request packets (IRPs). Проще говоря, драйверы шлют друг другу сообщения, обрабатывают их, отвечают на них. Драйверы могут образовывать цепочки при прохождении запроса IRP. Так, например, работают снифферы. Они улавливают IRP, отправляемые сетевым адаптерам, и устанавливают над сетевым адаптером и драйвером tcpip.sys свои фильтрующие устройства, так как интерфейсы NDIS и TDI как раз и работают через отправку пакетов IRP. При этом интерфейс TDI очень похож на обычные сокеты, а фильтрующее устройство над ним дает возможность определить даже приложение пользовательского режима, отправившее эти данные или запросившее соединение.
Обойти перехват TDI-пакетов фаерволом очень просто — нужно посылать сообщения напрямую в драйвер tcpip.sys. Чтобы это сделать, пришлось покопаться в слитых исходных кодах Windows 2000. После месяца работы был готов класс, реализующий сокеты под ядром ОС. Причем это были асинхронные сокеты, то есть подключения, прием данных, отправка — любые действия в сети выполнялись в одном потоке и контролировались событиями.
Также принцип работы фильтрующих драйверов дал мне идею, как спрятать файл драйвера на диске — просто установить фильтр над драйвером файловой системы.
Для отладки драйвера мне потребовался дебагер WinDbg[31] и два компьютера, соединенных null-модемным кабелем (кабель, соединяющий COM-порты). Достать этот кабель в Кингисеппе было нереально, поэтому первый такой мне пришлось буквально паять самому.
Вторая машина нужна была для запуска тестируемого драйвера. А поскольку в режиме отладки останавливалась вся операционная система и не работал ни один прикладной драйвер, были доступны только базовые операции ввода-вывода через COM-порты. Поэтому и использовался null-модемный кабель.
За этим рабочим столом я провел год бессонных ночей. Мне всегда нравилось работать по ночам, когда прекращалась суета на улице и в доме, и я находился наедине со своим кодом, клавиатурой и монитором.
Ключи реестра спрятать фильтром не удалось, поэтому пришлось прибегнуть к излюбленной хитрости — модификации кода ядра, то есть функции работы с реестром переопределялись на свои.
Защита бота от обнаружения имела и другие фичи[32]: удаление драйвера из списка загруженных устройств, обнаружение работы под виртуальной машиной и другое.
Сервер
Сервер управления строился по той же асинхронной модели работы. Точнее, я использовал Completion Ports. Коротко говоря, обработка поступающих соединений от ботов проходила асинхронно, всего в несколько потоков (по одному-два на ядро процессора). Ведь каждый поток занимает как минимум 1 Мб памяти стека. А много потоков, тем более большую часть времени находящихся в ожидании данных из сети, поедают мощность центрального процессора просто на синхронизацию и переключение между ними.
Сложность асинхронной обработки данных состоит в том, что при каждом событии — присланы данные/отправлены данные — нужно знать, к какому конкретно соединению они относятся, к какому боту, на какой стадии находится общение. Неудивительно, что тот же Obulk Psyche (Cutwail) работал по многопоточной модели.
Через несколько месяцев была готова основа бота — драйвер, умеющий подключаться к серверу управления, передавать данные о себе (версия ОС, версия руткита) и запрашивать модули. То есть была построена кровеносная система ботнета.
Сервер обеспечивал транспорт сообщений между модулями управления на сервере и между рабочими модулями на боте.
Механизм защиты бота также работал. Дело осталось за малым — написать модули рассылки писем: управляющий для сервера и исполняющий для бота. Задания должны были передаваться в виде шаблона письма, макросов и списка почтовых адресов (мыло, IP-адрес обслуживающего почтового сервиса). Генерацией письма занималась отдельная кросс-платформенная библиотека (могла быть использована сервером, работающим в пользовательском режиме, и ботом, работающим в ядре ОС), которую модифицировал из NorthWinda мой брат.
Писал и отлаживал ботнет, по большей части, я. Более года.
И вот пришло время боевых тестов. Появилась проблема — у нас не было обратной связи. Если машины пользователей валились с синим экраном, мы не могли узнать об этом.
Проблема была решена следующим образом: устанавливался перехватчик критического исключения (при BSoD’е) в ядре ОС, он, в свою очередь, раскручивал стек вызовов и формиравал bug report, который сохранялся в одном из ключей реестра (если, конечно, реестр был еще жив). При повторном подключении бота он рапортовал, что перезагрузка произошла из-за критической ошибки, и давал отчет о падении. Имея версию бота и адреса вызовов, через WinDbg можно было найти искомое место, вызвавшее падение. Часто причиной этого были чужие боты, которые грузились параллельно.
SMTP (англ. Simple Mail Transfer Protocol — простой протокол передачи почты) — это широко используемый сетевой протокол, предназначенный для передачи электронной почты в сетях TCP/IP.
HTTP (англ. HyperText Transfer Protocol — «протокол передачи гипертекста») —