- PVSM.RU - https://www.pvsm.ru -

ВАЖНО!!! Все описанные в статье действия потребуют «взлома» смартфона и получения на нём прав суперпользователя (root). В процессе «взлома» вы можете потерять на устройстве все данные или вовсе не обратимо сломать его. Будьте осторожны! Обдумывайте свои действия, не делайте того, о чём можете пожалеть!
Сначала практика, потом теория? Нет проблем. Если вы не понаслышке знакомы с мобильными технологиями и хорошо разбираетесь с архитектурой Android, то эта глава специально для вас. Если же вы новичок, то лучше сначала прочитать главу «Подготовка смартфона», а потом вернуться сюда.
Для того чтобы приступить к экспериментам необходимо:
Проверка считается пройденной, если вы можете подключиться к смартфону по SSH и успешно выполнить на нём команду «su». Если с этим есть проблемы, то переходите в раздел «Подготовка смартфона», там разберёмся, как что настроить.
В 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 "x00x00x04x00x00x00x00x00" > /dev/hidg0 #press a
echo "x00x00x00x00x00x00x00x00" > /dev/hidg0 #release a
Теперь пошевелим курсором мыши. Следующий скрипт переместит курсор мыши на некоторое расстояние вниз. Чтобы лучше это увидеть, предварительно поставьте курсор в центр экрана.
#!/system/bin/sh
# mouse_move_down.sh
echo "x00x00x55x00" > /dev/hidg1
Это, пожалуй, самый простой тест. Если вы используете Windows, то откройте «Disk Management» («Управление дисками»), там появится новый диск на 100Mb (Рис. 1). Для использования его нужно просто отформатировать. Если у вас другая операционная система, то нужно выполнить аналогичные действия, но уже с вашей спецификой.

Рис. 1
Интересно? Хочется подробностей? Добро пожаловать в статью.
Всем, кто успешно прошёл «Быстрый старт», можно смело пропускать данную главу.
Напоминаю, что этот процесс довольно опасен. Не делайте его на вашем основном смартфоне. Используйте отдельный смартфон для тестов, который не жалко угробить. Например, подопытным кроликом для данной статьи послужил ASUS ZenFone Max Pro M1 (Android 8.1) c разбитым экраном, который до этого без дела валялся на полке.
Процесс получения root в смартфоне, как правило, состоит из следующих этапов:
Первые этапы специфичны для каждого смартфона. Найти необходимые инструкции и прошивки вы скорее всего сможете на сайтах 4PDA или XDA Forums. Если их там нет, то Яндекс в помощь.
Хочу заострить ваше внимание на одной важной особенности получения root, о которой почему-то нигде не пишут. При перепрошивке смартфона подключать его следует только к USB 2.0 портам компьютера. Если их нет, то потребуется USB 2.0 хаб. Использование USB 3.0 портов (или более новых) может сопровождаться ворохом проблем:
После получения root необходимо установить эмулятор терминала termux. C его помощью мы будем выполнять все эксперименты. Ставить termux лучше с сайта F-Droid [4], поскольку в «Google play» размещена старая версия, имеющая проблемы с репозиториями.
Команды настройки SSH сервера должны выполняться от обычной учётной записи, root использовать не нужно.
pkg update -y
Во время выполнения обновлений менеджер пакетов будет спрашивать, что делать с имеющимися конфигурационными файлами. Для наших целей лучше их обновить.
pkg install -y termux-auth openssh
id
Ответ будет содержать строку с идентификаторами, среди которых «uid» (user id) будет содержать требуемое имя.
passwd
ipconfig
sshd
Всё готово для подключения по SSH. Мы знаем IP адрес смартфона, у нас есть имя пользователя и пароль, единственное порт для подключения стоит использовать 8022, так как именно его используется OpenSSH в termux по умолчанию.
Если с компьютера подключиться к смартфону по SSH не удаётся, то можно попробовать следующие варианты:
pkill sshd
sshd
Одной из возможных причин недоступности SSH в termux может быть установка на смартфоне брандмауэра, блокирующего любые входящие подключения. В данном случае необходимо развернуть на компьютере SSH сервер, со смартфона подключится к нему SSH клиентом с проброской портов, а затем с компьютера SSH клиентом подключится в проброшенный порт.
При сохранении проблем попробуйте поискать ответы в официальном руководстве [5] termux по настройке удалённого доступа.
Первый раз, набрав команду «su», в termux сработает оповещение от Magisk, которое запросит вашего одобрения наделения (grant) приложения termux root доступом. Необходимо согласиться.
Если очень упростить, то можно сказать, что операционная система Android – это слоёный пирог [6] (Рис. 2), где всю низкоуровневую работу выполняет Linux, а приложения работают в виртуальной машине Android runtime [7].

Рис. 2
Приложения бывают обычные, привилегированные (системные) и разработанные поставщиком устройства (Device manufacturer apps). Перенастройка USB-порта недоступна обычным приложениям, а повышение уровня доступа до привилегированного сопряжено с определёнными сложностями [8].
Но есть другой вариант. Дело в том, что в виртуальной машине Android runtime существует API, позволяющий выполнять Linux-команды, а уже с их помощью можно сделать практически всё что угодно. Ограничением будут лишь полномочия пользователя, под которым работает приложение, и механизмы разграничения доступа самого Linux (например, SELinux).
Процедура перенастройки USB-интерфейса с помощью вызова Linux-команд является привилегированной и недоступна для обычного приложения, требуется root-доступ. Несмотря на то что мы ранее получили root, это вовсе не значит, что все наши приложения стали запускаться из-под пользователя root. Они всё так же запускаются из-под ограниченной учётной записи, и то, чего нельзя было делать ранее (до получения root), нельзя делать и сейчас. Единственным важным отличием стало то, что теперь (после получения root) есть возможность выполнить команду «su», которая запускает привилегированную командную оболочку (shell), где как раз и можно выполнить все необходимые нам действия.
Всякий раз, когда требуется выполнить команду или скрипт из-под учётной записи root это означает, что предварительно нужно повысить полномочия с помощью команды «su», а потом выполнять требуемые действия.
В терминах Linux-ядра смартфон, оснащённый настраиваемым USB-контроллером, называется Linux USB Gadget [9]. Виртуальная файловая система configfs [10] — наиболее удобный способ его конфигурирования.
Смартфоны бывают разные, и в некоторых из них, например, в старых моделях подобного функционала может и не быть. Для того чтобы удостовериться, что ваш смартфон позволяет настраивать 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 (клавиатура, мышь).
Определить точку монтирования 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-порта имеет ряд особенностей:
Перед тем как приступить к конфигурированию USB-порта, нам потребуется разобраться с принципами функционирования USB-устройств. Первое, на чём хочется заострить внимание, это то, что наша идея превратить смартфон одновременно в клавиатуру, мышь и флешку не является чем-то экстраординарным. Никого ведь не смущают МФУ, совмещающие в себе одновременно фикции принтера, сканера и факса. Подобные USB-устройства, обладающие множеством функций, в терминах USB, называются композитными. Кстати, множество игровых мышек также являются композитными устройствами, сочетающими в себе функции мышки и клавиатуры (Рис. 3). Поэтому наш гибрид – вполне заурядная вещь в мире USB.

Рис. 3
Поскольку к USB-шине может быть подключено множество самых разных устройств, компьютер (USB-хост) должен понимать, что к нему подключилось и как с этим работать. Для этого USB-устройство обменивается с компьютером набором дескрипторов:
Таким образом, конфигурирование USB-порта с помощью configfs сводится к тому, чтобы предоставить Linux-ядру необходимую информацию, на базе которой оно сформирует требуемый набор дескрипторов.
Настало время разобраться со структурой configfs в части конфигурирования USB-порта. Для этого создадим в каталоге /config/usb_gadget/ новый профиль устройства и назовём его «xxx»:
mkdir /config/usb_gadget/xxx
Сразу после выполнения этой команды в каталоге «/config/usb_gadget/xxx» была создана следующая файловая структура:
| Файл или каталог | Описание |
| UDC | Файл, указывающий на активность профиля. Если файл пуст, то профиль не активен, если нет, то в нём указывается имя драйвера устройства, ассоциированного с этим профилем. Для отключения профиля используется команда:
Для активации профиля:
|
| Параметры, используемые для формирования дескриптора устройства | |
| bDeviceClass | Файлы, содержащие шестнадцатеричные коды USB-устройств. Перечень возможных кодов приведён на сайте USB-IF [11] |
| 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». В наших экспериментах она использоваться не будет. По умолчанию функция отключена. |
Описание функций мышки и клавиатуры имеют одинаковую структуру, различающуюся содержимым.
| Файл | Описание |
| protocol | Номер протокола: 1 – клавиатура, 2 – мышь |
| subclass | Номер подкласса. В нашем случае всегда будет 1, указывающий, что это подкласс Boot Interface. Другими словами, создаваемая нами клавиатура и мышь будут совместимы даже с BIOS. |
| report_length | Длина отчёта о состоянии устройства. Определяется дескриптором отчёта HID устройства. В нашем случае: 8 – клавиатура, 4 – мышь. |
| report_desc | Двоичный код дескрипторов отчёта HID-устройств. Далее рассмотрим их более подробно. |
В наших экспериментах мы используем дескрипторы отчётов HID-устройств, которые кочуют по различным open-source проектам, но тем не менее показали себя вполне работоспособными.
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] [12].Appendix E: Example USB Descriptors for HID Class Devices для работы с Android не подошли.
Если вам захочется поэкспериментировать с дескрипторами отчёта, то можете воспользоваться официальной утилитой [13] от USB-IF, либо онлайн-парсером [14] от Frank Zhao.
В отличие от клавиатуры и мыши, каталог, описывающий функцию флешки, имеет совершенно другую структуру
| Файл | Описание |
| 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 – нет. |
После того как в активном профиле USB-порта активированы функции клавиатуры и мыши, в системе появятся два новых устройства /dev/hidg0 и /dev/hidg1. Первое соответствует клавиатуре, а второе — мыши. Посылая отчёты в эти устройства, мы можем имитировать нажатия кнопок на клавиатуре или движения мыши.
Отключение функций клавиатуры или мышки в активном 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"
Следующий скрипт позволяет получить информацию об имеющихся профилях, включая полный перечень доступных функций и список активных функций в профиле.
#!/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-профилю.
#!/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
Это скрипт антагонист предыдущему. Он отключает (но не удаляет) ранее созданные функции в системном профиле.
#!/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-клавиатура при изменении своего состояния (нажатии или отпуске клавиши) посылает отчёт следующего формата ([1] [12].B.1 Protocol 1 (Keyboard)):
| Байт | Назначение |
| 0 | Модификатор |
| 1 | Резерв |
| 2 | Код клавиши 1 |
| 3 | Код клавиши 2 |
| 4 | Код клавиши 3 |
| 5 | Код клавиши 4 |
| 6 | Код клавиши 5 |
| 7 | Код клавиши 6 |
Модификаторы, хранящиеся в Байте 0 отчёта, имеют формат ([1] [12].8.3 Report Format for Array Items):
| Бит | Назначение |
| 0 | LEFT CTRL |
| 1 | LEFT SHIFT |
| 2 | LEFT ALT |
| 3 | LEFT GUI |
| 4 | RIGHT CTRL |
| 5 | RIGHT SHIFT |
| 6 | RIGHT ALT |
| 7 | RIGHT GUI |
В байтах (2-7) указываются коды нажатых клавиш, которые определены в спецификации [2] [12].Keyboard/Keypad Page (0x07). Из-за большого объёма данных коды всех клавиш приводить здесь не будем, ограничимся лишь фрагментом (Рис. 4), необходимым для понимания принципа работы.

Рис. 4
Сама спецификация в открытом доступе, так что вы легко сможете её найти. Кроме официальной спецификации, можете посмотреть GitHub-репозиторий tmk_keyboard [15], содержащий визуальную карту кодов кнопок. На первых этапах он, наверное, будет более понятным.
Со справочной информацией покончено, перейдём к анализу принципа работы. Как вы скорее всего уже заметили, USB-клавиатура может обрабатывать одновременно нажатие 6 клавиш, а с учётом клавиш модификаторов это количество увеличивается до 14. В этой связи протокол её работы ([1] [12].Appendix C: Keyboard Implementation) имеет определённую специфику: передаются только изменения состояния клавиатуры. Другими словами, если пользователь нажал кнопку, изменение произошло, если удерживает, то ничего не меняется, если отпустил, то опять изменение.
Чтобы с этим разобраться рассмотрим ряд примеров:
Закончим с клавиатурой, рассмотрев скрипт, вызывающий блокнот и печатающий в нём «Hello World!!».
#!/system/bin/sh
# print_hello_world.sh
echo "x08x00x15x00x00x00x00x00" > /dev/hidg0 # press Win+R
sleep 1s # wait until window apears
echo "x00x00x00x00x00x00x00x00" > /dev/hidg0 # release key
echo "x00x00x11x00x00x00x00x00" > /dev/hidg0 # press n
echo "x00x00x12x00x00x00x00x00" > /dev/hidg0 # press o
echo "x00x00x17x00x00x00x00x00" > /dev/hidg0 # press t
echo "x00x00x08x00x00x00x00x00" > /dev/hidg0 # press e
echo "x00x00x13x00x00x00x00x00" > /dev/hidg0 # press p
echo "x00x00x04x00x00x00x00x00" > /dev/hidg0 # press a
echo "x00x00x07x00x00x00x00x00" > /dev/hidg0 # press d
echo "x00x00x37x00x00x00x00x00" > /dev/hidg0 # press .
echo "x00x00x08x00x00x00x00x00" > /dev/hidg0 # press e
echo "x00x00x1Bx00x00x00x00x00" > /dev/hidg0 # press x
echo "x00x00x08x00x00x00x00x00" > /dev/hidg0 # press e
echo "x00x00x28x00x00x00x00x00" > /dev/hidg0 # press Enter
echo "x00x00x00x00x00x00x00x00" > /dev/hidg0 # release key
sleep 3s # wait until window apears
echo "x02x00x0Bx00x00x00x00x00" > /dev/hidg0 # press H
echo "x00x00x08x00x00x00x00x00" > /dev/hidg0 # press e
echo "x00x00x0Fx00x00x00x00x00" > /dev/hidg0 # press l
echo "x00x00x0Fx00x00x00x00x00" > /dev/hidg0 # press l
echo "x00x00x12x00x00x00x00x00" > /dev/hidg0 # press o
echo "x00x00x2Cx00x00x00x00x00" > /dev/hidg0 # press Space
echo "x02x00x1Ax00x00x00x00x00" > /dev/hidg0 # press W
echo "x00x00x12x00x00x00x00x00" > /dev/hidg0 # press o
echo "x00x00x15x00x00x00x00x00" > /dev/hidg0 # press r
echo "x00x00x0Fx00x00x00x00x00" > /dev/hidg0 # press l
echo "x00x00x07x00x00x00x00x00" > /dev/hidg0 # press d
echo "x02x00x1Ex00x00x00x00x00" > /dev/hidg0 # press !
echo "x00x00x00x00x00x00x00x00" > /dev/hidg0 # release key
Человек, когда работает за компьютером, видит результаты своей работы, а скрипт, генерирующий нажатия клавиш – нет, это порождает ряд проблем:
Мышь, как и клавиатура, на каждое изменение своего состояния посылает отчёт. Формат отчёта определён в спецификации [1] [12].B.2 Protocol 2 (Mouse). После экспериментов над Android, превращённым в мышь, спецификацию отчёта пришлось дополнить, и в итоге она стала выглядеть так:
| Байт | Описание |
| 0 | Состояние кнопок |
| 1 | Перемещение по X («+» – влево, «-» – вправо) |
| 2 | Перемещение по Y («+» – вверх, «-» – вниз) |
| 3 | Колёсико («+» – вверх, «-» – вниз) |
Байты 1-3 могут принимать значения от -127 до 127. Значения кодируются дополнительным кодом, где 00 hex = 0 dec, 01 hex = 1 dec, 7F hex = 127, 81 hex = -127 dec, FF hex = -1 dec, 80 hex – игнорируется. Байт состояния кнопок мыши расшифровывается так (1 – означает нажатие кнопки, 0 – отпуск):
| Бит | Описание |
| 0 | Левая кнопка |
| 1 | Правая кнопка |
| 2 | Средняя кнопка |
| 3 | Навигация назад |
| 4 | Навигация вперёд |
| 5-7 | Неопределенно |
Фактическое перемещение курсора мыши осуществляется операционной системой в зависимости от текущего положения курсора и значений изменения координат, полученных из USB-отчёта от мыши (Рис. 5).

Рис. 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 мышкой не всё так просто. Есть ряд нюансов, которые необходимо учитывать:
#!/system/bin/sh
# mouse_draw_rect.sh
echo "x01x00x00x00" > /dev/hidg1 # Press LMB
echo "x01x7Fx00x00" > /dev/hidg1 # Move MAX Right
echo "x01x01x00x00" > /dev/hidg1 # Move MIN Right
echo "x01x00x00x00" > /dev/hidg1 # Press LMB
echo "x01x00x7Fx00" > /dev/hidg1 # Move MAX Down
echo "x01x00x01x00" > /dev/hidg1 # Move MIN Down
echo "x01x00x00x00" > /dev/hidg1 # Press LMB
echo "x01x81x00x00" > /dev/hidg1 # Move MAX Left
echo "x01xFFx00x00" > /dev/hidg1 # Move MIN Left
echo "x01x00x00x00" > /dev/hidg1 # Press LMB
echo "x01x00x81x00" > /dev/hidg1 # Move MAX Up
echo "x01x00xFFx00" > /dev/hidg1 # Move MIN Up
echo "x00x00x00x00" > /dev/hidg1 # Release LMB
Здесь сначала нажимается левая кнопка мыши, затем курсор с зажатой кнопкой двигается вправо, затем вниз, потом вверх, где и отпускается кнопка. При этом между изменениями движения курсора вставлен отчёт, который просто удерживает нажатой левую кнопку мыши. Если этого не делать, то в некоторых случаях вместо ожидаемого квадрата на экране можно увидеть треугольник.
Рассмотрим ряд признаков, которые позволят отличить управление клавиатурой и мышью реальным человеком от управления этими же устройствами ботом, использующим Android как средство ввода.
Поведенческие признаки:
Аппаратные признаки:
В этой статье повсеместно используются скрипты, и у вас может сложиться мнение, что, кроме как из termux, взаимодействовать с виртуальной клавиатурой и мышью никак нельзя, но это не так. Как уже отмечалось в начале статьи, из родного API Andoird можно выполнять Linux команды. Для наших целей нужно выполнить команду «su», что приведёт к формированию оболочки. Затем, используя перенаправление потоков ввода-вывода, ей можно подавать на вход любые другие команды, включая скрипты, и получать результаты их выполнения. Поэтому вы можете смело брать написанный здесь код и выполнять его из своего приложения. Пример того как работать с «su» в Android, вы можете найти в этой статье [16].
Все скрипты, приведённые в этой статье, являются свободным ПО и могут использоваться без каких-либо ограничений.
Мы научились нажимать смартфоном кнопки клавиатуры, шевелить курсором мыши и получили новую флешку, что с этим всем делать? А применений нашему комбайну на самом деле очень много:
В ходе исследования очень помогли инструменты:
Автор: imbasoft
Источник [21]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/usb/391841
Ссылки в тексте:
[1] termux: https://termux.dev/en/
[2] TWRP: https://twrp.me/
[3] Magisk: https://github.com/topjohnwu/Magisk
[4] F-Droid: https://f-droid.org/packages/com.termux/
[5] официальном руководстве: https://wiki.termux.com/wiki/Remote_Access
[6] слоёный пирог: https://source.android.com/docs/core/architecture?hl=en
[7] Android runtime: https://source.android.com/docs/core/runtime?hl=en
[8] сложностями: https://xakep.ru/2016/04/20/android-api/
[9] Linux USB Gadget: https://www.kernel.org/doc/Documentation/usb/gadget_configfs.txt
[10] configfs: https://docs.kernel.org/filesystems/configfs.html
[11] USB-IF: https://www.usb.org/defined-class-codes
[12] [1]: #Liter
[13] утилитой: https://usb.org/sites/default/files/documents/dt2_4.zip
[14] онлайн-парсером: https://eleccelerator.com/usbdescreqparser/
[15] GitHub-репозиторий tmk_keyboard: https://github.com/tmk/tmk_keyboard/wiki/USB:-HID-Usage-Table
[16] статье: https://muzikant-android.blogspot.com/2011/02/how-to-get-root-access-and-execute.html
[17] Wireshark с модулем USBCap: https://www.wireshark.org/download.html
[18] Python библиотека hid-tools: https://pypi.org/project/hid-tools/
[19] Universal Serial Bus (USB) Device Class Definition for Human Interface Devices (HID) Firmware Specification—5/27/01 Version 1.11: https://usb.org/sites/default/files/hid1_11.pdf
[20] HID Usage Tables FOR Universal Serial Bus (USB) Version 1.5: https://usb.org/sites/default/files/hut1_5.pdf
[21] Источник: https://habr.com/ru/companies/ruvds/articles/816595/?utm_source=habrahabr&utm_medium=rss&utm_campaign=816595
Нажмите здесь для печати.