
Заметки по обратной разработке и инструменты на Python для прошивки JBL Wave Buds 2 (BES1306): формат OTA-контейнера, разметка флеш-памяти, протокол BLE/GATT и модель доверия на основе CRC-32.
Заметки по реверс-инжинирингу и воспроизводимый инструментарий для JBL Wave Buds 2
(Bestechnic BES1306, PID 2100): раскладка во флеш-памяти, формат OTA-контейнера
вплоть до байта, протокол команд BLE/GATT и зашифрованный транспорт BES «TOTA v2»,
границы доверия на стороне устройства и приложения, заводская консоль и
воспроизводимый метод загрузки самостоятельно собранного образа на принадлежащее вам
устройство.
Анализ охватывает две сборки — проанализированный в IDA wavebuds.elf (апрель 2025) и
дистрибутивный пакет 2.9.0 (сентябрь 2026) — полностью специфицированный 8-поточный OTA-контейнер
(подтверждённый побайтово идентичной перепаковкой), модель целостности CRC-32,
подтверждённую как на стороне приложения, так и на стороне устройства, таблицу заводских команд из 54/59 записей,
12 переменных состояния OTA в RAM, перечисление из 7 960 функций и кросс-сборочный
дифференциал. Семантическое восстановление глубоко проработано для подсистем OTA/флеш/CRC/заводской консоли
и ограничено перечислением в остальных местах — см. аудит полноты.
[!WARNING] Это аппаратное исследование, выполняемое владельцем, а не официальное обновление JBL. Прошивка модифицированного образа необратима: фаза загрузки выполняется поэтапно и безопасна с точки зрения кирпича, но активация образа с корректным CRC, но сломанного, не имеет доступного пути восстановления. Прочитайте SAFETY.md перед тем, как что-либо воспроизводить.
Турецкая версия: README.tr.md

Аппаратный результат на протестированном устройстве: после того как конвейер OTA через приложение + пользовательский CA MITM был проверен, оба наушника подключаются, показывают 100%, и каждый элемент управления приложения (ANC/Ambient, жесты, эквалайзер) работает. Образ, изменённый на один байт, был принят таким же образом, и устройство осталось полностью функциональным.
Адреса взяты из проанализированной сборки (wavebuds.elf); см.
реестр адресов и происхождение.
0x2C0918BC проверяет конфигурацию, каждый сегмент и
весь образ с помощью процедуры CRC-32 0x2C0CE944 (таблица 0x2C0F5218) плюс
магическое значение "BEST". Образ с корректным CRC и одним изменённым байтом был принят и
загружен.com.jbl.counterfeit.Rsa2048DynamicVerifier) —
это защита от подделок (подлинность устройства), а не подпись прошивки.0x28120000, пока
работающее приложение не затронуто, поэтому фаза загрузки безопасна с точки зрения кирпича.0x2C0905E4: MEMORY[0x20026BA0] ∈ {2,4}).UNRESOLVED.Модификация намеренно минимальна — один байт распакованного образа.
Она меняет строку ядра RTX RTX V5.5.1 → V5.5.2 по смещению в распакованном виде
64096, и CRC-32 контейнера пересчитывается. По замыслу она косметическая: цель —
доказать, что устройство принимает модифицированный, но корректный по CRC образ, а не
изменить поведение.
Base (owner-supplied; not redistributed)
official 2.9.0 package 549,558 bytes SHA-256 836cb251f9fb2261dde14f39ba18d358c48018817f3c3d1b527e1ac5f3ab7ba2
decompressed image 955,596 bytes SHA-256 489663e80b76f20f4c94671064908569fac5f4e3df10ab6d7369baffe094f67d
container CRC-32 A0C7CCEC (valid), input range [0x0, 0x862AD)
Репозиторий намеренно не содержит прошивку JBL. Предоставьте собственный легально полученный пакет и воспроизведите:
python3 tools/ota_unpack.py <official_2.9.0_package.bin> --extract image.bin
python3 tools/ota_repack.py make-test <official_2.9.0_package.bin> test.bin
python3 tools/ota_unpack.py test.bin # exactly one decompressed byte differs; CRC valid
Точные байты перепакованного контейнера зависят от LZMA-кодера; устройство проверяет CRC-32, а не хеш пакета (см. docs/04), и однобайтовое различие после распаковки детерминировано. Доставка через приложение описана в docs/08.
| Карта флеш-памяти | Разметка 2 МБ NOR |
| Поток OTA-команд | последовательность и её контрольные точки CRC-32 |
| Границы доверия | что проверяет каждый этап и на чём держится доверие к образу |