- Research on how the Bodet Harmony PSA Protocol works
- Tools to allow features to be used your Netsilon can't do
- Research on replacing the Bodet Software Called SIGMA and the Time Server for it (I can't even take its name serious) and eventually links to the replacement software called BE-YOUR-OWN-SIGMA (if I achieve reverse engineering it to a certain decentish degree).
Important Disclaimer: While the structural fields of the packets are mostly well understood, the checksum calculation remains quiet mysterious. Without correctly reproducing the checksum, generating functional packets yourself remains unreliable unless you copy known working ones, therefore this can only be used for repetitive actions with already learnt and working commands.
Contains valid payloads that get accepted by the system if sent to multicast address 239.192.55.2
stop-payloads.txt
If you want to help out with figuring things out this is where to look I'd say
Please IF YOU KNOW HOW TO MAKE THE CHECKSUMS WORK PROPERLY OR KNOW MORE THAN ME PLEASE HELP ME!!!
- Platform: Freescale MQX RTOS
- MCU: Most likely a Freescale/NXP Cortex-M4 (based on MQX + strings + 2017 build date)
- Networking Stack: LwIP
- Storage: MFS-style filesystem, Speakers and Sound Generating Components have an SD Card
- Web Interface: Embedded HTTP server (
Server: MQX HTTP - Freescale Embedded Web Server
)
- Ports & Protocols:
- HTTP, FTP (port 21), SNMP, IGMP multicast, UDP
- FTP Banner:
RTCS FTP Server Ready
- Project was built using Windows Jenkins (who could've guessed that), based on hardcoded paths in strings of firmware files:
d:\JenkinsJobs\workspace\Indus\Harmonys\Harmonys_trio\Metis_appli\Middlewares\Third_Party\LwIP\
- Sources show extensive use of LwIP stack and standard Freescale directory structures
Based on repeated appearances in both firmware strings :
Username |
Password |
public |
jkl1vi5erjnfh |
public |
aSe2=9Z8gOi37* |
- Found log strings that explicitly reference checksum calculation and failures:
CHK = %04x (%d)
CHK BAD !!! %d
- Could however also be just for firmware integrity maybe? Rather unlikely though.
Also of note :
F_traitement_trame_PROTOCOLE
F_traitement_trame_vie_repeteur
REP STREAM !!! ERREUR !!!
RX %d/%d (%d/%d)
- These functions appear responsible for:
- Receiving and validating packets
- Detecting checksum mismatches
- Possibly retrying on failures?
Each IP Button Bodet Sound Protocol Payload follows a consistent format:
[MEL HEADER]-[LENGTH]-[START]-[SEQUENCE]-[COMMAND]-[ZONE INFO]-[METADATA]-[CHECKSUM]
Seems to send two of the packets each time a button is pressed
- Hex:
4D 45 4C
- ASCII: "MEL" (probably short for "Melody")
- Identifies this as a Bodet Sound Protocol packet
- 2 bytes
- Indicates payload size in decimal (excluding MAC/IP/UDP headers)
- Example:
0021
= 33 bytes
- Constant:
0100
- Marks start of command block
- 2 bytes, Little Endian
- Only the first byte appears to increment; the second is often
FF
, suggesting padding or reserved space
- Likely acts as a replay or event counter
-
Examples:
-
3001
= Melody
5001
= Alarm
5002
= Stop
- 12 bytes (6 words of 16 bits = 96 bits)
- Represents zones 1–100 using a bitfield
- Each zone bit is encoded as:
byte_index = (zone - 1) // 8
bit_index = (zone - 1) % 8
set bit (7 - bit_index) in byte[byte_index]
* You can enable multiple zones in a single packet by OR-ing the relevant bits
* Examples:
- Position: Final byte of packet
- Behavior: Matches
(sum of all previous bytes) & 0xFF
in most cases, but not always.
- Status: SEND HELP (see section below)
4d454c 0021 0100 28ff 3001 8000 0000 0000 0000 0000 0000 0001 03 00 01 09 0100 01 d5
- Zone 8 =
8000 ...
- Volume =
03
, Repeats = 00
(infinite)
- Melody =
09
- Checksum =
D5
4d454c 001a 0100 24ff 5002 ffff ffff ffff ffff ffff ffff 0f 01 07
- All zones =
FF FF ...
(you actually cant choose which zone to turn of system refuses zonemaps here)
- Command = Stop (
5002
)
- Ends with
0F 01
instead of 0100
→ supports theory that 0100
indicates only the end of melody/alarm command block
- Checksum =
07
While many packets obey a simple rule:
checksum = sum(packet[:-1]) & 0xFF
... others diverge due to what appears to be a variable offset or conditional logic. Several hypotheses have been explored:
- Static or conditional offset subtracted from the sum
- Offset based on specific bytes (e.g., command, zone byte)
- Very small chance of a lookup table (LUT) approach per command (dont think so though since IP buttons have only 256KB RAM)
If the checksum is wrong, the Bodet PSA system and its components obviously ignore the packet. Hence generating your own commands reliably is not yet possible unless mimicking an exact known good packet.
This makes full integration with modern systems (for triggering Bodet audio via automation) dependent on further reverse engineering.
If you have firmware dumps, better knowladge of UDP and reverse engeneering checksums or just generally more insights, feel free to contribute
The executables/hexen.py
script provides a utility to send raw hex payloads and includes a bruteforce mode for the last byte of a given hex prefix. This is particularly useful for trying to find working checksums or other variable last bytes.
-
Initiating Bruteforce:
- Run the script:
python hexen.py
- To start a bruteforce, type:
brute <hex_prefix>
- Example:
brute 4d454c0021010004ff300180000000000000000000000000010202010f010001
- The script will then iterate through all possible last bytes (0x00 to 0xFF) appending them to this prefix.
-
Configuration Prompts:
- Mode Selection:
(1) Manual
: Sends one packet at a time and asks for feedback.
(2) Auto Ascending
: Sends all packets from <prefix>00
to <prefix>ff
automatically.
(3) Auto Descending
: Sends all packets from <prefix>ff
down to <prefix>00
automatically.
- Delay:
- Prompts for the time (in seconds, e.g.,
0.5
, 1
) to wait between sending each packet.
-
Interactive Controls (During Bruteforce):
- Manual Mode (
1
):
- After each packet is sent, you'll be prompted:
Did it work? (y/n/auto/stop/r=retry last 3/c=cancel):
y
: Confirms the current hex string worked. The bruteforce for this prefix stops, and the successful string is saved to the MAGIC
file.
n
: Continues to the next hex value.
auto
: Switches to auto-ascending mode for the remainder of the current prefix.
stop
or c
: Aborts the current bruteforce operation.
r
: Resends the last up to 3 packets (including the current one).
- Auto Modes (
2
or 3
) (Windows Only - requires msvcrt
):
- An initial message will inform you:
During auto mode: press 'c' to cancel, 'r' to retry last 3, 'p' to pause/resume.
c
: Cancels the current bruteforce operation.
r
: Pauses sending, resends the last up to 3 packets, then resumes.
p
: Toggles pause/resume for the auto-sending process.
-
Saving Results to MAGIC
File:
- The
MAGIC
file path is defined at the top of hexen.py
(default: /Users/crt/Documents/bodeting/research/bad-bruteforcing/attempt-1.txt
).
- Successful Bruteforce: If you confirm a packet worked (with 'y' in manual mode), the complete successful
full_hex_string
is automatically appended to this file.
- Cancelled/Completed (No Success): If the bruteforce is cancelled or finishes all iterations without a 'y' confirmation, you'll be prompted:
Kein Zauber hat gewirkt oder du hast abgebrochen. Gib den Suffix für '<hex_prefix>' ein, um ihn ins Buch zu kritzeln (oder Enter zum Überspringen):
- If you enter a suffix (e.g.,
fa
), the script will save hex_prefix + entered_suffix
to the MAGIC
file.
- If you press Enter, nothing is saved for that attempt.
- The script checks if the directory for the
MAGIC
file exists and if the file is writable, providing error messages if issues are encountered.
This tool aims to simplify the process of testing variations of known packet structures, especially when only the checksum isnt known