Decompiled from stock QuNexus_Firmware_v2.2.1.bin (EFM8UB20F64G / 8051, base 0x2400, 54279 bytes) with radare2 6.2.0. - qunexus_v2.2.1.asm : full linear disassembly (37287 lines, byte-faithful) - pseudocode_all.c : r2 pdc pseudocode for all 1002 functions - functions.txt : function index (1002 functions) - regen.sh + r2script.r2 : one-command reproduction (brew install radare2) Verified: reconstructing the binary from the asm byte-columns reproduces the original image byte-for-byte (30560 instructions + 195 data gaps).
77 lines
3.6 KiB
Markdown
77 lines
3.6 KiB
Markdown
# QuNexus firmware v2.2.1 — reverse-engineered source
|
||
|
||
Disassembly and pseudo-decompilation of the Keith McMillen / KESUMO QuNexus
|
||
application firmware (EFM8UB20F64G, an 8051-core MCU), produced with radare2.
|
||
|
||
This is a **nested git repository** (its own repo, living under the parent
|
||
`qunexus-qt6` project). It is self-contained: the stock input binary is
|
||
included so every artifact here can be regenerated with one command.
|
||
|
||
## Input
|
||
|
||
| File | What |
|
||
|---|---|
|
||
| `QuNexus_Firmware_v2.2.1.bin` | stock v2.2.1 application image, flat binary, base `0x2400`, 54 279 bytes, spans `0x2400`–`0xF806`. (The bootloader region `0x0000`–`0x23FF` is not in this image and is not decompiled here.) |
|
||
|
||
## Generated artifacts
|
||
|
||
| File | What | Lines |
|
||
|---|---|---|
|
||
| `qunexus_v2.2.1.asm` | **Full linear disassembly** of the whole image, absolute code-space addresses (`0x2400`+), with xrefs & comments. Nothing omitted. | 37 287 |
|
||
| `pseudocode_all.c` | r2 `pdc` C-like **pseudocode for all 1002 functions**. 668 complete; 334 end with `// chop` (r2's size limit on big functions — see those in the asm). | 38 396 |
|
||
| `functions.txt` | r2 function index: `address size nblocks name` — 1002 functions. | 1 002 |
|
||
|
||
## Reproduce
|
||
|
||
```
|
||
brew install radare2 # one-time
|
||
./regen.sh # rebuilds the three artifacts from the .bin
|
||
```
|
||
|
||
`regen.sh` runs `r2 -a 8051 -b 8 -m 0x2400 -i r2script.r2 QuNexus_Firmware_v2.2.1.bin`.
|
||
`r2script.r2` is the exact radare2 script used.
|
||
|
||
## Faithfulness — does it re-compile?
|
||
|
||
The disassembly is **byte-faithful**: reconstructing the binary from the asm's
|
||
byte columns (30 560 instructions + 195 small data gaps) reproduces the
|
||
original 54 279-byte image **byte-for-byte**. So the listing is a complete,
|
||
accurate representation — nothing lost or corrupted.
|
||
|
||
The r2 `.asm` file is **not** directly valid input to an 8051 assembler (it is
|
||
r2 display format: function borders, xref comments, `fcn.xxxx` labels, address
|
||
prefixes). To re-assemble into a flashable binary it must be converted to a
|
||
real assembler's syntax (e.g. `sdas8051` from SDCC, or Keil A51): strip r2
|
||
annotations, turn `ljmp`/`lcall` targets into labels, emit the 195 data gaps as
|
||
`.db`, and set `.org 0x2400`. With that conversion it re-assembles to the
|
||
identical binary. (Round-trip via SDCC is the natural next step if needed.)
|
||
|
||
## Known landmarks (verified in the output)
|
||
|
||
| Address | Meaning |
|
||
|---|---|
|
||
| `0x2400` | app reset vector (`ljmp 0xb691`) |
|
||
| `0xA57B` | USB-MIDI router: cable number → destination ring buffer |
|
||
| `0xDF05` | USB-MIDI event dispatcher |
|
||
| `0xDF28` | `LCALL 0xA57B` — the single call site the USB-1→CV patch retargets |
|
||
| `0x8126` | 23-byte `0xFF` padding region the patch's stub is written into |
|
||
| `0xE8E6` | `LJMP 0x0000` — the only bootloader-entry jump |
|
||
| `0xB48D` | SysEx command handler (bootloader-entry path) |
|
||
|
||
## Caveats
|
||
|
||
- r2's 8051 auto-analysis is decent but imperfect: data-in-code regions decode
|
||
as the matching instruction (a linear-sweep artifact). Use `ljmp`/`lcall`/
|
||
`acall` targets and `functions.txt` as the map of real code.
|
||
- `pdc` chops ~1/3 of functions (the big ones). The asm listing covers them
|
||
fully. For unchopped Ghidra-quality pseudocode, the `r2ghidra` plugin
|
||
(`r2pm install r2ghidra`, then `pdg @ func`) is the upgrade path.
|
||
|
||
## Provenance
|
||
|
||
Decompiled 2026-08-17 from the stock `QuNexus_Firmware_v2.2.1.bin` (the same
|
||
image shipped in the qunexus-qt6 editor's Qt resources as
|
||
`QuNexus_Firmware_v2.2.1-cs512.syx`). The reverse-engineering was done in
|
||
service of a USB-1→CV routing patch (see `../patch_usb1_to_cv.py` and
|
||
`../c2probe/`); this repo captures the reference disassembly of the unmodified
|
||
firmware. |