Демонстрация порта DOOM (порт будет разобран в следующих частях):
Часть 1: из чего состоят наушники, софтверная часть и создание патчера стоковой прошивки
Примерно год назад я заинтересовался тем, что находится внутри моих наушников soundcore Life Q35 с точки зрения софта и железа. Я захотел модифицировать их прошивку, а может, ещё и запустить DOOM (спойлер: у меня получилось).
soundcore Life Q35 — наушники на базе SoC Bestechnic BES2300P (YP).
Характеристики чипа:
Два ядра ARM Cortex M4F (до 300 МГц)
4 МБ Flash памяти
~ 1 МБ SRAM
Даташит можно посмотреть здесь.
Начало: разборка и дамп прошивки
Всё началось с того, что я перехватил и подменил трафик приложения soundcore, скачал с серверов файл с апдейтом с помощью собственного запроса к серверу через curl, что‑то попытался из него вытащить, да забросил это дело.
Через полгода я решил взяться за это исследование серьёзно и разобрать их. Купил UART‑адаптер, паяльник и переборол страх сломать свои основные наушники.
В интернете никаких инструкций по разборке и распиновок не было, поэтому пришлось исследовать это самостоятельно. Я разобрал левую чашу наушников, перевернул плату, нашёл пины UART, подпаялся к ним и... застрял на некоторое время.

В интернете есть утилиты для прошивки, оставленные и созданные комьюнити проекта openpinebuds (репозиторий, спасибо pine64!), а также официальный SDK для сборки собственной прошивки.
Для начала я, конечно же, решил прочитать память наушников, но как?
В официальной инструкции для PineBuds писалось, что нужно положить наушники в кейс, а у меня полноразмерные наушники...
Я давно замечал: когда наушники выключены, при нажатии кнопки ANC в левом динамике раздается треск с каким‑то странным промежутком, будто просыпается процессор. Это наблюдение стало ключом к режиму загрузчика.
После нескольких тестов методом тыка я выяснил: если запустить утилиту для прошивки bestool и зажать кнопку ANC на выключенных наушниках, они просыпаются, шлют sync пакет в UART, входят в режим загрузчика и, наконец, позволяют считать или перезаписать память!
Из чего состоит прошивка и с чем её едят?
После считывания дампа возник вопрос: как модифицировать прошивку и из чего она вообще состоит?Binwalk на неё плохо работает, ничего не выдает, а значит, нужно исследовать её вручную.
Заметил в конце прошивки метаданные, которые облегчили начало анализа:

Из них я узнал, что прошивка работает на основе RTX (RTOS), какой в наушниках чип, размеры и оффсеты некоторых разделов, а также выяснил характеристики памяти и базовый адрес загрузки (в будущем оказалось полезным для Ghidra)
Проблемы стоковой прошивки (причина создания проекта)
Кстати, почему я захотел модифицировать наушники?
Меня раздражала пара проблем в них (как потом оказалось, я не один такой), к примеру:
Дешёвые, раздражающие звуки роботизированной женщины с частотой дискретизации 16 кГц в моно, которые даже нельзя отключить!
Периодический треск в ушах при разряде батареи
Gate‑эффект при подключенном 3,5 мм в активном режиме (не слышны тихие звуки по кабелю)
Помимо этого, мне хотелось полностью контролировать наушники, чтобы в любой момент я (и любой другой пользователь) мог поменять в них что угодно.
Реверс‑инжиниринг (Загрузка прошивки в Ghidra)
Перед тем, как начать анализировать прошивку в Ghidra, её нужно правильно загрузить, чтобы все строки из прошивки привязались к функциям, а декомпилятор работал правильно.
Для этого рекомендую использовать утилиты для поиска базы. Например, я пользуюсь basefind2:
python basefind2.py firmwareflash.bin scanning binary for strings len>=10… total strings found: 4516 scanning binary for pointers… total pointers found: 225712 finding differences of length: 10 possible offset 0x1ffe7404 06.20% possible offset 0x3c000000 76.17%
Что делать, если скрипт не сработает и что нужно учесть при загрузке прошивки?
Можно поискать базу в метаданных прошивки (в нашем случае она есть)
Если Ghidra все равно плохо декомпилирует прошивку, можно попробовать прибавить к адресу в метаданных
0x4000000(иногда в метаданных прошивок BES базовый адрес указывается как NC, то есть non‑cached).Если вы скачали прошивку с серверов (обновление), к базовому адресу нужно прибавить смещение из
OTA_CODE_OFFSET, поскольку загрузчикOTA_BOOTне обновляется по воздуху и отсутствует в обновлениях.
Началась работа над патчером:
Я начал с замены звуков, поднятия их частоты дискретизации и добавления возможности проигрывать их в стерео (так как память на 70% пустая, место есть), для этого я:
Провел анализ прошивки с помощью Ghidra
Нашёл
switch-caseфункцию, которая отвечает за системные звуки и плеер этих звуковС помощью ИИ написал универсальный патчер на
python, который на данный момент неплохо анализирует разные прошивки (не только от Q35), находит в них нужные функции, делает несколько патчей и записывает кастомные звуки после конца прошивки
Стоит отметить, что при поиске функции для системных звуков возникли некоторые трудности — функция не имеет отладочных выводов и я её нашёл довольно интересным оригинальным методом.
Для поиска функции я создал с помощью ИИ экстрактор звуков из прошивки (они лежат в прошивке в SBC формате), вытащил звуки, посмотрел, на каком адресе они извлекались, а затем перешёл по начальному адресу любого найденного звука в Ghidra и посмотрел перекрёстные ссылки (XREF). Единственной функцией в ссылке как раз и оказался менеджер звуков!

Подведём итоги первой части и взглянем на рабочий патчер!
В итоге за несколько месяцев я создал самую первую часть от своего проекта — openqore. Патчер получил название qorepatcher.
Скоро выйдет большое обновление для всего проекта, которое позволит обновлять наушники по воздуху!
В следующих частях я расскажу о портировании SDK от PineBuds на эти (и в будущем на другие) наушники и про порт DOOM, где действия в игре привязаны к кнопкам на наушниках.
А теперь предлагаю взглянуть на итог моей первой работы! Я заменил стоковые звуки на собственные, которые написал сам.
До встречи в следующей части!
Скрытый текст
Комментарии (24)

executionerrok
18.07.2026 07:20Удивлен что хоть у кого то оголовье и наушники целые

nnonick Автор
18.07.2026 07:20На самом деле там сломаны оба механизма складывания (динамики просто мотаются свободно из стороны в сторону) и после пары падений сломалась пластиковая часть механизма для настройки оголовья (ни на что не повлияло), но носить их возможно... 4 года ходил с ними.

executionerrok
18.07.2026 07:20До сих пор хожу с ними, те же проблемы решил строительной изолентой, замотав два динамика намертво

nnonick Автор
18.07.2026 07:20Прекрасно... я бы тоже так сделал, если бы продолжал носить, ни разу их не складывал. Хорошие наушники за свои деньги, они еще и прошиваются, даже исходники для чипа есть. Можно всё что угодно с ними сделать!

DrMefistO
18.07.2026 07:20Как раз недавно смотрел у Aaron Christophel видео, в котором он завёл Doom на том же камне, но в умных часах.

saxalinpro
18.07.2026 07:20У меня тоже есть наушники от Soundcore Q30 (а3028) только, могу в будущем чем то помочь, может если получится слить каким-то образом прошивку для развития, если будет обновление по воздуху, с руками дружу, паяльник имею, ток вот прошивальщика нет, но есть Ардуино, может на нем возможно написать?

nnonick Автор
18.07.2026 07:20Они очень похожи на q35, даже есть шанс, что прошивки совместимы. У Ардуин есть UART пины, как вижу, но наушникам на пинах нужно напряжение в 1.8V, а у них может быть 3.3 или 5. Скорее всего каким-то образом нужно будет понижать напряжение. Если интересует, можем связаться, мой ТГ указан снизу.

violletta_kabacz
18.07.2026 07:20Очень интересная статья, спасибо! У самого Q20i, но в сторону прошивок и встроек только-только начинаю входить. Из текста статьи не очень детально понял, как именно встраиваемый код попадает в итоговый бинарь и как МК наушников понимает, где его выполнить. Может, проморгал, но был бы рад, если бы пояснили :)
Кстати, использовали ли Вы какие-то ресурсы/инструменты для погружения в тему, или все шло эмпирическим путем?

nnonick Автор
18.07.2026 07:20Для начала хочу сказать, что изучал Q20i несколько месяцев назад, в них тот же самый чип!
Спасибо за обратную связь, в будущих частях про загрузку и т.д. расскажу :)
Сама прошивка - просто ARM-бинарник с RTOS, который разделен на секции (по смещениям адресов). В МК вшит неизменяемый загрузчик (BootROM), который отвечает за восстановление через сервисный порт (через него считывался флэш с помощью bestool) и загрузку прошивки с флешки. МК загружается именно с него.
При запуске он указывает процессору, что нужно исполнять код с адреса флэша (0x3c000000). Сам код в прошивке - ассемблерный байткод.
Мой патчер находит в прошивке похожую структуру кода (сравнивает с той, что в нем прописана), выбирает несколько функций-кандидатов и меняет код в главном кандидате (пишет звуки в пустую память, а в функции меняет указатели (адреса) с стоковых звуков на заменённые) и сохраняет бинарник. Его можно прошить через тот же bestool.
Про погружение - про саму составляющую прошивки я узнавал сам, об этом мало что было в интернете. На чип BES2300P есть даташит (он указан в начале статьи), но я его использовал максимум для того, чтобы узнать, какое напряжение требуется для UART пинов.
Если сказать просто - всё шло и эмпирическим путём, но с использованием различных ресурсов и инструментов.
Если просто перечислить инструменты, которые использовались:
Ghidra - декомпилятор/дизассемблер бинарного кода.
basefind2 - утилита, которая помогает найти адрес загрузки прошивки.
bestool - утилита для считывания/прошивки для чипов BES.
Конечно же, ИИ. С помощью него писались все скрипты и я частично использовал его как источник информации.
Я увлекаюсь информационной безопасностью, поэтому я решал CTF-задачи по реверс-инжинирингу, но больше всего тренировался на реальных вещах - я изначально исследовал работу ABL (fastboot в android) образа на процессорах Qualcomm, благодаря этому я как раз научился пользоваться Ghidra и получил базовые знания о том, как работает скомпилированный код. И сами наушники как раз тоже исследовались, чтобы получить знания в этой сфере.

ganzmavag
18.07.2026 07:20О, у меня как раз такие наушники, очень интересны любые возможности что-то там поменять. И вообще интересны подробности об их работе изнутри: как с эквалайзером работают, какие настройки у их стандартного эквалайзера, какие частоты дискредитации и битрейт поддерживают (по AAC у меня получалось по логам что-то около 230)

nnonick Автор
18.07.2026 07:20Через пару дней выйдет обновление, которое позволит прошить патч звуков прямо по воздуху, без разборки! Вообще, в даташите написано, что ЦАП чипа может выдавать вплоть до 192кГц и еще много чего. Главное - чтобы потянул блютуз. Но такое возможно уже с полностью кастомной прошивкой, которую я, к слову, тоже делаю. Остальное я не исследовал пока что... спасибо за комментарий! У меня стоит в целях на будущее реверс-инжиниринг звуковой части в стоковой прошивке.

k4ir05
18.07.2026 07:20Вообще, в даташите написано, что ЦАП чипа может выдавать вплоть до 192кГц
Ну блютуз такое не вывезет (разве что с низкой разрядностью).
А есть возможность заставить их (относится и к другим блютуз наушникам) нормально звучать в выключенном через провод? Или эта проблема в настройке самих динамиков?

nnonick Автор
18.07.2026 07:20В выключенном состоянии ЦАП не работает, это уже относится к самим динамикам. Кстати, чип поддерживает USB аудио, так что вполне можно по кабелю слушать музыку на безумных частотах, если когда-нибудь добавлю USB стек в свою прошивку :)

k4ir05
18.07.2026 07:20Это интересно. Но поддерживает ли USB-порт передачу данных? Производитель мог и урезанный туда воткнуть, он ведь используется только для зарядки.

nnonick Автор
18.07.2026 07:20Удивительно, но да. Линии данных подключены и идут прямо из платы с чипом в плату с разъемом. Но при этом стоковая прошивка собрана вообще без USB стека, судя по всему решили в последний момент не добавлять USB-аудио.
UplandDivan
Когда же кто-нибудь запустит Doom на советской игре "Электроника"?
pewpew
вместо мультика, который показывают, когда доходишь до 999 очков?