QuNexus v2.2.1 firmware: reverse-engineered disassembly & pseudocode

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).
This commit is contained in:
2026-08-17 22:22:21 +02:00
commit 27c21396f8
7 changed files with 76783 additions and 0 deletions
Binary file not shown.
+77
View File
@@ -0,0 +1,77 @@
# 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.
+1002
View File
File diff suppressed because it is too large Load Diff
+38396
View File
File diff suppressed because it is too large Load Diff
+37287
View File
File diff suppressed because it is too large Load Diff
+13
View File
@@ -0,0 +1,13 @@
e scr.color=0
e scr.utf8=0
e scr.html=false
e asm.bytes=true
e asm.lines=true
e asm.xrefs=true
e asm.flags=true
e asm.comments=true
aaa
afl > functions.txt
pD $s @ 0x2400 > qunexus_v2.2.1.asm
pdc @@F > pseudocode_all.c
echo === regen done ===
Executable
+8
View File
@@ -0,0 +1,8 @@
#!/bin/sh
# regen.sh -- regenerate the disassembly & pseudocode from the stock binary.
# Requires radare2 (>=6.x): brew install radare2
set -e
BIN=QuNexus_Firmware_v2.2.1.bin
command -v r2 >/dev/null || { echo "radare2 (r2) not found; brew install radare2"; exit 1; }
r2 -a 8051 -b 8 -m 0x2400 -q -i r2script.r2 "$BIN" 2>&1 | grep -vE "^WARN|^INFO"
echo "regenerated: functions.txt qunexus_v2.2.1.asm pseudocode_all.c"