Android-смартфон при подключении к компьютеру через USB может выглядеть как медиаустройство, модем или хранилище файлов. В этой статье мы научимся делать из него USB-клавиатуру, мышь и флешку.
ВАЖНО!!! Все описанные в статье действия потребуют «взлома» смартфона и получения на нём прав суперпользователя (root). В процессе «взлома» вы можете потерять на устройстве все данные или вовсе необратимо сломать его. Будьте осторожны! Обдумывайте свои действия, не делайте того, о чём можете пожалеть!
Быстрый старт
Сначала практика, потом теория? Нет проблем. Если вы не понаслышке знакомы с мобильными технологиями и хорошо разбираетесь с архитектурой Android, то эта глава специально для вас. Если же вы новичок, то лучше сначала прочитать главу «Подготовка смартфона», а потом вернуться сюда.
▍ Предполётная проверка
Для того чтобы приступить к экспериментам необходимо:
- Android-смартфон с разблокированной учётной записью root.
- Установленный на смартфон эмулятор терминала termux.
- Настроенный в termux OpenSSH сервер.
- Смартфон должен находиться в Wi-Fi сети, доступной с компьютера.
Проверка считается пройденной, если вы можете подключиться к смартфону по SSH и успешно выполнить на нём команду «su». Если с этим есть проблемы, то переходите в раздел «Подготовка смартфона», там разберёмся, как что настроить.
▍ Переконфигурирование USB-порта смартфона в режим клавиатура, мышь и флешка
В termux выполните скрипт, который настроит USB-порт смартфона под наши задачи.
Примечание. Все скрипты и команды в этой статье (если не сказано другого) нужно запускать из-под учётной записи root.
#!/system/bin/sh
# add_profile.sh
PROFILE_NAME="xxx"
PROFILE_BASEPATH="/config/usb_gadget/"
PROFILE_PATH="${PROFILE_BASEPATH}${PROFILE_NAME}"
PROFILE_CONFIG_NAME="b.1"
STORAGE_FILE_NAME="/data/data/com.termux/files/home/storage_file.img"
STORAGE_FILE_SIZE="100M"
# More info about USB Report Descriptors:
# - Human Interface Devices (HID) Specifications and Tools: https://www.usb.org/hid
# - USB HID Report Descriptor: https://github.com/tmk/tmk_keyboard/wiki/USB:-HID-Report-Descriptor
# - Device Class Definition for Human Interface Devices (HID). B.1.
# - - https://usb.org/sites/default/files/hid1_11.pdf
KEYBOARD_REPORT_DESC="\
\\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\
\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\
\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\
\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\
\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\
\\x81\\x00\\xc0"
# Version for online parser https://eleccelerator.com/usbdescreqparser/
# 0x05 0x01 0x09 0x06 0xa1 0x01 0x05 0x07 0x19 0xe0 0x29 0xe7\
# 0x15 0x00 0x25 0x01 0x75 0x01 0x95 0x08 0x81 0x02 0x95 0x01\
# 0x75 0x08 0x81 0x03 0x95 0x05 0x75 0x01 0x05 0x08 0x19 0x01\
# 0x29 0x05 0x91 0x02 0x95 0x01 0x75 0x03 0x91 0x03 0x95 0x06\
# 0x75 0x08 0x15 0x00 0x25 0x65 0x05 0x07 0x19 0x00 0x29 0x65\
# 0x81 0x00 0xc0
MOUSE_REPORT_DESC="\
\\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\
\\x19\\x01\\x29\\x05\\x15\\x00\\x25\\x01\\x95\\x05\\x75\\x01\
\\x81\\x02\\x95\\x01\\x75\\x03\\x81\\x01\\x05\\x01\\x09\\x30\
\\x09\\x31\\x09\\x38\\x15\\x81\\x25\\x7F\\x75\\x08\\x95\\x03\
\\x81\\x06\\xc0\\xc0"
# Version for online parser https://eleccelerator.com/usbdescreqparser/
# 0x05 0x01 0x09 0x02 0xa1 0x01 0x09 0x01 0xa1 0x00 0x05 0x09\
# 0x19 0x01 0x29 0x05 0x15 0x00 0x25 0x01 0x95 0x05 0x75 0x01\
# 0x81 0x02 0x95 0x01 0x75 0x03 0x81 0x01 0x05 0x01 0x09 0x30\
# 0x09 0x31 0x09 0x38 0x15 0x81 0x25 0x7F 0x75 0x08 0x95 0x03\
# 0x81 0x06 0xc0 0xc0
# Device parameters
VID="0xDEAD"
PID="0xBEAF"
MANUFACTURER="DEAD"
PRODUCT="BEAF"
SERIAL_NUMBER="AQAK-10"
PROFILE_CONFIGURATION_STR="Multi-Device"
echo "Creating new USB profile..."
# Fileds info: https://www.kernel.org/doc/Documentation/ABI/testing
mkdir -p $PROFILE_PATH
cd $PROFILE_PATH
if [ $? -eq 0 ]; then
# Base Class 00h (Device): https://www.usb.org/defined-class-codes
echo 0x00 > bDeviceClass # 00 - Class Defined by Interface ( composite )
echo 0x00 > bDeviceProtocol # Base Class 00h (Device): https://www.usb.org/defined-class-codes
echo 0x00 > bDeviceSubClass #
echo 0x40 > bMaxPacketSize0 # = 64 bytes. Auto assigned by Android, can't change
echo 0x0200 > bcdUSB # = USB 2.0. Auto assigned by Android, can't change
echo 0x0333 > bcdDevice # Device release number. Can be any
echo $VID > idVendor
echo $PID > idProduct
else
echo "USB profile create fail."
exit 1
fi
mkdir -p "$PROFILE_PATH/strings/0x409"
cd "$PROFILE_PATH/strings/0x409/"
if [ $? -eq 0 ]; then
echo $MANUFACTURER > manufacturer
echo $PRODUCT > product
echo $SERIAL_NUMBER > serialnumber
else
echo "strings create fail"
exit 1
fi
# create keyboard function
mkdir -p "$PROFILE_PATH/functions/hid.keyboard"
cd "$PROFILE_PATH/functions/hid.keyboard"
if [ $? -eq 0 ]; then
echo 1 > protocol # Keyboard
echo 1 > subclass # Boot Interface Subclass
echo 8 > report_length
echo -ne $KEYBOARD_REPORT_DESC > report_desc
else
echo "keyboard function create fail"
exit 1
fi
# create mouse function
mkdir -p "$PROFILE_PATH/functions/hid.mouse"
cd "$PROFILE_PATH/functions/hid.mouse"
if [ $? -eq 0 ]; then
echo 2 > protocol # Mouse
echo 1 > subclass # Boot Interface Subclass
echo 4 > report_length
echo -ne $MOUSE_REPORT_DESC > report_desc
else
echo "mouse function create fail"
exit 1
fi
# create mass_storage image file
if [ ! -f "$STORAGE_FILE_NAME" ]; then
fallocate -l $STORAGE_FILE_SIZE $STORAGE_FILE_NAME
fi
# create mass_storage function
mkdir -p "$PROFILE_PATH/functions/mass_storage.0"
cd "$PROFILE_PATH/functions/mass_storage.0/lun.0"
if [ $? -eq 0 ]; then
echo 1 >../stall
echo 0 > cdrom
echo 0 > removable
echo 0 > ro
echo 0 > nofua
echo "$STORAGE_FILE_NAME" > file
else
echo "mass_storage function create fail"
exit 1
fi
# DISABLE ALL USB Profiles!
find $PROFILE_BASEPATH -name UDC -type f -exec sh -c 'echo "" > "$@"' _ {} \;
# enable functions
# Device can have many configurations, like c.1, a.1, etc., but host chose from it
# Usually, device have only one config
mkdir -p "${PROFILE_PATH}/configs/${PROFILE_CONFIG_NAME}/strings/0x409"
cd "$PROFILE_PATH/configs/${PROFILE_CONFIG_NAME}/"
if [ $? -eq 0 ]; then
echo $PROFILE_CONFIGURATION_STR > strings/0x409/configuration
find $PROFILE_PATH/functions/* -type d -maxdepth 0 -exec sh -c 'ln -s $@ ./' _ {} \;
else
echo "functions enable fail"
exit 1
fi
cd $PROFILE_PATH
ls /sys/class/udc > UDC
exit 0
▍ Проверка активации функций клавиатуры и мыши
Чтобы убедиться, что всё прошло как надо в termux выполните команду:
ls /dev | grep hidg
Если в результате выполнения этой команды вы видите строки «hidg0» и «hidg1» значит функции клавиатуры и мыши активировались успешно.
▍ Имитация нажатия кнопки «а»
Порт переконфигурирован. Всё готово к первому шагу. Попробуем «нажать» кнопку «а».
Примечание. Не забудьте подключить смартфон к USB-порту и найти на экране компьютера строку, где должна появиться нажатая буква.
#!/system/bin/sh
# print_a.sh
echo "\x00\x00\x04\x00\x00\x00\x00\x00" > /dev/hidg0 #press a
echo "\x00\x00\x00\x00\x00\x00\x00\x00" > /dev/hidg0 #release a
▍ Имитация движения мыши
Теперь пошевелим курсором мыши. Следующий скрипт переместит курсор мыши на некоторое расстояние вниз. Чтобы лучше это увидеть, предварительно поставьте курсор в центр экрана.
#!/system/bin/sh
# mouse_move_down.sh
echo "\x00\x00\x55\x00" > /dev/hidg1
▍ Проверка работы флешки
Это, пожалуй, самый простой тест. Если вы используете Windows, то откройте «Disk Management» («Управление дисками»), там появится новый диск на 100Mb (Рис. 1). Для использования его нужно просто отформатировать. Если у вас другая операционная система, то нужно выполнить аналогичные действия, но уже с вашей спецификой.
Рис. 1
Интересно? Хочется подробностей? Добро пожаловать в статью.
Подготовка смартфона
Всем, кто успешно прошёл «Быстрый старт», можно смело пропускать данную главу.
▍ Получение root
Напоминаю, что этот процесс довольно опасен. Не делайте его на вашем основном смартфоне. Используйте отдельный смартфон для тестов, который не жалко угробить. Например, подопытным кроликом для данной статьи послужил ASUS ZenFone Max Pro M1 (Android 8.1) c разбитым экраном, который до этого без дела валялся на полке.
Процесс получения root в смартфоне, как правило, состоит из следующих этапов:
- Активация в смартфоне отладки через USB.
- Разблокировка загрузчика.
- Замена стандартной прошивки восстановления на специально подготовленную (custom recovery), например, TWRP.
- Установка из TWRP специальной утилиты Magisk.
- Инсталляция из стандартной оболочки смартфона менеджера Magisk.
Первые этапы специфичны для каждого смартфона. Найти необходимые инструкции и прошивки вы скорее всего сможете на сайтах 4PDA или XDA Forums. Если их там нет, то Яндекс в помощь.
Хочу заострить ваше внимание на одной важной особенности получения root, о которой почему-то нигде не пишут. При перепрошивке смартфона подключать его следует только к USB 2.0 портам компьютера. Если их нет, то потребуется USB 2.0 хаб. Использование USB 3.0 портов (или более новых) может сопровождаться ворохом проблем:
- Смартфон может самопроизвольно выходить из режима быстрой загрузки.
- Утилита fastboot будет срабатывать «через раз» и выдавать ошибки: FAILED (command write failed (No error)), FAILED (status read failed (Too many links)) и прочие.
▍ Установка termux
После получения root необходимо установить эмулятор терминала termux. C его помощью мы будем выполнять все эксперименты. Ставить termux лучше с сайта F-Droid, поскольку в «Google play» размещена старая версия, имеющая проблемы с репозиториями.
▍ Настройка SSH сервера в termux
Команды настройки SSH сервера должны выполняться от обычной учётной записи, root использовать не нужно.
- Первым делом необходимо обновить termux:
pkg update -y
Во время выполнения обновлений менеджер пакетов будет спрашивать, что делать с имеющимися конфигурационными файлами. Для наших целей лучше их обновить. - Установим необходимые пакеты:
pkg install -y termux-auth openssh
- Теперь нам необходимо узнать имя пользователя, под которым работает termux. Наберём команду:
id
Ответ будет содержать строку с идентификаторами, среди которых «uid» (user id) будет содержать требуемое имя. - Для того, чтобы иметь возможность авторизации в SSH по паролю, необходимо его назначить. Сделаем это с помощью команды:
passwd
- Узнаем IP-адрес, который получил смартфон по WiFi. Выполним команду:
ipconfig
- Запустим OpenSSH сервер:
sshd
Всё готово для подключения по SSH. Мы знаем IP адрес смартфона, у нас есть имя пользователя и пароль, единственное порт для подключения стоит использовать 8022, так как именно его используется OpenSSH в termux по умолчанию.
▍ Решение проблем с OpenSSH в termux
Если с компьютера подключиться к смартфону по SSH не удаётся, то можно попробовать следующие варианты:
- Перезагрузить OpenSSH, последовательно выполнив команды:
pkill sshd sshd
- Перезагрузить смартфон.
При сохранении проблем попробуйте поискать ответы в официальном руководстве termux по настройке удалённого доступа.
▍ Настройка прав root в Magisk
Первый раз, набрав команду «su», в termux сработает оповещение от Magisk, которое запросит вашего одобрения наделения (grant) приложения termux root доступом. Необходимо согласиться.
Настройка USB-порта в Andoid
▍ Особенности использования привилегий root в Android
Если очень упростить, то можно сказать, что операционная система Android – это слоёный пирог (Рис. 2), где всю низкоуровневую работу выполняет Linux, а приложения работают в виртуальной машине Android runtime.
Рис. 2
Приложения бывают обычные, привилегированные (системные) и разработанные поставщиком устройства (Device manufacturer apps). Перенастройка USB-порта недоступна обычным приложениям, а повышение уровня доступа до привилегированного сопряжено с определёнными сложностями.
Но есть другой вариант. Дело в том, что в виртуальной машине Android runtime существует API, позволяющий выполнять Linux-команды, а уже с их помощью можно сделать практически всё что угодно. Ограничением будут лишь полномочия пользователя, под которым работает приложение, и механизмы разграничения доступа самого Linux (например, SELinux).
Процедура перенастройки USB-интерфейса с помощью вызова Linux-команд является привилегированной и недоступна для обычного приложения, требуется root-доступ. Несмотря на то что мы ранее получили root, это вовсе не значит, что все наши приложения стали запускаться из-под пользователя root. Они всё так же запускаются из-под ограниченной учётной записи, и то, чего нельзя было делать ранее (до получения root), нельзя делать и сейчас. Единственным важным отличием стало то, что теперь (после получения root) есть возможность выполнить команду «su», которая запускает привилегированную командную оболочку (shell), где как раз и можно выполнить все необходимые нам действия.
▍ Что значит запустить от root
Всякий раз, когда требуется выполнить команду или скрипт из-под учётной записи root это означает, что предварительно нужно повысить полномочия с помощью команды «su», а потом выполнять требуемые действия.
Linux USB Gadget
В терминах Linux-ядра смартфон, оснащённый настраиваемым USB-контроллером, называется Linux USB Gadget. Виртуальная файловая система configfs — наиболее удобный способ его конфигурирования.
Смартфоны бывают разные, и в некоторых из них, например, в старых моделях подобного функционала может и не быть. Для того чтобы удостовериться, что ваш смартфон позволяет настраивать USB-порт через configfs, необходимо проверить опции Linux-ядра:
#!/system/bin/sh
echo KERNEL_VERSION=`(uname -r |cut -d '-' -f1 )`
gunzip -c /proc/config.gz | grep -i configfs
Для наших целей на выходе скрипта должны присутствовать строки:
...
CONFIG_USB_CONFIGFS=y
…
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
…
CONFIG_USB_CONFIGFS_F_HID=y
…
Они означают, что Linux-ядро поддерживает настройку USB через configfs, и вдобавок поддерживаются режимы MASS_STORAGE (флешка) и HID (клавиатура, мышь).
▍ Настройка USB-интерфейса через configfs
Определить точку монтирования configfs можно с помощью команды:
mount | grep configfs
Обычно в Android это «/config». Настройки USB-интерфейса лежат в каталоге «/config/usb_gadget/».
Вот здесь становится интересно. Если посмотреть содержимое этого каталога:
ls /config/usb_gadget/
то можно увидеть, что в нём существует единственный подкаталог «g1» – это так называемый системный профиль USB-порта, созданный оболочкой Android. Кроме него, в каталоге «/config/usb_gadget/» можно создать сколь угодно других профилей, но активным может быть только один. В связи с этим у нас есть две стратегии конфигурирования USB-порта:
- Мы можем создавать новый профиль и затем делать его активным, отключив старый профиль (так сделано в разделе «Быстрый старт»).
- Мы можем добавлять/удалять функции в уже существующем активном профиле.
Каждый подход имеет свои плюсы и минусы. Создавая и активируя новый профиль, поддерживающий клавиатуру, мышь и флешку, мы будем вынуждены отключить системный профиль, что, например, может привести к тому, что отладка по USB будет недоступна.
Изменяя функционал существующего, например, системного профиля, мы, в некоторых случаях можем получить плавающие «глюки» в работе USB, а также конкуренцию с оболочкой Android по настройке USB-порта. Поэтому каждая конкретная ситуация будет требовать своего решения.
Использование виртуальной файловой системы configfs для настройки USB-порта имеет ряд особенностей:
- За исключением имени профиля, названия всех файлов и каталогов предопределены. Внутри configfs нельзя создать произвольный файл или каталог.
- Форматы записываемых в файлы данных предопределены.
- Для удаления каталогов следует использовать «rmdir», предварительно удалив из него все внутренности. Использование «rm -rf» может повлечь проблемы.
- Изменения в configfs пропадают после перезагрузки устройства.
▍ Несколько слов о конфигурации USB-устройств
Перед тем как приступить к конфигурированию USB-порта, нам потребуется разобраться с принципами функционирования USB-устройств. Первое, на чём хочется заострить внимание, это то, что наша идея превратить смартфон одновременно в клавиатуру, мышь и флешку не является чем-то экстраординарным. Никого ведь не смущают МФУ, совмещающие в себе одновременно фикции принтера, сканера и факса. Подобные USB-устройства, обладающие множеством функций, в терминах USB, называются композитными. Кстати, множество игровых мышек также являются композитными устройствами, сочетающими в себе функции мышки и клавиатуры (Рис. 3). Поэтому наш гибрид – вполне заурядная вещь в мире USB.
Рис. 3
Поскольку к USB-шине может быть подключено множество самых разных устройств, компьютер (USB-хост) должен понимать, что к нему подключилось и как с этим работать. Для этого USB-устройство обменивается с компьютером набором дескрипторов:
- Дескриптор устройства, содержащий информацию о том, какая версия USB поддерживается устройством, классе устройства, идентификаторы производителя и устройства, а также ряд других параметров.
- Дескрипторы конфигураций устройства. Спецификация USB позволяет устройствам иметь несколько конфигураций, например, одна конфигурация может подразумевать питание устройства от встроенного блока питания, а вторая – питание через шину USB. Операционная система компьютера может выбрать одну из конфигураций устройства в зависимости от своих настроек и параметров работы. Например, ноутбук при питании от сети может активировать конфигурацию устройства с питанием через шину USB, а при питании от батареи использовать конфигурацию, подразумевающую питание устройства через встроенный блок питания.
- Дескрипторы строк. Содержат текстовую информацию, ассоциированную с устройством.
- Дескрипторы отчёта HID устройства (USB HID Report descriptor). Данный вид дескриптора применяется только к HID (Human Interface Device) устройствам, таким как мышь, клавиатура, джойстик и т. д. А вот USB-флешка, например, подобный дескриптор отправлять не будет, поскольку не является HID устройством. Если максимально упростить, то в самом дескрипторе содержаться сведения о том, как интерпретировать поступающую с устройства информацию.
Таким образом, конфигурирование USB-порта с помощью configfs сводится к тому, чтобы предоставить Linux-ядру необходимую информацию, на базе которой оно сформирует требуемый набор дескрипторов.
▍ Файловая структура configfs
Настало время разобраться со структурой configfs в части конфигурирования USB-порта. Для этого создадим в каталоге /config/usb_gadget/ новый профиль устройства и назовём его «xxx»:
mkdir /config/usb_gadget/xxx
Сразу после выполнения этой команды в каталоге «/config/usb_gadget/xxx» была создана следующая файловая структура:
Файл или каталог | Описание |
UDC | Файл, указывающий на активность профиля. Если файл пуст, то профиль не активен, если нет, то в нём указывается имя драйвера устройства, ассоциированного с этим профилем. Для отключения профиля используется команда:
Для активации профиля:
|
Параметры, используемые для формирования дескриптора устройства |
|
bDeviceClass | Файлы, содержащие шестнадцатеричные коды USB-устройств. Перечень возможных кодов приведён на сайте USB-IF |
bDeviceProtocol | |
bDeviceSubClass | |
bMaxPacketSize0 | Максимальный размер пакета для конечной точки 0. Допустимые размеры 8, 16, 32, 64. По факту, вне зависимости от указанного здесь значения Android USB Gadget будет использоваться значение 64. |
bcdUSB | Номер спецификации USB, с которой совместимо устройство. По факту, вне зависимости от указанного здесь значения Android USB Gadget будет использоваться значение совместимости с USB 2.0. |
bcdDevice | Номер версии устройства. |
idVendor | Параметры, используемые операционной системой для нахождения драйвера для устройства. idVendor назначается организацией USB-IF, idProduct назначается производителем. |
idProduct | |
Параметры, используемые для формирования дескрипторов конфигурации и строковых дескрипторов | |
functions/ | В данном каталоге содержатся подкаталоги, описывающие определённую функцию USB-устройства. Подкаталог «hid.keyboard» описывает клавиатуру, «hid.mouse» – мышь, «mass_storage.0» – флешку. Детальное содержимое этих подкаталогов будет рассмотрено далее. |
configs/ | Каталог содержит подкаталоги, соответствующие конфигурации устройства. Подкаталог с конфигурацией должен иметь имя, состоящее из буквы и цифры, например, «b.1». |
config/<подкаталог с конфигурацией устройства>/ | Здесь содержатся символические ссылки на каталоги функций из папки «functions/», а также ряд файлов, содержимое которых для нас неважно. Наличие символической ссылки делает функцию активной. Например, если в рассматриваемом каталоге будет символическая ссылка на каталог …functions/hid.mouse, это будет означать, что функция hid.mouse активна. |
strings/ | Содержит подкаталоги с описанием устройства на заданных языках. Имя подкаталога соответствует коду языка. Коды языков определены организацией USB.org. Например, код 0x409 соответствует английскому языку (en-US). |
strings/<код языка>/manufacturer | Файл, содержащий текстовое название производителя |
strings/<код языка>/manufacturer | Файл, содержащий текстовое название продукта |
strings/<код языка>/serialnumber | Файл, содержащий серийный номер устройства |
os_desc/ | Каталог отвечает за поддержку функции «OS Description». В наших экспериментах она использоваться не будет. По умолчанию функция отключена. |
▍ Структура каталогов «hid.mouse» и «hid.keyboard»
Описание функций мышки и клавиатуры имеют одинаковую структуру, различающуюся содержимым.
Файл | Описание |
protocol | Номер протокола: 1 – клавиатура, 2 – мышь |
subclass | Номер подкласса. В нашем случае всегда будет 1, указывающий, что это подкласс Boot Interface. Другими словами, создаваемая нами клавиатура и мышь будут совместимы даже с BIOS. |
report_length | Длина отчёта о состоянии устройства. Определяется дескриптором отчёта HID устройства. В нашем случае: 8 – клавиатура, 4 – мышь. |
report_desc | Двоичный код дескрипторов отчёта HID-устройств. Далее рассмотрим их более подробно. |
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0xE0, // Usage Minimum (0xE0)
0x29, 0xE7, // Usage Maximum (0xE7)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (LEDs)
0x19, 0x01, // Usage Minimum (Num Lock)
0x29, 0x05, // Usage Maximum (Kana)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x65, // Logical Maximum (101)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0x00, // Usage Minimum (0x00)
0x29, 0x65, // Usage Maximum (0x65)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
// 63 bytes
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x05, // Usage Maximum (0x05)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x38, // Usage (Wheel)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x08, // Report Size (8)
0x95, 0x03, // Report Count (3)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0xC0, // End Collection
// 52 bytes
В тоже время дескрипторы, представленные в официальной документации [1].Appendix E: Example USB Descriptors for HID Class Devices для работы с Android не подошли.
Если вам захочется поэкспериментировать с дескрипторами отчёта, то можете воспользоваться официальной утилитой от USB-IF, либо онлайн-парсером от Frank Zhao.
▍ Структура каталога mass_storage.0
В отличие от клавиатуры и мыши, каталог, описывающий функцию флешки, имеет совершенно другую структуру
Файл | Описание |
stall | Файл-флаг, разрешающий (значение «1») остановку массовых конечных точек (bulk endpoints). По умолчанию должен быть включён. Отключать следует только при возникновении проблем. |
/lun.<число>/ | Подкаталог с настройками конкретной логической единицы хранения (LUN). |
/lun.<число>/file | Файл, содержащий имя файла образа флешки. |
ro | Файл-флаг, устанавливающий возможность записи в хранилище. 0 – запись возможна, 1 – запрещена (read-only). |
removable | Файл-флаг, указывающий на то, что устройство следует интерпретировать как отчуждаемое. 1 – да, 0 – нет. |
cd | Файл-флаг, указывающий на то, что устройство следует интерпретировать CD-ROM. 1 – да, 0 – нет. |
nofua | Файл-флаг, указывающий на то, что устройство должно поддерживать функцию SCSI FUA. 1 – да, 0 – нет. |
▍ Устройства /dev/hidg0 и /dev/hidg1
После того как в активном профиле USB-порта активированы функции клавиатуры и мыши, в системе появятся два новых устройства /dev/hidg0 и /dev/hidg1. Первое соответствует клавиатуре, а второе — мыши. Посылая отчёты в эти устройства, мы можем имитировать нажатия кнопок на клавиатуре или движения мыши.
Отключение функций клавиатуры или мышки в активном USB профиле приведёт к тому, что эти устройства перестанут существовать. Что такое отчёты, и как их формировать, мы поговорим далее.
▍ Дополнительные скрипты для настройки USB-порта в смартфоне
Закрывая тему настройки USB-порта в смартфоне, рассмотрим ещё ряд вспомогательных скриптов, которые позволят вам глубже поковыряться в этой теме.
▍ Удаление профиля
Первый скрипт позволяет удалить ранее созданный профиль USB-порта. Название профиля должно передаваться в качестве первого позиционного параметра.
Примечание. Не удаляйте системный профиль «g1», смартфон может повиснуть.
#!/system/bin/sh
# remove_profile.sh
PROFILE_NAME="$1"
PROFILE_BASEPATH="/config/usb_gadget/"
PROFILE_PATH="${PROFILE_BASEPATH}${PROFILE_NAME}"
if [ -z "$PROFILE_NAME" ]; then
echo "Specify the profile name: \n$(ls $PROFILE_BASEPATH)"
exit 1
fi
# Stop profile
echo "" > ${PROFILE_PATH}/UDC
# Disable active functions
find ${PROFILE_PATH}/configs/ -type l -delete
# Remove config
find ${PROFILE_PATH}/configs/ -type d -delete
# Remove functions
find ${PROFILE_PATH}/functions/ -type d -delete
# Remove strings
find ${PROFILE_PATH}/strings/ -type d -delete
# Remove profile
rmdir "$PROFILE_PATH"
▍ Получение сведений о существующих USB профилях
Следующий скрипт позволяет получить информацию об имеющихся профилях, включая полный перечень доступных функций и список активных функций в профиле.
#!/system/bin/sh
# get_profiles_info.sh
for dir in /config/usb_gadget/*/
do
echo PROFILE_PATH=$dir
cd ${dir}configs/
echo CONFIG_PATH="${dir}configs/$(ls -1 | head -1)/"
cd $dir
if [ "$?" -ne "0" ]; then
echo "Error. Unable to change dir to $dir... exit"
exit 1
fi
echo UDC=$(cat UDC)
find ./configs/ -type l -exec sh -c 'echo FUNCTIONS_ACTIVE=$(basename $(readlink "$@"))' _ {} \;
for f in `ls -1 ./functions/`;
do
echo FUNCTIONS=$f;
done;
cd ./strings/0x409/;
for vars in *
do
echo ${vars}=$(cat $vars)
done
echo "============="
done
▍ Добавление функций клавиатуры, мыши и флешки к системному профилю USB-порта
Как упоминалось ранее, настраивать USB-порт можно как путём добавления нового профиля, так и активируя функции в уже имеющемся профиле. Представленный ниже скрипт добавляет функции клавиатуры, мыши и флешки к системному USB-профилю.
#!/system/bin/sh
# enable_func_in_sys_profile.sh
PROFILE_NAME="g1"
PROFILE_BASEPATH="/config/usb_gadget/"
PROFILE_PATH="${PROFILE_BASEPATH}${PROFILE_NAME}"
PROFILE_CONFIG_NAME="b.1"
STORAGE_FILE_NAME="/data/data/com.termux/files/home/storage_file.img"
STORAGE_FILE_SIZE="100M"
KEYBOARD_REPORT_DESC="\
\\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\
\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\
\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\
\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\
\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\
\\x81\\x00\\xc0"
MOUSE_REPORT_DESC="\
\\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\
\\x19\\x01\\x29\\x05\\x15\\x00\\x25\\x01\\x95\\x05\\x75\\x01\
\\x81\\x02\\x95\\x01\\x75\\x03\\x81\\x01\\x05\\x01\\x09\\x30\
\\x09\\x31\\x09\\x38\\x15\\x81\\x25\\x7F\\x75\\x08\\x95\\x03\
\\x81\\x06\\xc0\\xc0"
# create keyboard function
mkdir -p "$PROFILE_PATH/functions/hid.keyboard"
cd "$PROFILE_PATH/functions/hid.keyboard"
if [ $? -eq 0 ]; then
echo 1 > protocol # Keyboard
echo 1 > subclass # Boot Interface Subclass
echo 8 > report_length
echo -ne $KEYBOARD_REPORT_DESC > report_desc
else
echo "keyboard function create fail"
exit 1
fi
# create mouse function
mkdir -p "$PROFILE_PATH/functions/hid.mouse"
cd "$PROFILE_PATH/functions/hid.mouse"
if [ $? -eq 0 ]; then
echo 2 > protocol # Mouse
echo 1 > subclass # Boot Interface Subclass
echo 4 > report_length
echo -ne $MOUSE_REPORT_DESC > report_desc
else
echo "mouse function create fail"
exit 1
fi
# create mass_storage image file
if [ ! -f "$STORAGE_FILE_NAME" ]; then
fallocate -l $STORAGE_FILE_SIZE $STORAGE_FILE_NAME
fi
# create mass_storage function
mkdir -p "$PROFILE_PATH/functions/mass_storage.0"
cd "$PROFILE_PATH/functions/mass_storage.0/lun.0"
if [ $? -eq 0 ]; then
echo 1 >../stall
echo 0 > cdrom
echo 0 > removable
echo 0 > ro
echo 0 > nofua
echo "$STORAGE_FILE_NAME" > file
else
echo "mass_storage function create fail"
exit 1
fi
# Disable current profile
echo "" > $PROFILE_PATH/UDC
# Enable keyboard, mouse and mass storage functions
cd "$PROFILE_PATH/configs/$PROFILE_CONFIG_NAME/"
if [ $? -eq 0 ]; then
ln -s "$PROFILE_PATH/functions/hid.keyboard" ./
ln -s "$PROFILE_PATH/functions/hid.mouse" ./
ln -s "$PROFILE_PATH/functions/mass_storage.0" ./
else
echo "functions enable fail"
exit 1
fi
# Enable current profile
ls /sys/class/udc > $PROFILE_PATH/UDC
exit 0
▍ Отключение функций клавиатуры, мыши и флешки в системном USB-профиле
Это скрипт антагонист предыдущему. Он отключает (но не удаляет) ранее созданные функции в системном профиле.
#!/system/bin/sh
# disable_func_in_sys_profile.sh
PROFILE_NAME="g1"
PROFILE_BASEPATH="/config/usb_gadget/"
PROFILE_PATH="${PROFILE_BASEPATH}${PROFILE_NAME}"
PROFILE_CONFIG_NAME="b.1"
# Stop profile
echo "" > "${PROFILE_PATH}/UDC"
rm "${PROFILE_PATH}/configs/$PROFILE_CONFIG_NAME/hid.keyboard"
rm "${PROFILE_PATH}/configs/$PROFILE_CONFIG_NAME/hid.mouse"
rm "${PROFILE_PATH}/configs/$PROFILE_CONFIG_NAME/mass_storage.0"
# Start profile
ls /sys/class/udc > "${PROFILE_PATH}/UDC"
exit 0
Использование USB-порта в Android
▍ Разбираемся с работой клавиатуры
USB-клавиатура при изменении своего состояния (нажатии или отпуске клавиши) посылает отчёт следующего формата ([1].B.1 Protocol 1 (Keyboard)):
Байт | Назначение |
0 | Модификатор |
1 | Резерв |
2 | Код клавиши 1 |
3 | Код клавиши 2 |
4 | Код клавиши 3 |
5 | Код клавиши 4 |
6 | Код клавиши 5 |
7 | Код клавиши 6 |
Бит | Назначение |
0 | LEFT CTRL |
1 | LEFT SHIFT |
2 | LEFT ALT |
3 | LEFT GUI |
4 | RIGHT CTRL |
5 | RIGHT SHIFT |
6 | RIGHT ALT |
7 | RIGHT GUI |
Рис. 4
Сама спецификация в открытом доступе, так что вы легко сможете её найти. Кроме официальной спецификации, можете посмотреть GitHub-репозиторий tmk_keyboard, содержащий визуальную карту кодов кнопок. На первых этапах он, наверное, будет более понятным.
Со справочной информацией покончено, перейдём к анализу принципа работы. Как вы скорее всего уже заметили, USB-клавиатура может обрабатывать одновременно нажатие 6 клавиш, а с учётом клавиш модификаторов это количество увеличивается до 14. В этой связи протокол её работы ([1].Appendix C: Keyboard Implementation) имеет определённую специфику: передаются только изменения состояния клавиатуры. Другими словами, если пользователь нажал кнопку, изменение произошло, если удерживает, то ничего не меняется, если отпустил, то опять изменение.
Чтобы с этим разобраться рассмотрим ряд примеров:
- В скрипте, имитирующем нажатие кнопки «а», мы имитировали действия пользователя, при котором он сначала нажал кнопку «а», а потом отпускал все нажатые кнопки. По факту мы посылали в клавиатуру два отчёта:
- 00 00 04 00 00 00 00 00 – нажатие кнопки «а»;
- 00 00 00 00 00 00 00 00 – отпуск всех ранее нажатых кнопок.
- Теперь усложним. Допустим мы хотим имитировать ввод заглавной «А». Для этого нам нужно послать отчёт, содержащий код буквы «а» с активным модификатором Left Shift (хотя можно выбрать и Right Shift). Отчёт для ввода заглавной «А» будет выглядеть так:
- 02 00 04 00 00 00 00 00 – ввод «А».
- Что будет, если просто пошлём отчёт в нажатой «А» и больше ничего слать не будем? А произойдёт следующие. ПО компьютера, к которому подключён смартфон подождёт 0,5 сек, а затем будет генерировать нажатия «А» и будет это происходить до тех пор, пока клавиатура не отправит код отпуска всех клавиш.
- Давайте теперь разберёмся, что значит «отпустить кнопку» и «отпустить все кнопки». Понять это можно на примере. Пользователь нажимает кнопку «а», клавиатура посылает отчёт «00 00 04 00 00 00 00 00». Затем, не отпуская её он нажимает «m» – тогда будет послан код «00 00 04 10 00 00 00 00». Теперь он, продолжая удерживать «m» отпускает «a» – будет послан отчёт «00 00 10 00 00 00 00 00». То есть, код «а» (04) пропал, а его место занял код «m» (10). Когда он отпустит «m» будет послан код «00 00 00 00 00 00 00 00». Таким образом, кода отпуска какой-то конкретной клавиши не существует. Зато есть код, обозначающий, что все клавиши отпущены.
Закончим с клавиатурой, рассмотрев скрипт, вызывающий блокнот и печатающий в нём «Hello World!!».
#!/system/bin/sh
# print_hello_world.sh
echo "\x08\x00\x15\x00\x00\x00\x00\x00" > /dev/hidg0 # press Win+R
sleep 1s # wait until window apears
echo "\x00\x00\x00\x00\x00\x00\x00\x00" > /dev/hidg0 # release key
echo "\x00\x00\x11\x00\x00\x00\x00\x00" > /dev/hidg0 # press n
echo "\x00\x00\x12\x00\x00\x00\x00\x00" > /dev/hidg0 # press o
echo "\x00\x00\x17\x00\x00\x00\x00\x00" > /dev/hidg0 # press t
echo "\x00\x00\x08\x00\x00\x00\x00\x00" > /dev/hidg0 # press e
echo "\x00\x00\x13\x00\x00\x00\x00\x00" > /dev/hidg0 # press p
echo "\x00\x00\x04\x00\x00\x00\x00\x00" > /dev/hidg0 # press a
echo "\x00\x00\x07\x00\x00\x00\x00\x00" > /dev/hidg0 # press d
echo "\x00\x00\x37\x00\x00\x00\x00\x00" > /dev/hidg0 # press .
echo "\x00\x00\x08\x00\x00\x00\x00\x00" > /dev/hidg0 # press e
echo "\x00\x00\x1B\x00\x00\x00\x00\x00" > /dev/hidg0 # press x
echo "\x00\x00\x08\x00\x00\x00\x00\x00" > /dev/hidg0 # press e
echo "\x00\x00\x28\x00\x00\x00\x00\x00" > /dev/hidg0 # press Enter
echo "\x00\x00\x00\x00\x00\x00\x00\x00" > /dev/hidg0 # release key
sleep 3s # wait until window apears
echo "\x02\x00\x0B\x00\x00\x00\x00\x00" > /dev/hidg0 # press H
echo "\x00\x00\x08\x00\x00\x00\x00\x00" > /dev/hidg0 # press e
echo "\x00\x00\x0F\x00\x00\x00\x00\x00" > /dev/hidg0 # press l
echo "\x00\x00\x0F\x00\x00\x00\x00\x00" > /dev/hidg0 # press l
echo "\x00\x00\x12\x00\x00\x00\x00\x00" > /dev/hidg0 # press o
echo "\x00\x00\x2C\x00\x00\x00\x00\x00" > /dev/hidg0 # press Space
echo "\x02\x00\x1A\x00\x00\x00\x00\x00" > /dev/hidg0 # press W
echo "\x00\x00\x12\x00\x00\x00\x00\x00" > /dev/hidg0 # press o
echo "\x00\x00\x15\x00\x00\x00\x00\x00" > /dev/hidg0 # press r
echo "\x00\x00\x0F\x00\x00\x00\x00\x00" > /dev/hidg0 # press l
echo "\x00\x00\x07\x00\x00\x00\x00\x00" > /dev/hidg0 # press d
echo "\x02\x00\x1E\x00\x00\x00\x00\x00" > /dev/hidg0 # press !
echo "\x00\x00\x00\x00\x00\x00\x00\x00" > /dev/hidg0 # release key
▍ Особенности использования скриптов для виртуальной клавиатуры
Человек, когда работает за компьютером, видит результаты своей работы, а скрипт, генерирующий нажатия клавиш – нет, это порождает ряд проблем:
- Заранее неизвестно, какая клавиатурная раскладка активна на компьютере. Скрипт вместо английских букв может начать вводить русские и наоборот. Не известны также горячие кнопки переключения, это может быть как Shift+Alt, так и Ctrl+Shift или другие.
- Если скрипт запускает программы, то им нужно время на отрисовку и получение фокуса ввода. Причём время запуска в общем случае может сильно варьироваться. Кнопки, нажатые до отрисовки требуемой программы, в лучшем случае могут уйти «в молоко», а худшем – натворить разных плохих дел.
▍ Разбираемся с работой мыши
Мышь, как и клавиатура, на каждое изменение своего состояния посылает отчёт. Формат отчёта определён в спецификации [1].B.2 Protocol 2 (Mouse). После экспериментов над Android, превращённым в мышь, спецификацию отчёта пришлось дополнить, и в итоге она стала выглядеть так:
Байт | Описание |
0 | Состояние кнопок |
1 | Перемещение по X («+» – влево, «-» – вправо) |
2 | Перемещение по Y («+» – вверх, «-» – вниз) |
3 | Колёсико («+» – вверх, «-» – вниз) |
Бит | Описание |
0 | Левая кнопка |
1 | Правая кнопка |
2 | Средняя кнопка |
3 | Навигация назад |
4 | Навигация вперёд |
5-7 | Неопределенно |
Рис. 5
Система координат начинается в верхнем левом углу экрана. Ось X растёт слева направо, ось Y сверху вниз. Новое положение курсора вычисляется по формулам:
где New X – новое значение координаты X курсора, Old X – предыдущие значение координаты X курсора, Move X – изменение значения координаты X курсора, полученное из USB отчёта мыши. Значения New Y, Old Y и Move Y – аналогичны, но для координаты Y. Если значение Move X отрицательное, то курсор смещается влево, если положительное, то вправо. Если значение Move Y отрицательное, то курсор подымается вверх, иначе смещается вниз.
Колёсико мышки обрабатывается по принципу: положительное значение – скроллинг вверх, отрицательное – скроллинг вниз. Величина скролллинга определяется значением параметра «колёсико» в USB-отчёте.
C мышкой не всё так просто. Есть ряд нюансов, которые необходимо учитывать:
- Получаемые координаты курсора мыши являются виртуальными. Чтобы операционная система могла перерисовать курсор в новом положении экрана, она переводит их в экранные значения с учётом разрешения экрана и работы функций акселерации, которая ускоряет перемещения экранного курсора в зависимости от интенсивности движения физической мыши. На более резкий сдвиг мыши экранный курс отодвинется дальше.
- Мышь отправляет USB-отчёты с определённой частотой, и на перемещение экранного курсора также тратится время. Это может привести к неожиданным последствиям. Рассмотрим скрипт, который должен нарисовать в MS Paint квадрат:
#!/system/bin/sh # mouse_draw_rect.sh echo "\x01\x00\x00\x00" > /dev/hidg1 # Press LMB echo "\x01\x7F\x00\x00" > /dev/hidg1 # Move MAX Right echo "\x01\x01\x00\x00" > /dev/hidg1 # Move MIN Right echo "\x01\x00\x00\x00" > /dev/hidg1 # Press LMB echo "\x01\x00\x7F\x00" > /dev/hidg1 # Move MAX Down echo "\x01\x00\x01\x00" > /dev/hidg1 # Move MIN Down echo "\x01\x00\x00\x00" > /dev/hidg1 # Press LMB echo "\x01\x81\x00\x00" > /dev/hidg1 # Move MAX Left echo "\x01\xFF\x00\x00" > /dev/hidg1 # Move MIN Left echo "\x01\x00\x00\x00" > /dev/hidg1 # Press LMB echo "\x01\x00\x81\x00" > /dev/hidg1 # Move MAX Up echo "\x01\x00\xFF\x00" > /dev/hidg1 # Move MIN Up echo "\x00\x00\x00\x00" > /dev/hidg1 # Release LMB
Здесь сначала нажимается левая кнопка мыши, затем курсор с зажатой кнопкой двигается вправо, затем вниз, потом вверх, где и отпускается кнопка. При этом между изменениями движения курсора вставлен отчёт, который просто удерживает нажатой левую кнопку мыши. Если этого не делать, то в некоторых случаях вместо ожидаемого квадрата на экране можно увидеть треугольник.
Имитация действий человека и обнаружение ботов
Рассмотрим ряд признаков, которые позволят отличить управление клавиатурой и мышью реальным человеком от управления этими же устройствами ботом, использующим Android как средство ввода.
Поведенческие признаки:- Послав отчёты «02 00 04 00 00 00 00 00» и «00 00 00 00 00 00 00 00» бот обеспечит ввод одной заглавной «А». Но клавиатура, управляемая человеком, посылала бы другие коды. Вначале был бы послан код нажатия Left Shift – «02 00 00 00 00 00 00 00», затем при нажатом Left Shift была бы нажата «а» – код «02 00 04 00 00 00 00 00», потом отпущена «а» – код «02 00 00 00 00 00 00 00», а затем отпущен Left Shift – «00 00 00 00 00 00 00 00».
- Кроме того, у всех людей разные размеры ладоней, моторика пальцев и привычки. Временные задержки между нажатием и отпуском клавиш, относительные задержки между вводом различных букв, предпочтения по используемым модификаторам образуют уникальный клавиатурный подчерк конкретного человека.
- Мышь, управляемая человеком, отличается от мыши, управляемой ботом. Реальная мышь обычно генерирует гигантское количество отчётов на малейшее перемещение. Причём в самих отчётах изменение координат происходит на 1 или чуть больше. Бот же будет генерировать небольшое число отчётов с большим изменением координат.
- Человек практически не в состоянии провести курсор по прямой, будут хоть и небольшие, но биения в обеих координатах. Бот же в свою очередь будет практически всегда перемещать курсор по прямым линиям.
Аппаратные признаки:- Кроме поведенческих признаков ботов можно выявлять и по аппаратным особенностям, анализируя обмен USB-пакетами. В ходе экспериментов установлено, что Android имеет определённые ограничения на имитацию USB-устройств. Например, полностью сымитировать существующую игровую мышь на нём невозможно. Реальная мышь в дескрипторах устройства сигнализирует о работе в режиме USB 1.1, в то время как Android всегда отдаёт USB 2.0. Кроме этого есть ещё множество других демаскирующих потенциального бота признаков.
Создание родного (native) приложения
В этой статье повсеместно используются скрипты, и у вас может сложиться мнение, что, кроме как из termux, взаимодействовать с виртуальной клавиатурой и мышью никак нельзя, но это не так. Как уже отмечалось в начале статьи, из родного API Andoird можно выполнять Linux команды. Для наших целей нужно выполнить команду «su», что приведёт к формированию оболочки. Затем, используя перенаправление потоков ввода-вывода, ей можно подавать на вход любые другие команды, включая скрипты, и получать результаты их выполнения. Поэтому вы можете смело брать написанный здесь код и выполнять его из своего приложения. Пример того как работать с «su» в Android, вы можете найти в этой статье.
Все скрипты, приведённые в этой статье, являются свободным ПО и могут использоваться без каких-либо ограничений.
Сценарии использования
Мы научились нажимать смартфоном кнопки клавиатуры, шевелить курсором мыши и получили новую флешку, что с этим всем делать? А применений нашему комбайну на самом деле очень много:
- Для системных администраторов:
- Смартфон, как портативное устройство ввода (клавиатура, мышь).
Особенно актуальным будет данный сценарий при обслуживании техники вне офиса, например, банкоматов, платёжных терминалов, инфокиосков и т.д. - Многофункциональный LiveUSB.
На смартфоне можно создать несколько образов загрузочных флешек под различные задачи. Затем по необходимости, можно выбирать нужный образ простым изменением настроек в скриптах переконфигурирования USB-интерфейса. - Автоинсталлятор.
С помощью смартфона можно проводить автоинсталляцию ПО. Для этого необходимые дистрибутивы записываются на флешку, а для клавиатуры и мыши пишутся скрипты, управляющие процессом инсталляции.
- Смартфон, как портативное устройство ввода (клавиатура, мышь).
- Для разработчиков:
- Автотестер.
С помощью смартфона, имитируя действия клавиатуры и мыши, можно выполнять тестирование разрабатываемого ПО.
- Автотестер.
- Для обычных людей
- Имитатор работы.
При работе на удалёнке некоторые компании проверяют, чтобы человек постоянно что-то делал за компьютером. С помощью смартфона можно имитировать пользовательскую активность, не дающую, например, мессенджерам перейти в статус «Отошёл».
- Имитатор работы.
Инструменты исследования
В ходе исследования очень помогли инструменты:
- Wireshark с модулем USBCap. Знаменитый сниффер, который может использоваться и для отладки USB-устройств. С его помощью в режиме реального времени можно увидеть весь информационный обмен между компьютером и устройством, включая USB дескрипторы, отчёты и прочее.
- Python библиотека hid-tools. Имеет целую коллекцию инструментов для работы с USB HID устройствами. Основной изюминкой библиотеки является возможность получения от устройства данных (дескрипторов, отчётов) в понятном для человека виде.
Список источников
- Universal Serial Bus (USB) Device Class Definition for Human Interface Devices (HID) Firmware Specification—5/27/01 Version 1.11
- HID Usage Tables FOR Universal Serial Bus (USB) Version 1.5
Telegram-канал со скидками, розыгрышами призов и новостями IT ?
Комментарии (41)
Grey83
02.06.2024 14:38+1Android-смартфон с разблокированной учётной записью root.
У смартов с последними версиями ведроида на борту с этим проблема, емнип.
Сначала ещё нужно разлочить загрузчик (и не везде это просто делается), а потом только можно будет получить root. Производители закручивают гайки с каждым годом всё туже.
В общем нужно смотреть профильную тему на 4PDA/XDA.
Ну и наличие кастомного рекавери тоже хорошо бы предварительно проверить (т.к. первый попавшийся не подойдёт).При перепрошивке смартфона подключать его следует только к USB 2.0 портам компьютера. Если их нет, то потребуется USB 2.0 хаб. Использование USB 3.0 портов (или более новых) может сопровождаться ворохом проблем
А просто провода поддерживающего только стандарт 2.0 недостаточно (не говоря о том, что всё ещё крайне мало устройств поддерживают стандарт 3.0)? Например такой, где с одной стороны просто USB Type-A v2.0 (т.е. только с 4 контактами).
CitizenOfDreams
02.06.2024 14:38+8А ведь когда-то Андроид подключался как mass storage безо всяких кастомных рекавери и прочих танцев с бубном...
Grey83
02.06.2024 14:38Да вроде и сейчас должен (на 7-ке и новее: на XP у меня потребовало дрова).
CitizenOfDreams
02.06.2024 14:38+1Нет, функцию mass storage в Андроиде уже много лет назад выключили. Без рута подсоединить телефон к компьютеру можно только как MTP-устройство или как фотоаппарат. Если у вас mass storage работает из коробки - модель телефона в студию, пожалуйста.
С другой стороны, оно сейчас не особо и нужно, потому что телефоны наконец-то научились работать по MTP с более-менее нормальной скоростью. Ну и появились более удобные способы синхронизации файлов между телефоном и компом, такие как Syncthing.
Grey83
02.06.2024 14:38Ну если режим под названием "передача файлов" - это именно MTP, то тогда ой.
Хм, заглянул в настройки, в раздел "Для разработчиков": таки MTP.
UnknownErrror
02.06.2024 14:38Немного не понял, а зачем отдельно в команде установки прописывать "termux-auth"? Он же сам установится вместе с "openssh"
Достаточно команды "pkg install -y openssh" так как пакет "termux-auth" находится в зависимостях у "openssh", в чём можно легко удостовериться введя "pkg info openssh"
aspid-crazy
02.06.2024 14:38+1Стало любопытно, если попробовать считывать движения телефона акселерометром, насколько похожим окажется поведение такого смартфона-мыши? Я имею в виду, положить смартфон на стол, и возить им по столу, как мышью - насколько точно получится в этом случае двигать курсором?
Olegsoft
02.06.2024 14:38Это ненадолго... ))) usb порт расшатается за месяц ! Это вобще как то на ерунду похоже... да можно сыграть на чайнике в HL, но зачем... ?
aspid-crazy
02.06.2024 14:38+1А зачем собака виляет хвостом? Потому что может:))
Очевидно, что это ни на секунду не полезное и удобное применение смартфона, но интересно же:)SquareRootOfZero
02.06.2024 14:38+1Давно есть идея контроллера, суть такова: взять небольшой тазик, ко дну изнутри приклеить смартфон, поставить всё это под ноги и, наклоняя в разные стороны, использовать показания гироскопов в качестве как бы джойстика. Джва года хочу попробовать.
ABy
02.06.2024 14:38Wii board?
SquareRootOfZero
02.06.2024 14:38Есть (был?) контроллер под названием 3dRudder, работающий примерно как я выше описал (уже не помню, пришла мне моя идея с тазиком до того, как я узнал о его существовании, или после, типа "можно ж и самому подобное сделать, из спичек и желудей). Ставишь под ноги и ступнями наклоняешь в нужную сторону, сидя в кресле. Wii board, насколько я понял, использует не датчики наклона, а датчики веса, т. е. сидя за компом использовать не получится, надо прям стоять на ней. Хотя для VR-игр, возможно, была бы неплохая тема, а то существующие там схемы передвижения игрока в бродилках-стрелялках откровенно уйобищны.
ABy
02.06.2024 14:38По моему довольно неудобно нолучится. Хотя игрокам с ограниченными возможностями (безруким) может зайти.
Ramzez
02.06.2024 14:38Почему нельзя взять джойстик и прикрепить к нему тазик ?)) почему надо из телефона делать джойстик ?))
SquareRootOfZero
02.06.2024 14:38Существуют джойстики, работающие от наклона корпуса ?)) Я не видел ?)) Но если да, то почему нет ?))
DayDve
02.06.2024 14:38+2Для использования смартфона как мышки с акселерометром (airmouse) можно воспользоваться kdeconnect
Он и как клавиатура может использоваться
И для передачи файла (не mass storage только, а sshfs)
Devastor87
02.06.2024 14:38Люблю статьи от RUVDS: всегда подробно, понятно, интересно, полезно :)
По этой статье один вопрос:
Что будет, если просто пошлём отчёт в нажатой «А» и больше ничего слать не будем? А произойдёт следующие. ПО компьютера, к которому подключён смартфон подождёт 0,5 сек, а затем будет генерировать нажатия «А» и будет это происходить до тех пор, пока клавиатура не отправит код отпуска всех клавиш.
Это, как я понимаю, происходит из-за внутреннего механизма прерываний системы?
Можно ли его обойти в этом примере?
То есть, если ещё проще: можно ли убрать эту "паузу" в 0.5 секунд, чтобы при "нажатии" той же "а" она сразу же начинала "залипать", без пауз?
imbasoft Автор
02.06.2024 14:38Пауза возникает на стороне ОС. Соответственно воздействуя на её длительность паузы можно изменить.
p_fox
02.06.2024 14:38+1А не проще воткнуть блютуз-свисток и поставить на смарт одну из кучи прог, вроде "Bluetooth клавиатура и мышь" без всяких танцев с бубном?
unclegluk
02.06.2024 14:38Проще, я так делал. Есть даже варианты с тачпадом и дополнительным монитором (через wi-fi или шнурок). Но ведь «Нормальные герои всегда идут в обход». А потом жалуются, что смарт не так работает или окирпичился.
Grey83
Использовать смарт вместо клавы и мышки можно не подключая через USB: давно есть проги которые позволяют это делать через Wi-Fi (вроде нужно ещё клиент на ПК ставить, но это не точно).
Ну а чтобы использовать смарт как загрузочную флешку тоже имеется софт на ведроид, емнип. Названия не подскажу, т.к. давно встречал (у меня обычных достаточно, чтобы со смартом так не заморачиваться).
grvelvet
Есть, кривой, за деньги, или требует рут доступ. Если срочно нужно восстановить ОС а под рукой ничего нет, то проще распаковать образ на флешку со смартфона через otg.
Лучше иметь отдельную флешку с тем же ventoy.
Grey83
читаем статью и в самом начале её видим вот это:
Я так и делаю. Правда не везде Ventoy работает. На старом железе (которому лет 20) не стартует, например, и приходится тот же Rufus, WinSetupFromUSB, MultiBootUSB или XBoot флешку записывать (с месяц назад как раз пришлось сильно заморочиться).
evgepet
Да, Ventoy не всегда срабатывает на старых компах. Даже на 13-15-летних. Для таких "стариков" держу в кармане дополнительно три флешки, на каждой из которых, развёрнута единственная винда, или livecd.
inkelyad
Что выглядит бестолковщиной. Вот же, комп уже умеет USB HID устройствами пользоваться. А в телефоне - USB интерфейс есть.
Но нееет... возможность притвориться таким в андроиде, судя по всем, специално зарезана.
Я подозреваю, ради безопасности - чтобы зловреды, попавшие в телефон, который потом подключили(для зарядки, например) к компьютеру - не вызывали терминал и не 'набирали' чего-нибудь нехорошее.
Самое смешное, что эмулировать bluetooth HID устройства - можно без получения root-а.
Но вот, скажем, притворяться USB аудио картой/быть bluetooth audio sink -- андроиды не умеют. Видимо, чтобы осложнить запись воспроизводимого аудио.
imbasoft Автор
Этот способ позволяет не использовать клиента, в некоторых случаях это принципиальный момент.
Grey83
Даже те, которые через штатный RDP подключаются?
Ну если принципиальный и часто приходится, то проще и удобнее беспроводную клаву купить (есть такие под всякие TVBox'ы, размером со смарт, если размер важен).
DayDve