История покупки

Я понял, что играть на телевизоре гораздо веселее и привычнее, например, для жены, а ещё ждал гостей, которые собирались заглянуть ко мне на неделю-другую летом.

Мой Яндекс ТВ едва дружил с Bluetooth. Я с трудом поставил на него Steam Link, но телевизор совсем не хотел тянуть поток больше 30 Мбит/с. Камушек там оказался довольно дохлым: смотреть MKV в устраивающем меня качестве получалось, а вот со стримингом Steam он справлялся плохо.

Менять телевизор не улыбалось, поэтому я стал смотреть в сторону приставок. Долго ли, коротко ли, я набрёл на H96Max: разные ревизии, варианты с 4 и 8 гигабайтами ОЗУ, гигабитный Ethernet. Судя по отзывам, всё работало шустро, а гигабит был вполне честный. Долго читал отзывы на маркетплейсах. Было ощущение, что это лотерея, но я решил рискнуть. Приставки с приятным лейблом на корпусе стоили уже совсем негуманно, а тут выигрыш в цене обещал быть в 2–2,5 раза.

Судя по количеству продаж на маркетплейсах, приставка понравилась не только мне.

Что мне в итоге досталось

Приехала коробочка, которую я сразу запустил. Первый smoke test в Steam Link показал 300 Мбит/с от источника к приставке. Я был счастлив: задуманное удалось.

Заявленные характеристики и результаты моей проверки

Заявленные параметры я нашёл в карточке H96 Max M9S на сайте производителя и подробной спецификации H96 Max. Сведения о самом процессоре сверил с краткой спецификацией Rockchip RK3576. Ниже отдельно указал обещания производителя, данные моего экземпляра и границы проверки. Чтение системной информации и успешный запуск приложения не заменяют нагрузочного испытания оборудования.

Компонент

Заявлено производителем

Что я подтвердил на своём экземпляре

Что я не проверял или не установил

SoC и CPU

Rockchip RK3576: 4 × Cortex-A72 + 4 × Cortex-A53

RK3576 в свойствах системы; восемь ядер и соответствующие идентификаторы ARM в /proc/cpuinfo

Максимальные частоты, производительность под длительной нагрузкой и троттлинг

GPU

ARM Mali-G52 MC3; у Rockchip — OpenGL ES до 3.2, OpenCL 2.1, Vulkan 1.2

Наличие драйвера Mali в прошивке и работу графического интерфейса

Отдельные GPU-бенчмарки и соответствие драйвера всем заявленным API

NPU и обработка изображения

6 TOPS INT8 с оговоркой Rockchip о разреженности; AI VisionPQ и масштабирование видео до 4K

Наличие компонентов PQ в прошивке

Реальную работу NPU, скорость нейросетей и качество AI-обработки изображения

ОЗУ

DDR4, варианты 4 или 8 ГБ

В моём варианте на 8 ГБ ядро видит около 7,73 ГиБ

Тип и производителя микросхем, пропускную способность и полный тест памяти; обозначение DDR4 оставляю как заявление H96

Накопитель

eMMC, варианты 32, 64 или 128 ГБ

Вариант на 128 ГБ; размер блочного устройства — около 125,1 млрд байт, или 116,5 ГиБ, до вычета разделов и файловых систем

Маркировку и версию eMMC, скорость, износ и проверку всей ёмкости записью с последующим чтением

Ethernet

RJ-45, 1000 Мбит/с

Работу проводной сети и тест Steam Link на 300 Мбит/с

Согласованную скорость линка, предельную пропускную способность и модель PHY

Wi-Fi

Wi-Fi 6, диапазоны 2,4 и 5 ГГц

Наличие интерфейса wlan0 в системе

Соединение в режиме 802.11ax, скорость, дальность, оба диапазона и модель радиомодуля

Bluetooth

Bluetooth 5.4

Работу и повторное подключение Bluetooth-контроллера после доработок и перезагрузок

Соответствие именно версии 5.4, все профили Bluetooth и маркировку чипа

HDMI и дисплей

HDMI 2.1; в подробной таблице — до 4K при 120 Гц, CEC и ARC; в краткой — 4K при 60 Гц, HDR10/HLG

Изображение 1920×1080 при 60 Гц, возврат изображения после сна

4K при 60/120 Гц, HDR, CEC, ARC и соответствие интерфейса возможностям HDMI 2.1

Декодирование видео

H.264, H.265, VP9, AV1, AVS2; реклама 8K, подробные оговорки ниже

В конфигурации Rockchip Codec2 зарегистрированы H.264, H.265, VP9 и AV1; Steam Link и привычное видео в VLC работают

Каждый кодек и профиль отдельно, AVS2, аппаратный путь для каждого файла и режимы 4K/8K

Кодирование видео

H.264/H.265 до 4K при 60 кадрах/с

Наличие соответствующих энкодеров в конфигурации Codec2

Их фактическую работу и предельную производительность; просмотр Steam-трансляции этого не проверяет

USB

Один USB 3.0 и один USB 2.0

Поддержку USB в системе

Физическое соответствие разъёмов спецификации, режим SuperSpeed, скорость накопителей и допустимый ток

Звук

S/PDIF и отдельный Audio Out; MP3, AAC, WMA, RM, FLAC

Звук в проверенных сценариях Steam Link и VLC

S/PDIF, Audio Out, passthrough, многоканальный звук и все перечисленные форматы по отдельности

Пульт

Пульт 2,4 ГГц/Bluetooth, поддержка голосового управления

Обычное управление, сон и пробуждение штатным пультом

Голосовой ввод и работу всех режимов связи комплектного пульта

Питание и корпус

Блок питания 5 В / 2 А; корпус 96 × 138 × 23,6 мм

Работу приставки в моих повседневных сценариях

Маркировку и электрические параметры блока питания, энергопотребление, размеры и физическую ревизию платы

ОС

Android 14

Android 14 / API 34, ARM64 и запуск 32- и 64-битных приложений при проверке WebView

Полное соответствие требованиям Android, сертификацию Google и DRM-возможности

С заявленными режимами видео есть нестыковки. В разных частях подробной карточки H96 указаны 8K при 24 и 30 кадрах/с, а для HDMI — 4K при 60 и 120 Гц. В текущей краткой спецификации Rockchip для H.265, VP9 и AV1 указан предел 4K при 120 кадрах/с, для H.264 — 4K при 60 кадрах/с. Заявление об 8K эта спецификация не подтверждает; на своей приставке я его не проверял. Декодирование файла и режим вывода HDMI — отдельные возможности, поэтому смешивать их в одну «максимальную разрешающую способность» не стал. Спецификация H96, спецификация Rockchip.

Есть оговорка и по памяти: H96 пишет DDR4, а Rockchip перечисляет LPDDR4, LPDDR4X и LPDDR5. Это разные обозначения; без идентификации установленных микросхем я не выдаю рекламную строку за установленный тип памяти. Точные модели Wi-Fi/Bluetooth, Ethernet PHY, памяти и накопителя, как и ревизию платы, по собранным данным я не установил. Наличие в образе прошивок для нескольких радиочипов не говорит, какой из них распаян в моей коробке. Карточка H96, спецификация Rockchip.

Что установлено о моей прошивке

Это уже данные с приставки, а не рекламные характеристики:

  • Сборка: RZX.V01.20250926.1112, тип userdebug; основная архитектура arm64-v8a, также заявлены armeabi-v7a и armeabi.

  • Ядро: Linux 6.1.75, сборка от 26 сентября 2025 года.

  • Уровень исправлений безопасности Android: 5 февраля 2024 года. Дата сборки прошивки заметно новее заявленной даты патчей.

  • Загрузочные компоненты: в свойствах указаны DDR v1.05-da1087e33f, SPL v1.05, BL31 v1.09, BL32 v1.02, U-Boot 31221-dirt-09/26/2025. Это прочитанные идентификаторы; содержимое всей загрузочной цепочки я независимо не проверял.

Получился не ванильный Android TV, а OEM-сборка с телевизионным интерфейсом, собственными службами и заводскими утилитами. Название на корпусе не гарантирует одинаковую начинку у разных партий.

Всё это обошлось в 16 617 рублей по курсу местной валюты расчёта, с доставкой послезавтра. Если бы согласился подождать дней 20–30, было бы около 9000 рублей. Это цена моей покупки, а не актуальный прайс.

Что случилось потом

В процессе ежедневного поиска новостей мне попался материал об этих приставках, о чём я уже писал в Security: «Китайские Android TV-приставки H96 использовали для накрутки рекламы и в качестве домашних прокси».

Я выключил приставку из розетки и отложил проблему в долгий ящик: мне не было известно, что внутри моего экземпляра и насколько всё плохо. Позже попался текст о разработчике, который с помощью Claude Code отключил лишние приложения на Android TV и ускорил интерфейс без root-доступа.

Забрезжила надежда если не решить проблему, то весело провести время.

Итак, я взял Codex с моделью GPT-6 Astra и начал задавать вопросы о прошивках Android TV, конкретно этой модели и всём, что теоретически касается моего устройства. Потом я перешёл от разговоров к инвентаризации и проверкам.

Условия были вполне приземлёнными: должны сохраниться обычный пульт, Bluetooth-контроллер, Steam Remote Play с изображением, звуком и управлением, VLC с видео из локальной сети, сон и пробуждение. Cast и сетевой пульт мне не нужны. Исходящие соединения я решил оставить разрешёнными, а вход для администрирования — сделать по SSH с аппаратным ключом.

Сначала я ничего не менял. Сохранил конфигурацию, списки пакетов, процессов, сокетов и служб, выгрузил APK и выбранные системные файлы. В инвентаризации оказалось 111 приложений; собрал 178 APK, включая split-пакеты и overlay. Подробно разбирал 17 выбранных OEM-приложений, исследовал выбранные скрипты и нативные компоненты. Это объём конкретного аудита, а не обещание, что каждый байт прошивки получил экспертную оценку. Ниже — результаты проверок и доработок моего экземпляра.

Список уязвимостей и слабых мест моей H96Max M9S

Вот что всплыло до внесения изменений. Здесь есть подтверждённые проблемы, опасные функции и просто ненужные сетевые службы — степень проверки у них разная.

  • ADB по сети без подтверждения ключа. Порт TCP 5555 слушал сетевые интерфейсы, а заводской сценарий включал его при загрузке. Проверка с новым клиентом показала переход к соединению без этапа ADB AUTH. Отдельно я подтвердил, что из полученной оболочки можно стать root. Для устройства, доступного в локальной сети, это была самая неприятная находка. Доступность этого порта из Интернета я не установил.

  • Слишком доступный su. /system/xbin/su принадлежал root:shell и имел права 6755. В исследованном бинарнике я не нашёл собственной проверки UID вызывающего процесса. Переход shell → root подтвердил; возможность такого же перехода из любого обычного APK не доказывал: там имеют значение дополнительные ограничения запуска.

  • SELinux в Permissive. Запреты политики записывались в журнал, но не блокировали операции. Это не отменяет обычные Unix-права, однако убирает важный слой изоляции Android. У ряда проверенных процессов, включая Zygote, system_server и Steam, также отсутствовал активный seccomp-фильтр.

  • Несколько механизмов автоматической установки APK. Нашлись com.www.intallapp, заводской com.rockchip.devicetest и отдельный root-скрипт preinstall.sh. В двух ветках обработки пути к APK подставлялись в shell-команды без корректного экранирования. Это основание подозревать инъекцию через специально подготовленное имя файла; эксплуатацию с таким носителем я не проводил. Наличие отдельного root-сценария означало, что одного отключения приложения недостаточно.

  • Заводские операции с непредсказуемыми последствиями. В прошивке нашёл компонент перезагрузки, доступный другим приложениям без специального разрешения, и тестовые сценарии USB/SD, в которых предусмотрен сброс данных. Отдельно обнаружил службу flash_img: она запускает dd с правами root, получая параметры из системных свойств. Эти механизмы создают дополнительные возможности для локального вмешательства в работу приставки. Возможность произвольной перепрошивки через Интернет в ходе аудита не подтверждена.

  • Небезопасное автоматическое Bluetooth-сопряжение. Привилегированный помощник com.hcy.firstbt узнавал пульт по части имени, автоматически подтверждал сопряжение и использовал PIN 0000. Здесь нужен доступ по радио и подходящий сценарий сопряжения. Делать вывод о постоянно открытом Bluetooth из этого кода нельзя, но такой помощник мне точно не нужен.

  • Старые WebView и Chrome. Единственным разрешённым поставщиком WebView был пакет версии 116.0.5845.195; Chrome — 122.0.6261.90. WebView исполняет веб-содержимое внутри приложений, поэтому его возраст имеет значение даже без привычки открывать браузер на телевизоре.

  • Устаревшая и отладочная системная база. Android сообщал уровень патчей февраля 2024 года при сборке осенью 2025-го. Обнаружились userdebug и признаки разблокированного устройства. Fingerprint при этом изображал Pixel 5 с Android 13, хотя реальные API и плата были другими. Это подмена идентичности сборки, но сама по себе она не доказывает наличие ботнета. Перечень применимых CVE по одной строке версии ядра тоже достоверно не составить.

  • Слабые места в OTA-клиентах. В RKOTA я нашёл HTTP для метаданных обновления, в коде Abupdate — проблемную проверку имени TLS-сервера и путь работы с MQTT без TLS. Активное использование MQTT в наблюдаемом состоянии не подтвердилось. При этом в коде присутствовала проверка подписи ZIP через verifyPackage, поэтому утверждать, что приставка примет любую неподписанную прошивку, было бы неверно.

  • Избыточные права на устройства и каталоги. /dev/teepriv0 и /dev/tee0 имели режим 0666; ряд каталогов настройки изображения и графического кэша — 0777. Это расширяет круг процессов, способных обращаться к таким объектам. Извлечение ключей из TEE или выполнение кода через кэш я не демонстрировал.

  • Неиспользуемый отладочный сервер. В образе лежал rkpq_tool_server, способный при запуске слушать TCP 5543 без аутентификации. Во время проверки он не работал, автозапуск я не нашёл. Его присутствие и фактически открытый порт — разные вещи, но оставлять доступную ненужную утилиту незачем.

  • Лишние входящие соединения. Cast и управление с телефона открывали, среди прочего, TCP 8008, 8009, 8443, 9000, 6466 и 6467, а также динамические порты. Сам открытый порт не является доказательством уязвимости. Но пользоваться этими функциями я не собирался, а доступных по сети компонентов они добавляли немало.

Отдельно я искал известные индикаторы Vo1d, BADBOX и Fuyao: характерные имена и пути, выбранные домены и хеши. В собранных материалах совпадений не нашёл. Подозрительные на первый взгляд штатные компоненты тоже проверял, а не объявлял троянами по названию.

Это обнадёживает, но фразу «приставка не была заражена из коробки» такой результат не обосновывает. У меня не было независимо доверенного эталона всей прошивки; я не исследовал полностью загрузчик, TEE и весь нативный код и не вёл длительную внешнюю запись трафика. Корректный результат: в пределах проведённых проверок признаков известных исследованных вредоносов не обнаружено. Найденных слабых настроек и без трояна хватало.

Чего в итоге удалось добиться

Прошивку целиком я не заменял. Уменьшил доступность опасных функций, обновил один важный компонент и включил уже имеющуюся защиту. Изменения сопровождал резервными копиями, временными пробами и таймерами отката; после перезагрузок проверял, что результат сохраняется.

  • SSH на порту 22, вход только по ключу. Установил Dropbear 2026.94 для Android ARM64. Парольная аутентификация и PAM исключены из сборки, прямой вход root запрещён. Вход выполняется под shell с моим аппаратным ключом OnlyKey формата sk-ssh-ed25519@openssh.com; для обслуживания после входа доступен su 0. Ограничение адресом в firewall здесь не заменяет секрет: сервер действительно требует подпись ключом.

  • Прямой сетевой ADB отключён. Остановил adbd, убрал заводское включение TCP 5555 и закрепил отключение при загрузке. Дополнительно включил ro.adb.secure=1 и проверил наличие поддержки аутентификации в бинарнике. Основной проверенный результат — ADB после перезагрузки не слушает сеть. Отдельный повторный сетевой тест AUTH с запущенным демоном в финальную проверку не входил.

  • Firewall для IPv4 и IPv6. Разрешил новый входящий SSH, ответы на исходящие соединения и необходимый служебный обмен, включая DHCP и нужные ICMP-сообщения. Остальные новые входящие соединения блокируются, исходящие разрешены. Steam Link в моём сценарии работает как клиент: открывать на приставке широкий диапазон входящих «портов Steam» не понадобилось. Новую трансляцию со звуком и управлением я проверял несколько раз; VLC с локальной сетью тоже работает. При финальных TCP-проверках доступен только порт 22. Для UDP результат сканера open|filtered сам по себе не доказывает ни открытый, ни закрытый порт.

  • Отключил ненужные пакеты и заводские сценарии. Убрал из работы Cast, управление с телефона, установщики, заводские тесты, проблемные OTA-клиенты, старый Chrome и ненужный магазин Aptoide. Отключение пакетов обратимо, APK и данные сохранены. Root-автоустановку и запуск flash_img нейтрализовал отдельно от Android-пакетов, чтобы не оставить второй путь к тем же операциям.

  • Сохранил Bluetooth без заводского автоподтверждения. Отключил помощник com.hcy.firstbt, сохранив сам Bluetooth-стек. Переподключение контроллера проверял после изменений и перезагрузок.

  • Сузил доступ к root и служебным объектам. Для su установил 4750 root:shell; проверочный UID без нужной группы больше не мог его запустить. Сам бинарник не менял. /dev/teepriv0 получил 0600, отладочный PQ-сервер — 0700, выбранные графические каталоги — 2775 system:audio с ограничением прав файлов. Убрал возвращавшие этим каталогам 0777 заводские команды и включил dmesg_restrict=1. Публичный /dev/tee0 сохранил; произвольно закрывать все устройства без проверки пользователей я не стал.

  • Обновил WebView отдельно от Android. Установил официальный Google WebView 153.0.8010.36 из Google Play с проверкой подписи. Заводской список разрешённых поставщиков расширил небольшим ресурсным overlay, указав нужный пакет и сертификат. Проверку подписи не отключал. Старый WebView оставил как резервный поставщик. Проверил фактический выбор новой версии и работу 32- и 64-битных тестовых приложений: DOM, JavaScript, Canvas и HTTPS с обычной проверкой TLS. Возможность будущих автоматических обновлений ещё предстоит подтвердить на следующем выпуске.

  • Перевёл SELinux в Enforcing до запуска приложений. Начал с AVC-журнала и выяснил, какие отказы связаны с неверными метками объектов. Исправил метки двух графических библиотек и конкретных sysfs-узлов пробуждения и extcon. Новых allow, dontaudit и permissive-доменов не добавлял; бинарная политика осталась прежней. Enforcing включается на стадии post-fs-data, до Zygote. Поздний setenforce 1 после старта приложений давал менее полный результат.

  • Проверил изоляцию новых процессов. После раннего включения Enforcing у проверенных процессов Bluetooth, Steam, VLC и WebView стал активен seccomp (Seccomp: 2). Я не ограничился выводом getenforce: заново запускал приложения, проверял журналы и реальные сценарии. Сон и пробуждение тоже прошли проверку.

  • Вернул правильное поведение фронтального LED без расширения SELinux-политики. После включения Enforcing старый OEM-путь управления индикатором из system_server перестал работать: цвет во сне и при работе не менялся. Перенёс управление в существующий Lights HAL через Binder, исправив небольшие участки framework и HAL. Отдельного постоянно работающего демона не добавлял. Первая проба выявила конфликт с Google Assistant: внутренний индикатор попадал в публичный список ламп. В итоговом варианте я это исправил и повторил проверки. Два изменённых файла подключаются при загрузке через bind mount; оригиналы этих файлов в разделах сохранены.

  • Закрепил и проверил загрузку. SSH, firewall, отключение ADB, ранний Enforcing, WebView и исправление LED пережили перезагрузки. После проб я подтвердил обычный пульт, два цикла сна с переключением индикатора, Bluetooth-контроллер, новую Steam-трансляцию и сетевое видео в VLC. Пробные таймеры я снял после успешных проверок; заключительная загрузка подтвердила постоянный профиль, доступ по SSH и сохранение защиты.

Для меня самым интересным оказался SELinux: вовсе не потребовалось скармливать весь AVC-журнал в генератор разрешений. Часть отказов исчезла после исправления меток, а для LED удалось использовать предназначенную для работы с оборудованием службу. Запрещённая операция не всегда означает, что её нужно разрешить прежнему вызывающему процессу.

Что осталось нерешённым

Сказать «исправил всё» было бы слишком смело:

  • Ядро, vendor-компоненты, загрузчик и TEE не стали новыми. WebView обновлён, но это не обновление всей платформы и не новый уровень исправлений Android. Старые версии и закрытые компоненты остаются основным ограничением.

  • Полноценную замену прошивки с проверкой именно моей платы я не нашёл. Рассматривал альтернативы, но уверенного сочетания Bluetooth, аппаратного видео, Steam, пульта и восстановления после неудачной прошивки не получил. Вариант без Bluetooth для меня не подходит. Это не утверждение, что новое ядро вообще не умеет Bluetooth: нужны подходящие драйверы, firmware и описание конкретной платы. Замена только system через GSI также не обновляет весь vendor и загрузочную цепочку.

  • Заводская модель доверия осталась ослабленной. Устройство по-прежнему userdebug и не превращено в платформу с доверенной заблокированной загрузкой. Доступ через группу shell к root сохранён намеренно. Права на su ограничили круг вызывающих процессов, но не добавили проверку личности внутрь самого бинарника.

  • Enforcing имеет оговорки. Он включается на post-fs-data, а не с первой инструкции ядра. В исходной политике остался permissive-домен su; новых исключений я не добавлял. При непрохождении защитных проверок загрузочного сценария предусмотрен возврат к Permissive ради восстановления. Поэтому одна строка Enforcing не означает, что все домены и все стадии загрузки одинаково защищены.

  • Некоторые избыточные DAC-права остались. Например, штатная логика позднее возвращает LED-узлам режим 0777; доступ к ним при этом ограничивает SELinux. В ходе ремонта индикатора я не стал заодно переделывать весь заводской жизненный цикл этих узлов.

  • Исходящий трафик не ограничен. Это сознательное условие для моих приложений. Если внутри всё же есть неизвестный вредоносный компонент, такой firewall не помешает ему самому установить соединение наружу. Отсутствие открытых входящих портов, кроме SSH, не является справкой об отсутствии закладок.

Резервные копии изменённых файлов и рабочий откат — полезная страховка, но не замена проверенной процедуре полного восстановления после повреждения загрузки. Рецепт получился привязанным к конкретной сборке. Слепо применять те же файлы и команды к любой коробке с надписью H96Max я бы не стал.

Зачем пишу этот текст

Моя приставка теперь делает то, ради чего покупалась: Steam Remote Play, Bluetooth-контроллер и VLC работают, обычный пульт и сон тоже. При этом исчезли анонимный сетевой доступ через ADB и часть заводских лазеек, появился вход по аппаратному ключу, заработал Enforcing и обновился WebView.

Железом для этих задач я доволен и для похожих сценариев могу рекомендовать его с оговорками. Доработки потребовали времени, анализа кода, пробных загрузок и ручных проверок. Цена покупки — ещё не полная цена владения такой коробочкой. А мой результат не гарантирует ни ту же плату, ни ту же прошивку, ни отсутствие заражения у другого продавца.

Если подобная приставка уже есть, инвентаризация и аудит её ПО имеют смысл. Просто смотреть фильмы из Интернета, локальной сети или с флешки можно и на менее производительном устройстве; мне запас понадобился прежде всего для игрового стриминга.

Спасибо, что дочитали до конца. Если меня не закидают помидорами, напишу вторую часть о технических деталях: командах, проверках, резервных копиях, откате и о том, почему несколько очевидных на первый взгляд решений пришлось переделать.