(listen to this image if you can't read cyrillic)
This repository is my work on reverse-engineering my fake chinese JBL speaker. My initial goal was to properly replace the default awful voiceover but I ended up developing few more programs. I decided to make them public so everyone could try modifying the firmware of their AppoTech / Buildwin speakers. I tried to impose as few restrictions as possible to allow experimenting with firmware.
The programs in the repository are exclusively for the AppoTech platform, also known as Buildwin. Do not use these tools on speakers based on chips from other manufacturers. You can easily recognize an AT/BW chip by the manufacturer's logo on the chip: .
If you want to try to proceed without tearing down your speaker you can try connecting it to PC. I have not figured out (yet) the reliable and always working way to boot into the USB Mode while the firmware is fine. However if your speaker got recognized by the PC with USB VID 1908
then it's AppoTech / Buildwin.
At this moment the most reliable way to work with firmware is unsoldering the SPI flash IC and reading/dumping its whole contents. I used flashrom on Linux for this purpose.
Further in the text firmware.bin
will be referred to as the complete SPI memory image of the speaker.
./xxxxxxxxxxx.py -h
) before working with the program. The following are the most common examples of program usage.
Program for modifying firmware sound resources. Your one-stop solution for getting rid of "the chinese lady" voiceover. It has been created as result of reverse-engineering the official MP3RESTOOL utility for Windows. The only difference is appotech-sfx
doesn't generate the .h
file. Well, we don't need it anyway.
Caveat: you'll have to make your own SFX pack, but with emergence of AI tools such as RVC/RVCv2 you can easily make any voiceover you like.
./appotech-sfx.py -e ./my-sfx-files firmware.bin
This command reads firmware.bin
and extracts individual files into ./my-sfx-files
directory. It will be created automatically if it doesn't exist.
Do not change the original order of the files unless you're fuzzing the firmware and intentionally trying to find bugs in it. First go the MP3s, then go the WAVs. The firmware cannot decode MP3 while in Bluetooth mode, this is exactly why it has a set of WAV files.
Warning for Audacity users! You must disable dithering before exporting any modified WAV file: The WAV files will have very loud unpleasant noise if you don't disable dither. Dither is a long-time "feature" of Audacity but it's broken for low-samplerate projects such as AppoTech SFX.
Keep an eye on the total size of audio files! Do your best to avoid exceeding the size of the original SFX blob. This is very important.
./appotech-sfx.py -O firmware.bin ./my-sfx-files
This will not overwrite the original firmware but create a new file.
Program for modifying the Bluetooth settings. If such option was enabled by the manufacturer of your speaker (those are enabled at compile time) then you can override the default Bluetooth name and MAC address, as well as set up Mute settings.
./appotech-btinfo.py -i firmware.bin -S bt_name "Ze Blootoos diwice" -O firmware-mod.bin
./appotech-btinfo.py -i firmware.bin -S bt_mac "13:37:00:00:13:37" -O firmware-mod.bin
Actually you can change both name and MAC in one command. Read -h
for details.
Program for modifying the database of paired/connected devices. Can be useful for dumping Bluetooth Link Keys.
./appotech-btpairing.py -i firmware.bin -p
./appotech-btpairing.py -i firmware.bin -x 0 -O firmware-mod.bin
This will make the speaker try to connect to the specified device after poweron. Is it a DOS opportunity..?
The amount of devices saved is decided by the speaker manufacturer, the size is hardcoded when the firmware is compiled. I have no idea (yet) how to access this value. Usually it's 3~6. For example it's 4 on my speaker.
Note: the draft of this chapter was originally written in Russian (my native language), you are reading a machine translation by DeepL. If you find any mistake, I would be grateful for Pull Requests with corrections.
The AT/BW controllers have a USB flashing feature. It is activated automatically under certain circumstances, e.g. when SPI memory could not be initialised or when the battery is disconnected from the speaker. The speaker is then recognised as a blank USB Mass Storage drive when connected to a computer via USB.
There is an official MPTool program for Windows that flashes SPI memory in the speaker. This is very interesting because you can easily flash the memory without having to unsolder the chip or make converters.
Since the speaker is pretending to be an empty drive, it does not need a separate driver and/or Zadig fiddling, and the program uses only the native DeviceIoControl
function from WinApi. Once started, the program waits for the speaker to connect. When connected, the program checks its name (in my case it is Buildwin SPI08080-Loader 1.02
) and dynamically loads a small module (in my case spi0802_driver.dll
) from the working directory, after which it performs a handshake with the speaker and begins the SPI memory chip identification routine. This is done by loading the database of supported memory from FlashLib.ini
, testing the ID of each chip one by one until the operation succeeds. In case of failure (e.g. when the SPI chip is not supported by the software), the chip IDs will be logged.
During operation MPTool sends SCSI commands to the speaker and receives responses from it. The problem is that after the handshake is complete, the communication is encrypted. Actually, I can't really call this "encryption", more like "scrambling", for the following reasons:
- MPTool does not use AES and similar algorithms when communicating with the speaker. On the contrary, quite a few XOR operations are used in creating the outgoing command.
- The entropy of the intercepted USB traffic remains low after the handshake, indicating that no encryption is used. Even some patterns in the scrambled commands could be seen in Wireshark:
It is interesting to note that during the handshake, the speaker responds with some kind of 4-byte value, which is presumably then used in scrambling the traffic. In addition, only the commands coming from the computer are scrambled, while the speaker's responses are received in plain text.
The problem is exacerbated by the fact that when repeating the same operation (I tested MPTool in SPI memory identification mode, i.e. when the FlashLib.ini
file does not contain any chips) the outgoing traffic is not repeated. During handshake, the speaker responds with different 4-byte values. It is possible that this has some connection. The picture below shows the handshake and the start of communication opened in Wireshark. The highlighted value returned by the speaker is always different.
You can notice that 2 opcodes are used: 0xFA
and 0xFB
, and scrambling is most likely used only with 0xFB
opcodes.
I was trying to find some information and came across the repository kagaimiq/ax225. His script for handshake also uses 0xFA0059684870
, but when I tried other commands from this repository, they didn't work.
I will keep trying ocassionally but to be honestly I'm sure I won't succeed. Any help is greatly welcome!
According to this document, the speaker might have a self-update feature that could allow loading the modded firmware from microSD card. Self-update is an optional component of firmware and the manufacturer can disable it at compile time. The document says there are many ways to flash the firmware, and I'm particularly interested in "force mode" that disables all "safety mechanisms" and overwrites the whole SPI flash with contents of updatefw.bin
or upd_app.bin
.
Caveat: the bwwhpupd.xbt
file is required to enter "force mode". You can check out the contents of this file here. It is unknown how this file is generated and if it could ever be reused on other speakers because multiple other docs mention signing and encrypting the firmware. I could not enter the self-update mode (by holding Next/Vol+ while powering on) because my speaker seems to have this feature disabled.