Щелканье замка в коридоре прозвучало неестественно громко на фоне монотонного гудения вентиляторов. Дверь приоткрылась, впустив в прокуренную комнату сквозняк и запах подъездной сырости. Денис шагнул через порог, бросил связку ключей на тумбочку и стянул легкую ветровку. У него давно имелся собственный ключ от квартиры Алексея — суровая необходимость для тех случаев, когда нода намертво зависала посреди ночи, модем переставал отвечать на звонки, а хозяин узла спал мертвым сном после трех суток непрерывного кодинга, и требовался жесткий аппаратный сброс по питанию.
Но сейчас система работала. Тяжелый металлический корпус модема US Robotics Courier на верхней полке стеллажа тускло светился красными диодами питания и готовности терминала. Индикаторы приема и передачи данных оставались темными. Линия молчала.
Алексей сидел перед монитором, ссутулившись так, словно невидимый бетонный блок давил ему на плечи. Он не повернул головы на звук шагов. Его покрасневшие от недосыпа и многочасового вглядывания в мерцающий фосфор кинескопа глаза были прикованы к синим панелям файлового менеджера. В комнате стоял густой, почти осязаемый запах перегретого текстолита, остывшего растворимого кофе и застарелого пота — запах загнанного в угол инженера.
Денис молча прошел вглубь комнаты, остановился за спиной друга и скрестил руки на груди. Зеленоватый отсвет четырнадцатидюймового экрана выхватывал из полумрака бледное, осунувшееся лицо сисопа.
— Ты звонил, — ровно произнес Денис, оценивая обстановку. Отъехавшее в сторону кресло. Пролитая на столешницу и уже успевшая засохнуть бурая лужа от кофе. Снятая боковая крышка системного блока, обнажающая переплетение шлейфов и мерцание диодов на материнской плате.
— Он прошел, — голос Алексея звучал глухо, надтреснуто, лишенно привычных ироничных интонаций. Он не отрывал взгляда от экрана. — Прошел мимо всего. Мимо логики, мимо железа, мимо базовых законов адресации.
Денис нахмурился, пододвинул табуретку и сел рядом. Он ожидал увидеть очередную истерику по поводу обойденного бана или хитроумного батника, но состояние Алексея пугало своей ледяной, отрешенной обреченностью.
— Давай по порядку. Ты поставил блокировку в тоссере?
— Блокировка — это детский сад, — Алексей медленно покачал головой, и это движение далось ему с видимым трудом. — Я не стал полагаться на парсер. Программный бан можно обойти, если знать дыры в коде маршрутизатора. Я пошел дальше. В восемнадцать ноль-ноль я полностью изолировал систему. Выстроил карантинную зону.
Сисоп протянул дрожащую руку к клавиатуре. Тяжелые пластиковые клавиши механической доски издали сухой, резкий треск под его пальцами. Левая синяя панель сменила директорию. На экране выстроился ровный столбец файлов с расширением bat.
— Смотри. Я написал батник полного контроля состояния дисковой подсистемы. Петля, которая крутится в фоновом режиме каждые тридцать секунд. Батник делает полный слепок таблицы размещения файлов FAT-шестнадцать. Он сканирует дерево каталогов, пересчитывает контрольные суммы каждого файла в директории почтовой базы, отдельно проверяет мертвую зону QUARANTINE, объем свободного кластерного пространства и пишет лог.
Денис подался вперед, вчитываясь в названия файлов. Он понимал уровень паранойи друга. Сделать непрерывный мониторинг физического состояния диска — это значит заставить процессор постоянно молотить вхолостую, изнашивать механику винчестера и сознательно тормозить всю остальную работу системы. Это была осада. Глухая оборона.
— Более того, — продолжал Алексей, повышая голос, в котором начали пробиваться истерические нотки. — Я физически вынес эталонные копии конфигурации и чистых логов на флоппи-диск. Дискета вставлена в дисковод, окошко защиты от записи заклеено плотной наклейкой. Если происходит любое изменение на жестком диске, батник сравнивает текущее состояние с эталоном на дискете и, если есть расхождение, останавливает систему, выдавая звуковой сигнал.
Алексей ударил по клавише ввода, открывая длинный текстовый отчет. Столбцы цифр, пути к файлам, временные метки.
— Дальше. Я отрубил все внешние обработчики. Оставил только BinkleyTerm для приема звонков на модем. Тоссер, который распаковывает архивы и кладет письма в базу, я перевел в ручной режим. Он не мог запуститься сам. Ни по времени, ни по событию. Я сидел и смотрел в экран.
Денис кивнул, принимая архитектуру ловушки. План был безупречен. Любые данные, поступающие из внешнего мира, обязаны подчиняться законам физики и протоколам маршрутизации. Модем принимает аналоговый сигнал, преобразует его в цифру. BinkleyTerm ловит этот поток, формирует транзитный пакет с расширением pkt и кладет его в защищенную директорию входящего трафика. Только после этого запускается тоссер, читает конфигурацию, проверяет права доступа, распаковывает пакет и интегрирует текст в общую базу данных сообщений. И на каждом из этих этапов операционная система DOS фиксирует изменение размера файлов, дергает аппаратные прерывания контроллера жесткого диска и оставляет следы в логах.
— И что произошло? — тихо спросил Денис.
Алексей сглотнул вязкую слюну. Его пальцы снова легли на клавиатуру, выбивая дробь команд.
— После твоего звонка шаговый двигатель жесткого диска затрещал снова. Сначала в QUARANTINE лежал тот самый 00000001.MSG, который вообще не должен был появиться. А потом индикатор обращения к памяти вспыхнул непрерывным красным светом, и батник заорал уже на изменении размера основной базы сообщений. Я остановил все процессы.
Денис забрал клавиатуру из-под дрожащих рук друга. Он должен был увидеть все сам. Технарь верит только логам. Опытный сисоп верит только шестнадцатеричному коду.
Он нажал комбинацию клавиш, переходя в корневую директорию почтовика. Открыл журнал работы терминала Binkley. Нажал кнопку перехода в конец файла. Последняя запись фиксировала инициализацию модема три часа назад. Ни одного входящего звонка. Ни одного согласования протоколов связи. Никаких ошибок соединения, никаких сброшенных линий.
Денис вышел из файла и перешел в директорию входящего трафика. Абсолютная пустота. Счетчик байтов внизу панели показывал ровный ноль. Никаких транзитных пакетов, никаких недокачанных архивов, никаких временных файлов.
Затем он открыл лог маршрутизатора. Тоссер спал. Последний запуск состоялся до включения карантинного режима. Программа даже не загружалась в оперативную память.
Система была стерильна. Герметична. Физически отрезана от внешних информационных потоков.
Денис навел курсор на файл данных основной базы сообщений jam.jdt. Время последней модификации изменилось. Размер увеличился на несколько килобайт. Он нажал функциональную клавишу просмотра файла и сразу переключился в шестнадцатеричный режим. Экран залило синим цветом, расчерченным на три колонки: адреса секторов слева, шестнадцатеричные коды байтов по центру, и их текстовое отображение в кодировке ASCII справа.
Он зажал клавишу пролистывания страниц, пропуская мегабайты старой переписки и служебного мусора базы данных. Мелькали обрывки чужих диалогов, цитаты, старые заголовки фреймов. Денис остановил прокрутку в самом конце файла, там, где располагались свежие, только что измененные кластеры.
Среди ровных рядов системного кода четко и ясно читался текст нового письма. Адресат: Ольга. Отправитель: Илья.
Денис вгляделся в шестнадцатеричные значения перед текстовым блоком. Он искал глазами стандартные служебные метки — клуджи Фидонета. Каждое обработанное сообщение обязано иметь маршрутные строки PATH, уникальный идентификатор MSGID, техническую информацию от тоссера. Вся эта служебная шелуха доказывает, что письмо прошло легальный путь через узлы сети.
Но клуджей не было.
Запись выглядела пугающе аккуратно: как уже готовое сообщение JAM, с тем минимумом служебной структуры, который позволял редактору его увидеть. Но вокруг нее не было главного — следов нормального рождения письма. Ни входящего PKT, ни лога распаковки, ни ожидаемых маршрутных клуджей, ни связки с деревом ответов.
Данные не валялись мусором в хвосте файла. Они встроились в базу так, словно кто-то знал ее формат, но при этом полностью обошел обычный путь: мейлер, тоссер, логи, входящий архив, человеческие руки.
Денис отпустил клавиатуру. В комнате повисла тяжелая, густая тишина, нарушаемая лишь свистом раскручивающихся кулеров.
— Ты видишь это? — шепотом спросил Алексей, и в его голосе звучал неподдельный животный ужас человека, чья вселенная только что треснула по швам. — Маршрутных клуджей нет. Нормального входящего пакета нет. Тоссер этого не рожал. А батник поймал изменение размера напрямую на секторах.
Денис потер переносицу, пытаясь уложить увиденное в рамки рационального мышления.
— Как? — Алексей не ждал ответа, он задавал вопрос пустоте. — Как можно изменить магнитное состояние секторов на блинах винчестера в обход контроллера диска? В обход базовой системы ввода-вывода? Это невозможно программно. Вирус резидентного типа обязан перехватить двадцать первое прерывание DOS. Мой батник проверял таблицу векторов прерываний. Она чиста! Никто не сидит в памяти.
Алексей вскочил с места, нервно заходил по тесному пространству между столом и разложенным диваном. Его движения были рваными, нескоординированными.
— Это аппаратная закладка. Другого объяснения нет. Неизвестный чип на контроллере материнской платы. Закрытый военный эксперимент. Они получили прямой доступ к физической памяти. Железо больше мне не подчиняется. Мой собственный компьютер впускает чужие данные и врет мне в лицо!
Денис продолжал смотреть на синий экран шестнадцатеричного редактора. Его мозг, привыкший к структурному анализу, отбрасывал панику и методично перебирал варианты. Аппаратная закладка? Слишком сложно, слишком дорого, слишком бессмысленно для атаки на любительскую сеть. Сбой контроллера диска? Он не генерирует осмысленный русский текст с правильной адресацией. Неизвестный способ удаленного доступа через силовую сеть питания? Бред из дешевых киберпанк-романов.
Но факт оставался фактом. Ловушка Алексея сработала идеально. Она не поймала хакера в сеть, но она дала стопроцентное, математически выверенное доказательство: они воюют с тем, что не подчиняется законам программного кода.
— Успокойся, — Денис развернулся на стуле, перегораживая Алексею путь для метаний по комнате. — Сядь. Сядь, я сказал.
В его голосе зазвучал металл, жесткая властность, которая всегда проявлялась в критических ситуациях, когда бинарное мышление Алексея давало сбой перед лицом иррационального.
Алексей остановился, тяжело дыша, посмотрел на друга воспаленными глазами и медленно опустился на край дивана.
— Софт бессилен, Леха, — ровным голосом произнес Денис. — Твоя ловушка отработала как часы: она доказала, что мы воюем с тем, что не парсится и не блокируется. Противник в упор не видит ни DOS, ни файловую систему.
Алексей до хруста сжал край диванной подушки.
— Значит, надо убирать базу сообщений с основного диска. Изолировать на физическом уровне, — лихорадочно забормотал он, не отрывая взгляда от вскрытого компьютера. — Если поток проходит мимо модема и операционки, его нельзя пускать в живую ноду. Нужна отдельная железная коробка. Глухой аппаратный буфер. Пусть пишет в пустую изолированную среду, чтобы мы могли...
— Прекрати строить бункеры, — Денис подался вперед, обрывая панику друга. Лицо оставалось холодным, взгляд потяжелел. — Мы проиграли войну внутри машины. Это факт. Но у этого хакера есть одна критическая уязвимость. Точка отказа, которую невозможно залатать.
Алексей поднял голову, непонимающе глядя на Дениса.
— Какая?
— Он человек. Физический объект. Кусок мяса с костями, который живет в конкретном городе, ходит по улицам и дышит воздухом. И этот кусок мяса только что совершил фатальную ошибку.
Денис развернулся к клавиатуре, нажал клавишу выхода из шестнадцатеричного редактора и запустил почтовую программу GoldED. Знакомый интерфейс развернулся на весь экран, подсветив свежую ветку личной переписки желтым маркером непрочитанного сообщения. Письмо от Ильи, адресованное Ольге, мирно лежало в папке входящих, дожидаясь, пока пользователь его откроет.
Денис навел курсор на заголовок и нажал ввод, открывая текст.
Алексей вздрогнул, словно его ударили током. Он рванулся с дивана, преодолев расстояние до стола в один шаг, и схватил Дениса за плечо, пытаясь оттащить от клавиатуры.
— Ты что творишь?! — заорал сисоп, его голос сорвался на визг. — Это личный нетмейл! Закрой немедленно! Это базовое табу! Сисоп не читает чужую почту! За это отлучают от сети навсегда, за это бьют морду в реале! Ты нарушаешь устав Полиси!
Денис не сдвинулся с места. Он лишь напряг плечо, сбрасывая руку Алексея, и жестко посмотрел ему в глаза снизу вверх.
— Очнись, Лёха. Полиси работает для нормальных пользователей. Прайваси заканчивается там, где начинается угроза уничтожения ноды. Этот ублюдок только что пробил твою идеальную карантинную зону. Он положил болт на твои прерывания и на твой жесткий диск. Это больше не почта. Это чужая запись прямо в сердце базы. И я буду разбирать ее под микроскопом, мне плевать на девичьи секреты и сопливую романтику.
Алексей замер, тяжело дыша. Его лицо пошло красными пятнами. Конфликт между жесткой сисопской этикой, вбитой в подкорку годами администрирования, и очевидной правотой Дениса разрывал его на части. Правила Фидонета были святы. Но система была взломана неизвестным, пугающим методом. Инстинкт инженера, требующий разобраться в аномалии, боролся с моральным кодексом.
Он отступил на шаг, стиснул кулаки и отвернулся к окну, за которым чернела теплая июньская ночь.
— Читай, — глухо выдавил он. — Но если там личное... я сам выдерну шнур питания.
— Я уже проверил, — спокойно ответил Денис, не отрывая взгляда от экрана. — Сначала выгрузил свежий хвост базы и прогнал через него бинарный поиск по ключевым словам. Потом открыл запись в GoldED, чтобы убедиться, что редактор тоже видит ее как письмо. Я не читал их восторги про луну и эльфов. Я искал привязку к реальности: «парк», «встреча», даты, время. Оля давно звала его на массовый сбор. И я нашел то, что искал.
Денис ткнул пальцем в мерцающий экран. В самом конце короткого сообщения, вшитого напрямую в кластеры жесткого диска, светилась одна фраза.
«Я постараюсь там быть».
Алексей медленно повернулся. Гнев и смятение на его лице начали сменяться сложным, концентрированным выражением человека, который внезапно увидел выход из глухого лабиринта.
— Он придет на фидопойку, — произнес Денис, чеканя слоги, чтобы смысл дошел до потрясенного сознания друга. — В эту субботу. Наш неуловимый призрак, ломающий аппаратные прерывания и обходящий маршрутизацию, вылезет из своей берлоги и придет ножками в парк, чтобы встретиться с девочкой.
— Массовый сбор, — пробормотал Алексей, его мозг начал лихорадочно перестраиваться на новые вводные. — Там будет человек пятьдесят. Пиво, обмен дискетами, гитары. Шум, толпа. Идеальное место, чтобы затеряться. Но и идеальное место, чтобы засветиться.
— Именно, — Денис встал с табуретки, подошел к окну и прислонился к подоконнику, скрестив руки. Теперь он полностью владел ситуацией. Он перевел игру на свое поле. Поле реального мира, логистики и тактического планирования. — Мы не будем пытаться поймать его в коде. Мы вытащим его на свет божий.
Алексей нервно потер подбородок.
— Мы не знаем, как он выглядит. Он не описывал свою внешность. Оля тоже не знает. Он может оказаться кем угодно — студентом из Бауманки, сорокалетним инженером из закрытого НИИ, школьником-вундеркиндом.
— Нам не нужно знать, как он выглядит, — отрезал Денис. Его голос звучал холодно, методично, как план военной операции. — Оля доведет его до встречи. Она будет стоять у памятника, как они и договаривались. Он сам к ней подойдет. Это неизбежно.
Денис начал выстраивать схему руками в воздухе, словно рисуя карту парка.
— Мы организуем периметр. Никаких маски-шоу, никаких бандитских замашек с арматурой в кустах. Мы не отморозки. Мы инженеры. Мы работаем чисто. Разделим наших проверенных поинтов на группы наблюдения. Точки контроля на всех аллеях, ведущих к памятнику. Станция метро, автобусные остановки — все пути отхода под контролем.
Алексей слушал, и дрожь в его руках постепенно утихала. Паника, вызванная крушением бинарной логики, растворялась в холодной, осязаемой решимости. В реальном мире действовали законы ньютоновской физики, а не магнитные аномалии. В реальном мире хакеру можно было посмотреть в глаза, сфотографировать его лицо, проследить его маршрут.
— У Игоря есть хороший фотоаппарат, — вспомнил Алексей. В его голосе появилась прежняя деловая хватка. — «Зенит-ЕТ» с мощным телевиком, объектив «Таир». Он может снимать с пятидесяти метров, портреты будут четкими.
— Отлично, — кивнул Денис. — Сажаем Игоря на возвышенность у летнего кафе. Заряжаем высокочувствительную пленку, чтобы не зависеть от облачности. Как только неизвестный подходит к Оле и называет себя Ильей — Игорь делает серию снимков. Мы фиксируем его физиономию.
Денис оттолкнулся от подоконника и начал мерить шагами комнату.
— Дальше — наружное наблюдение. Мы не вступаем в контакт на фидопойке. Там толпа, начнется кипеж, он может сбежать. Мы просто пасем его. Когда встреча закончится, мы ведем его до метро. Сопровождаем в вагоне. Вычисляем станцию, вычисляем адрес, парадную, квартиру. Нам нужно знать, откуда он выходит в сеть. Нам нужно увидеть его оборудование. Узнать провайдера, если он сидит через интернет-шлюз. Понять, кто он такой.
Алексей мрачно усмехнулся. Густая, плотная злость админа на того, кто влез грязными ботинками в святая святых компьютера, вытеснила страх перед неизведанным. Он посмотрел на системный блок, продолжавший гудеть под столом.
— А если он попытается скинуть хвост? — спросил сисоп, прищурившись. — Если начнет юлить дворами или растворится в толпе?
Денис остановился напротив Алексея. Его лицо в зеленоватом свете монитора выглядело жестким, лишенным всяких сомнений.
— Тогда мы сокращаем дистанцию. Подходим вплотную, блокируем пути отхода. И уже без всякой сетевой магии, без клавиатур и мониторов, глядя глаза в глаза, предельно вежливо спрашиваем: как именно ломается наша сеть? И поверь мне, Лёха, в реальной подворотне ни один аппаратный эксплойт ему не поможет. Мы вытрясем из него эту технологию.
Алексей медленно кивнул, принимая новую реальность. Больше не было смысла пялиться в логи. Не было смысла писать батники и возводить стены из программного кода. Матрица дала сбой, и чинить ее придется кулаками, фотопленкой и уличным наблюдением.
Денис повернулся обратно к экрану. Строка с вшитым в кластеры текстом письма больше не казалась приговором или насмешкой над законами информатики. Теперь это была наживка, которую заглотил неосторожный зверь.
Они ждали не цифрового пакета данных. Они ждали человека, который придет на встречу, не подозревая, что капкан реальности уже захлопнулся.