IO Ninja – программируемый эмулятор терминала/сниффер (часть 2)
Данная статья является продолжением предыдущей, вводной статьи, в которой речь шла о мотивации и истории создания терминала/сниффера IO Ninja, и было немного рассказано про встроенные возможности нашего продукта. Продолжим рассказ о том, что доступно «из коробки», но с более практическим уклоном.IO Ninja изначально задумывалась как утилита типа «всё-в-одном», и в комплект поставки входит большое количество встроеных плагинов для работы со всеразличными транспортами в разных режимах. Однако вместо сухого перечисления списка плагинов и их возможностей я решил продемонстрировать маленькую выборку задач из жизни, с которыми в нашей компании сталкивались на практике, и с которыми общеизвестные терминалы и мониторы справляются хуже, чем IO Ninja (а чаще не справляются вообще).
Пользователи Unix-подобных систем хорошо знакомы с возможностью перенаправления выхода одной программы на вход другой. Связывание сессий (Session Linking) в IO Ninja предоставляет похожий функционал. Различие заключается в том, что вместо однонаправленного каскада данных, как в случае Unix pipes, связываение двух сессий «закорачивает» выход одной на вход другой и наоборот (при этом в лог записываются все передаваемые данные). Тем самым появляется возможность использовать IO Ninja в качестве универсального посредника для перенаправления и/или прослушивания.Допустим, к компьютеру через последовательный интерфейс (serial) подключено устройство. Открываем IO Ninja и запускаем сессию Serial. Открываем и конфигурируем последовательный порт (возможно, посылаем несколько тестовых команд устройству, дабы убедиться, что оно живо-здорово).
Далее запускаем сессию TCP Listener, выбираем интерфейс и TCP порт, на котором будем слушать. Связываем наши две сессии Serial и TCP Listener через диалог настроек и — вуаля! Теперь к нашему последовательному устройству можно подсоединяться по TCP с любого другого компьютера!
Типовым методом автообнаружения устройств в сети является широковещательная UDP рассылка некоего эхо-запроса и последующий сбор ответных пакетов — так, в частности, работает автообнаружение у всех встраиваемых модулей, производимых нашей компанией. IO Ninja может быть использована в качестве широковещательного UDP терминала для общения в режиме «one-to-many».Открываем UDP Socket, прописываем в качестве адреса 255.255.255.255 (или же subnet-broadcast типа 192.168.1.255), и рассылаем эхо-запрос. В результате мы видим список всех устройств в локальном сегменте. Далее, если это необходимо, мы можем продолжать общение с каким-то конкретным устройством.
Кстати, обратите внимание на кнопочку с компасом. При работе с UDP (и в особенности на стороне сервера) часто требуется запоминать адрес, с которого пришёл пакет, и отвечать именно туда — соединения-то нет! В принципе, ничто не мешает копировать адрес из лога и вставлять его в поле ввода «Remote address». Но зачем делать руками то, что можно переложить на машину? Жмём компас, и получаем требуемую автоматизацию — UDP-сессия будет автоматически перенастраивать Remote address.
Иногда во время отладки требуется сохранить кусок принятых данных в файл. Это может быть, например, блок, который надо отправить в неизменном виде в этой или какой-то другой сессии, может быть, это переданный удалённым узлом файл, может быть ещё что-то третье.Стандартные терминалы часто буксуют на этой достаточно простой задаче, и связано это со следующими моментами:
Данные могут быть бинарными и содержать непечатаемые символы; Данные могут быть «размазаны» между несколькими пакетами; Нужен нам, как правило, не весь входной поток, а строго определённый блок (а значит, простым перенаправлением потока в файл проблема тоже решается не совсем чисто). IO Ninja выгодно отличается наличием лога в виде «шестнадцатеричной простыни» со склеиванием входящих пакетов — это позволяет выполнить именно то, что нам надо.
Выделяем нужный блок данных (поглядывая, если надо, на статус-бар — там отображается смещение и длина выделенного блока), сохраняем в файл, и потом используем. Например, пересылаем его по другой сессии:
Выше мы видели, как с помощью TCP Listener можно организовать перенаправление, чтобы можно было подсоединяться к последовательному устройству по TCP. Однако изначальным назначением плагина TCP Listener является не это, а работа в качестве server-side TCP терминала (в частности, для отладки клиентской стороны TCP соединения).Создаём новую сессию TCP Listener, выбираем интерфейс и порт, и запускаем наш сервер. После приёма входящего соединения от клиента с терминалом можно работать как обычно.
Отметим, что в TCP Listener также имеется возможность выбора: принимать или нет новые входящие соединения, если соединение уже имеется в наличии. Данная опция может быть крайне полезной в ситуациях, когда клиент устанавливает множество вторичных соединений на один и тот же адрес (как, например, многие web-браузеры)
IO Ninja включает в себя плагин Network Sniffer — основанный на PCap сетевой сниффер для прослушивания сетевых соединений. Однако, в ряде случаев значительно удобнее использовать другой встроенный плагин, а именно TCP Proxy.TCP Proxy — это комбинация TCP Connection и TCP Listener, которая позволяет организовать посредника для TCP соединений. Удобство данного подхода заключается в том, что он сразу даёт чистый лог потоков данных в реальном времени (вместо лога в виде пакетов, из которых потоки данных надо ещё потом восстановить). Помимо этого, данная модель работает и там, где прослушивание с помощью сниффера может быть затруднительно (с определёнными моделями сетевых свичей, Wi-Fi карточек и т.д.)
Создаём сессию TCP Proxy, конфигурируем серверную и клиентскую стороны и запускаем наш прокси-сервер. Любое подсоединение к данному серверу породит вторичное подсоединение с клиентской стороны нашего прокси, при этом все данные принятые на клиентской стороне, будет переданы на серверную и наоборот. В этом смысле TCP Proxy напоминает связывание сессий, но специально заточенное под TCP и вследствие этого более удобное.
IO Ninja может быть использована в качестве инструмента для отладки достаточно распространённого подхода к IPC (Inter-Process Communication) в Windows — named pipes. В частности, так общаются некоторые наши Windows-драйвера с сопутствующими сервисами и приложениями.Для эмуляции серверной стороны вашего приложения (той, где вызывается ConnectNamedPipe), запустите Named Pipe Listener. Данный плагин позволяет принимать входящие named pipe-соединения, которые будут исходить от вашего клиентского приложения/сервиса.После установления соединения вы можете общаться с клиентом, анализируя лог полученных запросов и отсылая ему ответные пакеты (созданные, например, в строителе пакетов).
Для эмуляции клиентской стороны (той, где вызывается CreateFile) используется плагин Generic File.
Помимо отладки named pipes (или FIFOs в *nix), данный плагин также может быть использован для чтения и записи в драйверы нестандартных устройств.
Кратко коснёмся вопроса прослушивания named pipes. Предположим, имеется приложение или драйвер, использующие pipes для IPC. Если вы можете каким-то образом настраивать адрес named pipe на клиентской стороне, то появляется возможность прослушивания pipe-соединений с помощью посредника (аналогично TCP Proxy).
Как именно? Пусть отлаживаемая система устанавливает pipe соединение на \\.\pipe\debuggee_pipe_server. Выбираем какое-нибудь незанятое имя pipe, например, \\.\pipe\my_pipe_proxy. Настраиваем клиентскую сторону отлаживаемой системы на этот наш \\.\pipe\my_pipe_proxy. В IO Ninja открываем пару Pipe Listener и Generic File, связываем их. В Pipe Listener прописываем \\.\pipe\my_pipe_proxy, жмём Listen. В Generic File прописываем \\.\pipe\debuggee_pipe_server, жмём Open. Посредник готов.
Со временем в будущих версиях IO Ninja будет также добавлено полноценное прослушивание named pipes без организации man-in-the-middle (в качестве первого приближения, скорее всего, через user-mode API hooking, а впоследствии — через file system filter).
Необходимость в отправке «битых» или иным образом специально сформированных Ethernet фреймов встречается не столь часто и может казаться относящейся, скорее, к разряду экзотики. Тем не менее данный функционал востребован в ряде вполне себе реальных сценариев. Например, в нашей практике это было необходимо во время отладки реализации TCP/IP стека у производимых нашей компанией встраиваемых модулей; другой реалистичной областью приложения могут быть задачи, стоящие перед специалистами по сетевой безопасности, разработчиками firewall-ов и т.д. Открываем сессию Network Sniffer, выбираем интерфейс и фильтр захвата, запускаем захват. В строителе пакетов подготавливаем необходимый фрейм — например, можно воспользоваться встроенной библиотекой шаблонов пакетов TCP/IP, или же просто скопировать какой-то из захваченных фреймов в шестнадцатеричный редактор и подправить нужные поля.
Нажимаем Send, и любовно составленный нами фрейм отправляется выполнять боевое задание!
Данный список сценариев использования IO Ninja далеко не полон, но, в принципе, достаточен для демонстрации общей картинки. Помимо этого, он абсолютно честен — все описанные выше функции родились из практических нужд, возникавших при разработке наших продуктов.В следующей части статьи мы перейдём к с самому интересному — к программируемости IO Ninja и открываемых этим новых возможностях.