
Note di reverse engineering e strumenti Python per il firmware degli JBL Wave Buds 2 (BES1306): formato del contenitore OTA, layout della flash, protocollo BLE/GATT e modello di fiducia CRC-32.
Note di reverse engineering e strumenti riproducibili per gli JBL Wave Buds 2
(Bestechnic BES1306, PID 2100): il layout del flash, il formato del container
OTA fino al singolo byte, il protocollo di comando BLE/GATT e il trasporto cifrato
"TOTA v2" di BES, i confini di fiducia lato dispositivo e lato app, la console di
fabbrica e un metodo riproducibile per caricare un'immagine autocostruita su un'unità di
proprietà.
L'analisi copre due build — il wavebuds.elf analizzato con IDA (apr 2025) e
il pacchetto di distribuzione 2.9.0 (set 2026) — un container OTA a 8 stream
completamente specificato (verificato tramite repack byte-identico), il modello di
integrità CRC-32 confermato sia lato app che lato dispositivo, una tabella di comandi
di fabbrica da 54/59 voci, 12 variabili di stato OTA in RAM, un'enumerazione di
7.960 funzioni e un differenziale tra build. Il recupero semantico è approfondito per
i sottosistemi OTA/flash/CRC/fabbrica ed è solo enumerativo altrove — vedi la
verifica di completezza.
[!WARNING] Questa è ricerca hardware eseguita dal proprietario, non un aggiornamento ufficiale JBL. Il flashing di un'immagine modificata è irreversibile: la fase di download è a stadi e sicura contro il brick, ma l'attivazione di un'immagine valida per CRC ma danneggiata non ha alcun percorso di ripristino esposto. Leggi SAFETY.md prima di riprodurre qualsiasi cosa.
Versione turca: README.tr.md

Risultato hardware sull'unità testata: dopo la validazione della pipeline OTA app + MITM con CA utente, entrambi gli auricolari si connettono, riportano il 100% e ogni controllo dell'app (ANC/Ambient, gesture, EQ) funziona. L'immagine modificata di un byte è stata accettata allo stesso modo e il dispositivo è rimasto pienamente funzionante.
Gli indirizzi provengono dalla build analizzata (wavebuds.elf); vedi il
registro degli indirizzi e la provenienza.
0x2C0918BC verifica la configurazione, ogni segmento e
l'intera immagine con la routine CRC-32 0x2C0CE944 (tabella 0x2C0F5218) più un
magic "BEST". Un'immagine valida per CRC con un byte modificato è stata accettata e
avviata.com.jbl.counterfeit.Rsa2048DynamicVerifier) è
anti-contraffazione (autenticità del dispositivo), non di firma del firmware.0x28120000 mentre
l'applicazione in esecuzione resta intatta, quindi la fase di download è sicura contro il brick.0x2C0905E4: MEMORY[0x20026BA0] ∈ {2,4}).UNRESOLVED.La modifica è intenzionalmente minima — un byte dell'immagine decompressa.
Cambia la stringa del kernel RTX RTX V5.5.1 → V5.5.2 all'offset decompresso
64096, e il CRC-32 del container viene ricalcolato. È cosmetica per design: lo
scopo è dimostrare che il dispositivo accetta un'immagine modificata ma valida per CRC, non
cambiare il comportamento.
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)
Il repository non contiene intenzionalmente alcun firmware JBL. Fornisci il tuo pacchetto ottenuto legalmente e riproduci:
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
I byte esatti del container ripacchettizzato dipendono dall'encoder LZMA; il dispositivo verifica CRC-32, non un hash del pacchetto (vedi docs/04), e il diff decompresso di un byte è deterministico. La consegna tramite l'app è in docs/08.
| Mappa della flash | partizionamento della NOR da 2 MB |
| Flusso dei comandi OTA | la sequenza e i suoi checkpoint CRC-32 |
| Confini di fiducia | cosa verifica ogni fase, e su cosa si fonda la fiducia nell'immagine |