Usbpcap что это за программа
Введение в перехват USB команд с помощью Wireshark
Введение
Недавно у меня на работе возникла задача повторить работу программы настройки одного навигационного устройства и поэтому я стал изучать тему, как можно перехватить данную информацию без полного реверс инжинеринга самого ПО и прошивки устройства. В итоге выяслилось что это можно сделать по средствам перехвата USB трафика, о чем я ниже напишу.
Кратко о USB
USB является хост-ориентированной шиной с топологией многоуровневой звезды. На шине может присутствовать только один хост и до 127 устройств. Каждое устройство может иметь до 32 концевых точек (endpoint) — 16 на приём и 16 на передачу. Все передачи на шине инициирует только хост — устройство может передавать данные только тогда, когда хост запросит их.
Также у USB есть многослойная система протоколов. Самый нижний слой обычно реализован в железе, поэтому он не так важен для нас.
Далее идет транспортный слой, который работает через каналы (pipe). Каналы делятся на:
На уровне программного обеспечения, минимальная неделимая единица – трансфер. По типам трансферы бывают следующие:
Для отправки сообщений устройству используются управляющие трансферы, так как они (единственные из всех) являются двунаправленными и ориентированы на обмен сообщениями, они состоят из 3-х фаз:
Таким образом для формирования трансфера хост должен знать адрес устройства, которому предназначен трансфер, а также тип, направление и номер концевой точки куда отправляется сообщение.
Пример перехвата USB трафика с Wireshark
Для перехвата USB траффика можно использовать популярный снифер Wireshark. Для Windows также необходимо установит USBPcap.
Запустить прехват можно выбрав соответствующий режим в wireshark:
Разберем подробней пример дампа:
Этот дамп содержит 2 части:
Схематично взаимодействие будет выглядеть так:
Как видно из примера взаимодействие с портом USB очень похоже на взаимодействие по сети. Хост всегда отправляет команду, а устройство подтверждает ее получение.
Наибольший интерес вызывают пакеты 9-16, так как видно что это контрольные трансферы (URB_CONTROL) а значит именно с их помощью происходит управление устройствам.
Итак первая команда (пакет 9) отправляет какую-то команду на устройство. Об этом свидетельствует префикс out, так как команды всегда идут от хоста, то перфикс задает напрваление относительно него.
Если посмотреть структуру запроса, то можно понять тип запроса, сам запрос длину тела и сами данные которые отправляются на устройство. В нашем случае не важно что означают эти параметры так как нам нужно просто воспроизвести функциональность стороннего ПО.
Следующий код запрашивает состояние устройства:
Затем отправляется еще одна команда с данными (пакет 13) и еще раз читает состояние (пакет 13), после чего можно заметить что девайс переподключился (пакет 17-18).
Реализация перехваченной функциональности
После анализа дампа понятно какие команды нужно отправить на устройство для воспроизведения работы анализируемого ПО.
Для простоты воспроизведем эти команды с помощью пакета PyUSB.
Скрипт будет выглядеть так:
Заключение
По сути анализ работы по USB дампам не сильно отличается от анализа сетевого трафика и если у вас есть минимальный опыт работы c wireshark то вы сможете без проблем разобраться с базовыми вещами не требующими глубокого понимания.
USBpcap что это за программа
USBpcap что это за программа
Это программы, позволяющие прослушать и декодировать данные, передаваемые по шине USB на интересующее устройство.
Такой инструментарий позволяет отладить программное обеспечение, работающее с USB, разобраться в деталях работы устройства, получить подробную информацию от устройстве USB и т. п.
SnoopyPro-0.22 — бесплатный и весьма толковый снифер [3]. Давно не поддерживается, документация практически отсутствует, но вполне себе работает.
[Как пользоваться Snoopy Pro]
Краткая справка HOWTO, как установить и запустить прослушивание пакетов для произвольного устройства USB.
1. Скачайте архив программы [3]. В архиве один-единственный исполняемый файл SnoopyPro.exe, который не требует установки (очень люблю такие программы!). Распакуйте его в произвольное место (папку) на диске, например в папку c:Program FilesSnoopyPro.
3. Выберите в списке интересующее вас устройство (оно должно быть подключено к компьютеру). Устройство проще найти, зная VID и PID устройства. В столбце VID/PID списка текст будет как раз содержать эти VID и PID. К примеру, Ваше устройство имеет VID 0x0B9B и PID 0x4012, тогда строка в списке, соответствующая искомому устройству, будет иметь вид «USBVid_0b9b&Pid_4012. «. Щелкните на эту строку правой кнопкой, и выберите Install and Restart.
5. Остановите сбор лога, и тогда Вы сможете его просмотреть. Для остановки сбора лога нажмите кнопку с черным квадратиком.
[Free USB Analyzer]
Программа также называется Device Monitoring Studio (т. е. у неё бывают опции для мониторинга не только USB, но и последовательных портов, сети). Опция для мониторинга сети называется USB Monitor.
В бесплатной версии возможности сильно урезаны, но вполне достаточны, чтобы проанализировать обмен пакетами. USB Monitor также имеет 3 платные версии, обладающие дополнительными возможностями.
Установка Free USB Analyzer большой сложности не вызывает благодаря наличию удобного инсталлятора. Однако требуется перезагрузка, и в системе при перезагрузке добавляются значительные изменения. Поэтому рекомендуется перед установкой сделать контрольную точку восстановления системы.
USBpcap что это за программа
Привет, друзья! Приятно видеть, что вы нас читаете и комментируете! Это значит, что пишем не зря. Сегодня я проводил весьма интересные эксперименты и хотелось бы поделиться некоторыми результатами.
Нас интересуют данные, передаваемые по шине USB. Можно ли как-то “прослушивать” этот трафик? Оказывается, можно.
Качаем программу USBPcap, устанавливаем:
Теперь запускаем файл USBPcapCMD.exe с правами администратора:
Запуск USB сниффера
Мониторить мы будем работу с флешкой, которую я заботливо вставил в порт 3 первого корневого хаба. В программе он определился под номером 2. Вводим цифру 2. Затем вводим результирующий файл (1.pcap), в него будет записываться все, что происходит на этой шине.
Немножко модифицируем содержимое текстового файла на флешке:
Запишем наглядную последовательность в файл
После этого завершаем консольное приложение сниффера нажатием клавиш Ctrl+C и открываем файл 1.pcap (появился в каталоге программы) через WireShark:
Команды обмена данными с USB устройством
Ух ты! Какое удобное представление данных! В формате нашего любимого сниффера. Попробуем разобрать некоторые команды. Увы, я не очень хорошо знаю спецификацию USB, поэтому все, что я сейчас буду описывать – это лишь мое мнение, которое может быть неполным или ошибочным. Если кто может уточнить – пишите в комменты.
Периодический опрос USB устройства
Итак, нетрудно заметить, что периодически (примерно раз в секунду) происходит опрос USB устройства:
Команда на запись USB устройства
Запись корневого каталога FAT
Мои ожидания оправдались! Путём несложных арифметических преобразований получаем:
0x000001F0 *200 = 0x0003E000
Открываем флешку в WinHEX и идём по адресу. Видим корневой каталог! Чтож, всё логично!
Корневой каталог FAT
Очищеный корневой каталог
Запись данных в файл на флешке
Умножаем блок на 200:
Содержимое файла на флешке
Ну точно! Это как раз кластер, которые занимает файл 1.txt, и с этого смещения начинается его содержимое 111222333444. Именно ASCII коды этих символов и выглядят как 0x31, 0x31, 0x31, 0x32,…. Всё сошлось!
Смотрим следующую команду на запись:
Запись в таблицу FAT
Умножаем на 200, получаем адрес 0x00000800
Поясняю, F8 – идентификатор носителя (жесткий диск). Далее идёт два байта заполнителя FFFF. А дальше – FFFF – это запись нашего файла. Это означает, что в таблице размещения файлов наш файл занимает один единственный кластер и это первая запись FAT. Посмотрите ссылку, чтобы разобраться.
Вот, в общем-то и всё. Надо сказать, я до этого не совсем понимал, как происходит запись на носители типа USB. Теперь это становится понятным. Существуют методические материалы по программированию USB устройств и драйверов, у меня же есть одна замечательная идейка, которую я хочу воплотить в жизнь. Для этого нужно написать небольшую программку, наподобие этого сниффера.
USB Analyzer
Мониторинг USB портов и
анализ активности USB-устройств
USB Analyzer — это простая в использовании программа для мониторинга данных USB-устройств для ОС Windows. Она предлагает простой, но всеобъемлющий режим отображения мониторинга и анализа активности USB-устройств.
USB Analyzer может отслеживать, записывать, отображать и анализировать входящие и исходящие данные между приложениями и любым USB-устройством, подключенным к вашему компьютеру. USB Monitor может успешно применяться при разработке приложений, драйверов USB-устройств или аппаратного обеспечения. Это ваша фундаментальная платформа для эффективного кодирования, тестирования и диагностики USB портов.
Реверс протокола USB устройства
Возникла такая задача.
Есть USB приставка типа осциллографа, и программа под winXP, от его разработчика, которая запускает измерения, устанавливает частоту дискретизации, получает и отображает данные.
Ни исходников программы, ни описания протокола, по которому она с устройством общается, нет.
Возникла необходимость разработки своего приложения род Linux для работы с осциллографом, автоматической обработки данных и передачи результата в OpenScada.
Нужно выяснить, как программа общается с устройством. Думаю использовать сниффер USB. Кто-нибудь имеет такой опыт? Какую лучше программу-сниффер использовать под XP? Как удобнее тестировать полученный таким образом результат под Linux?
USBPcap – USB Packet Capture For Windows
USBPcap is an open-source USB Packet Capture tool for Windows that can be used together with Wireshark in order to analyse USB traffic without using a Virtual Machine.
Currently, the live capture can be done on “standard input” capture basis: you write a magic command in cmd.exe and you get the Wireshark to capture raw USB traffic on Windows.
USBPcapDriver has three “hats”:
What you won’t see using USBPcap
As USBPcap captures URBs passed between functional device object (FDO) and physical device object (PDO) there are some USB communications elements that you will notice only in hardware USB sniffer.
Moreover, you won’t see complete USB enumeration. You will only see the USB control transfer send to device after the device has been assigned its address.
USBPcap – Захват USB-пакета для Windows
USBPcap – это инструмент USB Packet Capture с открытым исходным кодом для Windows, который может использоваться вместе с Wireshark для анализа трафика USB без использования виртуальной машины.
В настоящее время прямой захват можно выполнить на основе «стандартного ввода»: вы пишете магическую команду в cmd.exe, и Wireshark для захвата необработанного USB-трафика в Windows.
USBPcapDriver имеет три «шляпы»:
Корневой концентратор (USBPCAP_MAGIC_ROOTHUB)
Управление (USBPCAP_MAGIC_CONTROL)
Устройство (USBPCAP_MAGIC_DEVICE)
Поскольку USBPcap захватывает URB, передаваемые между объектом функционального устройства (FDO) и объектом физического устройства (PDO), есть некоторые элементы связи USB, которые вы заметите только в аппаратном USB-сниффере:
Состояние шины (Suspended, Power ON, Power OFF, Reset, High Speed Detection Handshake)
Идентификатор пакета (PID)
Сплит транзакции (CSPLIT, SSPLIT)
Длительность состояния шины и времени, используемого для передачи пакета по кабелю
Скорость передачи (низкая скорость, полная скорость, высокая скорость)
Более того, вы не увидите полное перечисление USB. ъ
Вы увидите, что передача управления USB-устройством будет отправлена на устройство после того, как устройству был назначен его адрес.
Существует также инструмент, чтобы проверить:
– SnoopyPro – Инструмент для удаления USB для Windows
Вы можете скачать USBPcap здесь:
Примечание: Информация для исследования, обучения или проведения аудита. Применение в корыстных целях карается законодательством РФ.
Wireshark для всех. Лайфхаки на каждый день
Пакет с сертификатами от Хабра
Практические варианты использования
В Wireshark миллион функций, но буквально каждый человек с минимальными знаниями может использовать его с пользой. Ниже примеры основных сетевых задач.
Расшифровка трафика SSL/TLS
Chrome и Firefox могут записывать логи сессионных ключей, которые используются для шифрования трафика SSL/TLS. Наша задача — включить запись этих логов, а потом загрузить их в Wireshark для анализа. Предполагается, что у нас есть физический доступ к компьютеру пользователя, трафик которого мы хотим расшифровать. Или к серверу, который устанавливает зашифрованное соединение с пользователем.
Сначала включаем запись ключей.
Старые билды Windows 10
В старых билдах Windows 10 работает старый метод. Заходим в Панель управления → Система и безопасность → Система. На вкладке «Дополнительные параметры системы» нажимаем кнопку «Переменные среды».
Добавляем для пользователя новую переменную SSLKEYLOGFILE и указываем путь до файла.
В результате получаем логи с ключами, начало файла:
Новые билды Windows 10
В более новых версиях после установки Windows 10 старый способ добавления переменных окружения может больше не работать. Тогда есть альтернативный вариант с помощью команды в оболочке PowerShell.
[Environment]::SetEnvironmentVariable(«PATH», «C:\TestPath», «User»)
Первый параметр — это имя переменной, второй — значение, третий — для какого уровня переменная (пользовательский или системный).
[Environment]::SetEnvironmentVariable(«SSLKEYLOGFILE», «D:\wireshark», «User»)
Linux и Mac OS X
Под Linux и Mac OS X можно использовать такую команду для изменения переменной окружения и ведения логов — с запуском браузера из того же терминального окна, поскольку переменные окружения всегда работают в пределах одной сессии.
После накопления лога запускаем Wireshark.
Заходим в «Параметры», там на вкладке «Протоколы» (Protocols) находим раздел TLS (раньше он назывался SSL) — и указываем путь к файлу с логами и ключом, который использовался в сессии симметричного шифрования: (Pre)-Master-Secret log filename.
Например, при заходе пользователя на сервер Gmail в окне инспектирования пакетов QUIC мы видим обычные пакеты QUIC, зашифрованные ключом TLS.
Но в нижней части экрана появляется новая вкладка Decrypted QUIC, которая показывает расшифрованное содержимое этих пакетов.
Такой метод расшифровки трафика клиента не требует установки Wireshark на его компьютер, достаточно только скачать дамп с ключами, а потом использовать его вместе с дампом трафика.
Примечание. Этот способ не ограничен только HTTP. Точно так же можно перехватывать и расшифровывать трафик SSL/TLS в других потоках. Например, зашифрованный трафик от сервера MySQL.
Анализируем трафик с другого компьютера
Если нужно разобраться с сервером в продакшне, то удобно скопировать оттуда файлы pcap — и проанализировать трафик на личном компьютере.
Записываем пакеты на сервере с помощью сниффера пакетов tcpdump, который входит в стандартный комплект *nix:
Затем копируем файлы к себе на компьютер:
Здесь уже запускаем Wireshark и открываем полученный файл.
Есть вариант отслеживать серверный трафик в реальном времени со своего домашнего/рабочего компьютера. Например, весь трафик, кроме портов 22 и 53:
Примерно то же самое с компьютера под Windows:
Ищем проблемы
Чтобы выделить конкретное TCP-соединение, находим любой интересующий пакет, щёлкаем по нему правой кнопкой мыши — и применяем фильтр диалога.
Теперь из всего записанного трафика остались только пакеты, принадлежащие конкретно этому соединению.
На скриншоте мы видим пакеты с начала установки соединения TLS: пакет с приветствием клиента, ответный пакет с приветствием сервера, предъявленный сертификат, список шифров и так далее. Содержимое каждого пакета можно изучить отдельно. Очень удобно.
Типичный паттерн — использовать Wireshark для диагностики конкретных проблем. Например, в случае разрыва TLS-соединения мы можем зайти и посмотреть, кто его разорвал (клиент или сервер), на каком этапе это произошло и по какой причине.
Содержимое пакетов
Побайтовое содержимое каждого пакета — это настоящая магия. Конкретно эта функциональность Wireshark позволяет выявить самые серьёзные баги. Например, несколько лет назад выяснилось, что гигабитные Ethernet-контроллеры Intel 82574L отключаются, если отправить на них специально сконструированный пакет с определённой последовательностью байтов — так называемый «пакет смерти». Именно благодаря Wireshark выяснилось, какие конкретно байты в пакете приводят к гарантированному отключению сетевой карты.
Вот запись конкретных пакетов: pod-http-post.pcap и pod-icmp-ping.pcap. Можем их скачать, открыть в Wireshark и посмотреть своими глазами.
Отключение сетевого интерфейса Intel происходит, если по адресу 0x47f находится значение 2 или 3, то есть 32 HEX или 33 HEX. Если там 4, то всё нормально.
Для атаки подходил любой пакет: HTTP POST, ICMP echo-request и проч. Например, на веб-сервере можно сконфигурировать ответ 200 таким образом, что «убивает» сетевые интерфейсы на клиентских машинах. Довольно любопытная ситуация.
Поиск пакетов по содержанию
Выше мы применили фильтр диалога, чтобы выдать все пакеты для конкретного TCP-соединения. Однако фильтры можно писать и вручную. Вот некоторые примеры запросов:
Трафик с мобильного телефона
Аналогичным образом можно проанализировать трафик с фитнес-часов по Bluetooth или трафик любого мобильного приложения под Android. Для этого нужно записать пакеты PCAP на мобильном устройстве — и передать их для анализа в Wireshark на рабочем ПК.
Есть несколько мобильных программ для записи PCAP. Например, приложение
PCAPdroid для Android:
PCAPdroid
В принципе, можно не передавать записанные файлы PCAP, а анализировать их прямо на мобильном устройстве. В некоторых мобильных снифферах есть и зачаточные функции анализатора пакетов, см. Packet Capture и Termux (о нём ниже).
Packet Capture
Wireshark имеет и прямой интерфейс Androiddump, чтобы снимать данные с телефона напрямую через Android SDK.
Трафик с телевизора и других бытовых приборов
Чтобы изучить трафик с телевизора, смартфона жены или других бытовых приборов, которые подключены в домашнюю сеть по Ethernet и WiFi, придётся записывать PCAP на маршрутизаторе. Иногда достаточно встроенных инструментов. Если у вас маршрутизатор с прошивкой DD-WRT, то можно прямо на устройстве запустить tcpdump :
Для прошивки OpenWrt есть вариант зеркалировать трафик с помощью iptables-mod-tee.
Можно зеркалировать и записывать трафик с помощью дополнительного физического хаба или врезки в сеть. Подробнее см. в документации.
Другой способ — перехватить беспроводной трафик WiFi с помощью утилиты Airodump-ng без подключения к маршрутизатору. Но это больше подходит для анализа трафика на чужих хотспотах.
Далее всё по накатанной — загружаем файлы в Wireshark, запускаем фильтры.
Кстати, Wireshark поддерживает также анализ трафика USB: встроенный сниффер USBPcap и импорт пакетов из сторонних снифферов, таких как Npcap и RawCap.
Termshark
Если вы анализируете объёмные логи на удалённом сервере, но не хотите копировать всё на свою машину, может пригодиться Termshark — удобный пользовательский интерфейс в консоли для анализатора TShark, по внешнему виду напоминающий Wireshark.
Функции
Вот как выглядит версия под Android:
Wireshark как веб-приложение
Если по каким-то причинам вы не можете запустить Wireshark на локальной машине, можно воспользоваться облачным сервисом CloudShark, который сделан на удивление качественно.
Основная функция — совместная работа и публикация разборов пакетов по URL. Например, cloudshark.org/captures/05aae7c1b941. Файлы загружаются в облако и анализируются в браузере. Это нужно, если вы хотите спросить совета на форуме, поделиться информацией с коллегами или опубликовать разбор пакетов для широкой аудитории. Кстати, удобно использовать с мобильного телефона, ведь под Android есть приложения для захвата пакетов, а вот хорошего анализатора нет.
Сервис платный, есть 30-дневный пробный период.
В общем, Wireshark — просто фантастическая программа на все случаи жизни.
Кроме реальной практической пользы, анализатор даёт примерное представление о том, как работает фильтрация DPI у российских провайдеров. Там всё устроено примерно так же. Система в реальном времени сканирует трафик, фильтрует конкретно пакеты от Twitter — и замедляет их доставку пользователям на территории России. В частности, этим непотребством занимается Роскомнадзор с 10 марта 2021 года.
На правах рекламы
Если для работы необходим сервер в аренду на Linux или Windows, то вам однозначно к нам — активация услуги через минуту после оплаты!
Реверс-инжениринг драйверов USB-устройств на примере машинки на радиоуправлении
Один из аргументов любителей Windows перед любителями Linux – недостаток драйверов для оборудования под эту ОС. С течением времени ситуация выправляется. Сейчас она уже гораздо лучше, чем 10 лет назад. Но иногда можно встретить какое-то устройство, которое не распознаётся вашим любимым дистрибутивом. Обычно это будет какая-нибудь USB-периферия.
Красота свободного софта в том, что эту проблему можно решить самостоятельно (если вы программист). Конечно, всё зависит от сложности оборудования. С трёхмерной веб-камерой у вас может и не получится – зато многие USB-устройства довольно просты, и вам не придётся нырять в глубины ядра или закапываться в С. В этом уроке мы с вами при помощи Python по шагам изготовим драйвер к игрушечной радиоуправляемой машинке.
Процесс по сути будет реверс-инженирингом. Сначала мы подробно изучим устройство, затем сохраним данные, которыми оно обменивается с драйвером в Windows, и попытаемся понять, что они означают. Для нетривиальных протоколов вам может потребоваться как опыт, так и удача.
Знакомство с USB
USB – шина с управлением хостом. Хост (PC) решает, какое устройство отправляет данные по проводам, и когда именно. Даже в случае асинхронного события (нажатие кнопки на клаве) оно не отправляется хосту сейчас же. Поскольку на каждой шине может быть до 127 устройств (и ещё больше, если через хабы), такая схема работы облегчает управление.
Также у USB есть многослойная система протоколов – примерно как у интернета. Самый нижний уровень обычно реализован в кремнии. Транспортный слой работает через туннели (pipe). Потоковые туннели передают разные данные, туннели сообщений – сообщения для управления устройствами. Каждое устройство поддерживает минимум один туннель сообщений. На высшем уровне приложения (или класса) есть протоколы вроде USB Mass Storage (флэшки) или Human Interface Devices (HID), устройства для взаимодействия человека с компьютером.
В проводах
USB-устройство можно рассматривать как набор конечных точек, или буферов ввода/вывода. У каждого есть направление данных (ввод или вывод) и тип передачи. По типам буферы бывают следующие: прерывания, изохронные, управляющие и пакетные.
Прерывания передают данные по чуть-чуть в реальном времени. Если пользователь нажал клавишу, устройство ждёт, пока хост не спросит «не нажимали ли там кнопочки?». Хост не должен тормозить, и эти события не должны потеряться. Изохронные работают примерно так же, но не настолько жёстко – они разрешают передавать больше данных, при этом допуская их потерю, когда это не критично (например, веб-камеры).
Пакетные предназначены для больших объёмов. Чтобы они не забивали канал, им отдаётся всё место, которое сейчас не занято другими данными. Управляющие используются для управления устройствами, и только у них есть жёстко заданный формат запросов и ответов. Набор буферов со связанными с ним метаданными называется интерфейсом.
У любого USB-устройства есть буфер номер ноль – это конечная точка туннеля по умолчанию, который используется для управляющих данных. Но как хост узнаёт, сколько у устройства есть ещё буферов и какого они типа? Для этого используются разные дескрипторы, отправляемые по особым запросам по туннелю по умолчанию. Они могут быть стандартными для всех, особыми для конкретных классов устройств, или проприетарными.
Дескрипторы составляют иерархию, которую можно посмотреть утилитами типа lsusb. Наверху сидит дескриптор устройства, где содержится Vendor ID (VID) и Product ID (PID). Эта пара уникальная для каждого устройства, по ней система находит нужный драйвер. У устройства может быть несколько конфигураций, каждое со своим интерфейсом (например, принтер, сканер и факс в МФУ). Но обычно определяется одна конфигурация с одним интерфейсом. Они описываются соответствующими дескрипторами. У каждой конечной точки есть дескриптор, содержащий её адрес (число), направление (ввод или вывод) и тип передачи.
У спецификаций классов есть свои типы дескрипторов. Спецификация USB HID ожидает передачу данных в виде «отчётов», которые отправляются и принимаются по буферу управления или прерываний. Эти дескрипторы определяют формат отчёта (к примеру, «1 поле длиной 8 бит») и то, как его надо использовать («офсет в направлении Х»). Поэтому HID-устройство описывает само себя и его может поддерживать универсальный драйвер (usbhid в Linux). Иначе пришлось бы писать свой драйвер для каждой мыши.
Не буду пытаться описывать в нескольких абзацах сотни страниц спецификаций. Интересующихся отправляю к книге O’Reilly «USB in a Nutshell», бесплатно лежащей по адресу www.beyondlogic.org/usbnutshell. Займёмся-ка лучше делом.
Разбираемся с разрешениями
По умолчанию с USB-устройствами можно работать только из-под рута. Чтобы не запускать таким образом тестовую программу, добавим правило udev:
Вставьте имя группы, к которой принадлежит ваш пользователь, и добавьте это в /lib/udev/rules.d/99-usbcar.rules.
Под капотом
Посмотрим, как выглядит машинка по USB. lsusb – инструмент для подсчёта устройств и декодирования их дескрипторов. Входит в комплект usbutils.
Стандартная иерархия. Как и у большинства устройств, у неё только одна конфигурация и интерфейс. Можно заметить одну конечную точку interrupt-in (кроме точки по умолчанию 0, которая есть всегда, и поэтому не выводится в списке). Поле bInterfaceClass сообщает о том, что это устройство HID. Это хорошо – протокол общения с HID открыт. Казалось бы, прочтём дескриптор отчётов, чтобы понять их формат и использование, и дело в шляпе. Однако у него стоит пометочка ** UNAVAILABLE **. ЧЗН? Поскольку машинка – устройство HID, драйвер usbhid присвоил её себе, но не знает, что с ней делать. Надо отвязать его от управления ею.
Для начала надо найти адрес шины. Переподключим её, запустим dmesg | grep usb, и посмотрим в последнюю строчку, начинающуюся с usb X-Y.Z:. X, Y и Z – целые числа, уникальным образом определяющие порты на хосте. Затем запустим
1.0 – это конфигурация и интерфейс, которые должен отпустить драйвер usbhid. Чтобы подвязать всё обратно, запишите то же самое в /sys/bus/usb/drivers/usbhid/bind.
Теперь поле Report descriptor выдаёт информацию:
Задано два отчёта. Один читает с устройства (ввод), второй пишет (вывод). Оба размером в байт. Однако их использование не очевидно. Для сравнения, вот как выглядит дескриптор отчёта для мышки (не весь, но главные строчки):
Тут всё ясно. С машинкой – непонятно, и нам надо догадаться об использовании битов самостоятельно.
Небольшой бонус
Большинство радиоуправляемых игрушек просты и используют стандартные приёмники, работающие на одинаковых частотах. Значит, нашу программу можно будет использовать для управления другими игрушками, кроме этой машинки.
Работа для детектива
При анализе сетевого трафика используют снифер. И в нашем случае такая штука пригодится. Бывают специальные USB-мониторы для коммерческого использования, но для нашей задачи подойдёт и Wireshark.
Настроим перехват USB в Wireshark. Сначала разрешим мониторинг USB в ядре. Загрузим модуль usbmon:
Подмонтируем особую файловую систему debugfs:
Появится директория /sys/kernel/debug/usb/usbmon, которую можно использовать для записи трафика простыми средствами оболочки:
Там лежат файлы с загадочными именами. Целое число – номер шины (первая часть адреса шины USB); 0 означает все шины на хосте. s – statistics, t – transfers, u — URBs (USB Request Blocks логические сущности, представляющие происходящие транзакции). Чтобы сохранить все передачи на шине 2, введите:
Для нетренированного глаза тут ничего непонятно. Хорошо, что Wireshark будет декодировать данные.
Теперь нам нужна Windows, которая будет работать с оригинальным драйвером. Лучше всего установить всё в VirtualBox (с Oracle Extension Pack, поскольку нам необходима поддержка USB). Убедитесь, что VirtualBox может использовать устройство, и запустите KeUsbCar, которая управляет машинкой в Windows. Запустите Wireshark, чтобы посмотреть, какие команды драйвер отправляет на устройство. На первом экране выберите интерфейс usbmonX, где X – это шина, к которой подключена машинка. Если Wireshark запускается не из-под рута, убедитесь, что узлы /dev/usbmon* имеют соответствующие разрешения.
Нажмём в KeUsbCar кнопочку Forward. Wireshark перехватит несколько исходящих управляющих пакетов. На скриншоте отмечен тот, который нужен нам. Судя по параметрам, это запрос SET_REPORT (bmRequestType = 0x21, bRequest = 0x09), который обычно используется, чтобы изменить статус устройства – такого, как лампочки на клавиатуре. Согласно тому Report Descriptor, что мы видели, длина данных составляет 1 байт, и сам отчёт содержит 0x01 (также подсвечено).
Нажатие кнопки Right выливается в похожий запрос. Но отчёт уже содержит 0х02. Можно догадаться, что это означает направление движение. Таким же образом выясняем, что 0х04 – это правый реверс, 0х08 – задний ход, и т.д. Правило простое: код направления – это двоичная единичка, сдвинутая влево на позицию кнопки в интерфейсе KeUsbCar, если считать их по часовой стрелке.
Также можно отметить периодические запросы прерываний от Endpoint 1 (0x81, 0x80 означает, что это точка ввода; 0x01 это её адрес). Что это? Кроме кнопок, у KeUsbCar есть индикатор заряда, так что это, возможно, данные по батарее. Их значение не меняется (0х05), если машина не выезжает из гаража. В противном случае запросов прерываний не происходит, но они возобновляются, если мы ставим её обратно. Тогда, видимо, 0х05 означает «идёт зарядка» (игрушка простая, поэтому уровень зарядки не передаётся). Когда батарея зарядится, прерывание начнёт возвращать 0x85 (0x05 с установленным 7 битом). Видимо, 7 бит означает «заряжено». Что делают биты 0 и 2, которые составляют 0х05, пока неясно.
Пишем почти настоящий драйвер
Заставить программу работать с устройством, которое ранее не поддерживалось – это хорошо, но иногда нужно сделать так, чтобы с ним работала и остальная система. Это значит, надо делать драйвер, а это требует программирования на уровне ядра (http://www.linuxvoice.com/be-a-kernel-hacker/), и вам это вряд ли сейчас нужно. Но возможно, нам удастся обойтись и без этого, если речь идёт про USB.
Если у вас есть USB-сетевуха, можно использовать TUN/TAP для подключения программы PyUSB в сетевой стек Linux. Интерфейсы TUN/TAP работают как обычные сетевые, с именами типа tun0 или tap1, но через них все пакеты становятся доступны в узле /dev/net/tun. Модуль pytun делает работу с TUN/TAP простой. Быстродействие страдает, но можно переписать программу на С с использованием libusb.
Ещё один кандидат – USB-дисплей. В Linux есть модуль vfb, который позволяет обращаться к фреймбуферу как к /dev/fbX. Можно использовать ioctls, чтобы перенаправить консоль на него, и закачивать содержимое /dev/fbX на USB-устройство. Это тоже не быстро, но ведь вы не собираетесь играть в 3D-шутеры через USB.
Пишем код
Сделаем такую же программу, как для Windows. 6 стрелочек и уровень зарядки, который мигает, когда машинка заряжается. Код лежит на GitHub github.com/vsinitsyn/usbcar.py
Как нам работать в USB под Linux? Это возможно делать из пространства пользователя при помощи библиотеки libusb. Она написана на С и требует хороших знаний USB. Простая альтернатива – PyUSB. Для интерфейса пользователя я использовал PyGame.
Исходники PyUSB скачайте с github.com/walac/pyusb, и установите через setup.py. Ещё вам понадобится установить библиотеку libusb. Поместим функциональность для управления машиной в класс с оригинальным названием USBCar.
Импортируем два главных модуля PyUSB и вставляем значения для управления машинкой, которые мы вычислили при просмотре трафика. VID и PID – это id машинки, взятые из вывода lsusb.
Функция usb.core.find() ищет устройство по его ID. Подробности см. github.com/walac/pyusb/blob/master/docs/tutorial.rst
Мы отвязываем драйвер ядра, как мы делали в случае с lsusb. 0 – номер интерфейса. По выходу из программы его надо привязать обратно через release(), если он был активен. Поэтому мы запоминаем начальное состояние в self._had_driver.
Запускаем конфигурацию. Этот код эквивалентен следующему коду, который PyUSB скрывает от программиста:
Этот метод надо вызвать перед завершением программы. Мы отпускаем использовавшийся интерфейс и присоединяем драйвер ядра обратно.
direction – одно из значений, определённых в начале класса. ctrl_transfer() передаёт управляющие команды. Данные передаются как строка или как список. Возвращает метод количество записанных байт. Поскольку у нас всего один байт, мы возвращем True в этом случае, и False в ином.
Метод для статуса батареи:
Метод read() принимает адрес конечной точки и количество байт для чтения. Тип передачи определяется конечной точкой и хранится в дескрипторе. Также мы задаём нестандартное время таймаута, чтобы программа работала быстрее. Device.read() возвращает массив, который мы конвертируем в список. Мы проверяем его первый байт, чтобы определить статус зарядки. Если машинка не в гараже, то вызов read() не выполнится, и выбросит ошибку usb.core.USBError. Мы предполагаем, что эта ошибка происходит именно из-за этого. В остальных случаях мы возвращаем статус ‘unknown’.
Класс UI инкапсулирует интерфейс пользователя. Пройдёмся по основным вещам. Главный цикл находится в UI.main_loop(). Мы задаём фон с картинкой, показываем уровень заряда, если машинка в гараже, и рисуем кнопки управления. Затем ждём события – если это клик, то двигаем машинку в заданном направлении через USBCar.move().
Вся программа, включая GUI, занимает чуть больше 200 строк. Неплохо для устройства без документации.
Конечно, мы специально взяли довольно простое устройство. Но в мире есть довольно много схожих с нашим устройств, и многие используют протоколы, не сильно отличающиеся от того, что мы расковыряли. Реверс-инжениринг сложного устройства – задача непростая, но уже сейчас вы можете добавить в Linux поддержку какой-нибудь безделушки вроде устройства, сообщающего о полученном e-mail. Если это и не сильно полезно – то, по крайней мере, это интересно.