385 lines
18 KiB
Markdown
385 lines
18 KiB
Markdown
# QR Code Analysis
|
||
|
||
## Scope
|
||
|
||
The QR code system on Pokemon Pro involves **two separate code paths**:
|
||
|
||
1. **QR Code Generation** — The game uses Nayuki's `qrcodegen` library to generate QR codes (WiFi config, Stern Insider Connected login, support URLs) and display them on-screen.
|
||
2. **QR Code Scanning** — A standalone hardware scanner module connected to the game via a `node4` bridge board (LPC812/LPC1124 MCU on the SPIKE-3 nodebus) and a serial UART.
|
||
|
||
**Important finding**: The QR code scanning functionality is in the **main game binary** (`/games/pokemon_pro/game`), **not** in `conagent`. The `conagent` binary has no QR-related strings or code. See `conagent-re.md` for the connectivity agent's separate role.
|
||
|
||
## Source Binary
|
||
|
||
- Target: `/games/pokemon_pro/game`
|
||
- Workspace path: `games/pokemon_pro/game`
|
||
- SHA-256: (see `artifact-index.md`)
|
||
- Type: stripped AArch64 PIE ELF, 52,829,400 bytes
|
||
- Embedded library: `qrcodegen` (Nayuki's QR Code Generator, C library)
|
||
|
||
## QR Code Generation
|
||
|
||
### Library: qrcodegen
|
||
|
||
The game embeds **Nayuki's QR Code Generator** library (`qrcodegen.c` at file offset `0x25e6c88`). This is a standalone C library that generates QR code symbol data from text input. Confirmed API functions:
|
||
|
||
| Function | Offset | Purpose |
|
||
|---|---|---|
|
||
| `qrcodegen_encodeSegmentsAdvanced` | `0x26028f8` | Core encoding entry point |
|
||
| `qrcodegen_getSize` | `0x2602760` | Get QR code module size |
|
||
| `qrcodegen_getModule` | `0x2602998` | Get individual module bit |
|
||
| `qrcodegen_isNumeric` | `0x2602728` | Check if text is numeric mode |
|
||
| `qrcodegen_isAlphanumeric` | `0x26029b0` | Check if text is alphanumeric mode |
|
||
| `qrcodegen_makeBytes` | `0x2602a00` | Create byte segment |
|
||
| `qrcodegen_makeNumeric` | `0x2602a18` | Create numeric segment |
|
||
| `qrcodegen_makeAlphanumeric` | `0x2602a38` | Create alphanumeric segment |
|
||
| `qrcodegen_makeEci` | `0x2602a30` | Create ECI segment |
|
||
|
||
Internal assertion strings confirm library version constraints:
|
||
- `qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX` (0x25e6c98)
|
||
- `21 <= qrsize && qrsize <= 177` (0x25e6d90)
|
||
- `0 <= (int)ecl && (int)ecl < 4` (0x25e7070)
|
||
|
||
### QR Code Output: BMP Files
|
||
|
||
Generated QR codes are rendered as **BMP image files**:
|
||
|
||
| Path | Offset | Purpose |
|
||
|---|---|---|
|
||
| `/tmp/qrx_.bmp` | `0x25db068` | Temporary QR code image |
|
||
| `/tmp/login.bmp` | `0x25e1760` | Login QR code output |
|
||
| `/connectivity/qr_code_storage/%d.bmp` | `0x25e26e8` + `0x25e2718` | Persistent QR code storage |
|
||
|
||
### QR Code Configuration Properties
|
||
|
||
QR code display properties are configured via a JSON-like object with these fields (all at offsets `0x25db270`–`0x25db2e0`):
|
||
|
||
| Field | Type | Purpose |
|
||
|---|---|---|
|
||
| `qrCodeText` | string | The text/URL to encode in the QR code |
|
||
| `qrCodeAppendMachineUuid` | bool | Whether to append machine UUID to text |
|
||
| `qrCodeStartTime` | timestamp | QR code validity window start |
|
||
| `qrCodeEndTime` | timestamp | QR code validity window end |
|
||
| `qrCodeXPosition` | int | Screen X position |
|
||
| `qrCodeYPosition` | int | Screen Y position |
|
||
| `qrCodeSize` | int | QR code size in pixels |
|
||
|
||
### Generated QR Code Types
|
||
|
||
| Type | String Context | Offset |
|
||
|---|---|---|
|
||
| Stern Insider Connected login | `Stern Insider Connected™ QR code.` | `0x25a7dba` |
|
||
| Connected Login QR | `Connected™ Login QR code.` | `0x25a7e99` |
|
||
| WiFi QR Code | `Scan WiFi QR Code` | `0x25a8360` |
|
||
| Quick Registration | `Connectivity/QrCodes/quick_registration_qr_code` | `0x25e1cf8` |
|
||
| Support | `Connectivity/QrCodes/support` | `0x25dc7e8` |
|
||
| Tech Support | `SCAN THIS QR CODE TO REACH OUR TECH SUPPORT TEAM` | `0x25dc231` |
|
||
|
||
## QR Code Scanning — Hardware Architecture
|
||
|
||
### Physical Components
|
||
|
||
The QR scanner system consists of:
|
||
|
||
1. **Scanner module** — A standalone 2D barcode scan engine (OEM part `part:520-9865-00` at `0x25b8c20`). The specific module model (Zebra, Honeywell, Newland, etc.) is not identifiable from strings; the firmware is a thin bridge without scanner-brand identifiers.
|
||
2. **Node4 bridge board** — A `node4` SPIKE-3 nodebus peripheral with dual firmware options:
|
||
- `node4-LPC812-1_33_0.hex` (LPC812, Cortex-M0+, 12 KB decoded)
|
||
- `node4-LPC1124_303-1_33_0.hex` (LPC1124, Cortex-M0+, 14 KB decoded)
|
||
3. **Connections**:
|
||
- Ribbon cable from scanner module to node4 board
|
||
- RJ45 nodebus cable from node4 to the game system
|
||
4. **GPIO antenna switch**: Two RF antennas on `gpiochip1` lines 3 (`ant1`) and 7 (`ant2`), controlled via `libgpiod.so.2`
|
||
|
||
### Serial Interface
|
||
|
||
The game communicates with the scanner module via **serial UART**:
|
||
|
||
| Path | Selection Logic | Offset |
|
||
|---|---|---|
|
||
| `/dev/ttyAMA2` | Default (kernel release byte != '5') | `0x25e9468` |
|
||
| `/dev/ttyAMA5` | Kernel release byte == '5' | `0x25e9478` |
|
||
|
||
Selection function at VA `0x94b8b0`: Uses `uname()` to check a kernel release byte, compares to `0x35` (`'5'`), selects ttyAMA5 on match, ttyAMA2 otherwise.
|
||
|
||
### Serial Configuration (VA `0x92d350`)
|
||
|
||
- **Open**: `open(path, O_RDWR | O_NOCTTY)`
|
||
- **Termios2**: Uses `TCGETS2` (ioctl `0x541e`) / `TCSETS2` (ioctl `0x541f`) — `struct termios2` for raw baud rates
|
||
- **Data bits**: 8 data bits, no parity
|
||
- **Stop bits**: 1 stop bit (configurable to 2 via `config[5] == 2`)
|
||
- **Local mode**: `CLOCAL | CREAD` (`0x880`)
|
||
- **Baud rate**: Configurable via 4-entry table indexed by `config[4] - 5`; actual rates not extractable from static analysis (uses non-standard termios2 CBAUD encodings)
|
||
- **Flow control**: `tcflow(fd, TCOON)`, `tcflush(fd, TCIOFLUSH)`
|
||
- **Timeout**: 1000 ms via `tcdrain`
|
||
|
||
### Node4 Bridge Firmware
|
||
|
||
The `node4` firmware files are thin, simple firmware images (6-11 ARM Thumb function entries) that bridge between:
|
||
|
||
- **Scanner side**: UART connection to the scanner module (baud rate divisors suggest 57600 for LPC812, 9600/230400/38400 for LPC1124)
|
||
- **Nodebus side**: SPIKE-3 nodebus protocol with node address `0x04`
|
||
|
||
The firmware does **not** contain:
|
||
- Scanner decode libraries (zbar, quirc, etc.)
|
||
- Scanner brand identifiers or protocol tables
|
||
- Any human-readable strings at all
|
||
|
||
This confirms the scanner module is a pre-integrated 2D barcode engine that handles decode internally, and the node4 board is a thin UART-to-nodebus bridge.
|
||
|
||
## QR Scanner Protocol
|
||
|
||
### Bridge Protocol (VA `0x94b9d0`–`0x94bbfc`)
|
||
|
||
The game communicates with the bridge (and through it to the scanner) using a custom framed protocol:
|
||
|
||
- **Buffer size**: 256 bytes (`mov w2, #0x100`)
|
||
- **Frame format**: `STX` + escaped body (cmd, seq, payload, checksum) + `ETX`
|
||
- **STX**: `0x02` — start of frame
|
||
- **ETX**: `0x03` — end of frame, triggers message processing
|
||
- **ESC**: `0x1B` — escape byte; next byte has bit `0x80` set
|
||
- **Checksum**: `(-sum(body)) & 0xFF`, verified before dispatch
|
||
- **Valid commands**: `0x10` through `0x41` (checked via `sub w0, w2, #0x10; cmp w0, #0x31`)
|
||
- **Command 0x30**: Firmware CRC handler at VA `0x953fc0`
|
||
- **Error handling**: "bridge rx checksum error", "message overrun", "too many message", "bridge %s unknown command: 0x%02x"
|
||
|
||
### Scanner Status Register (16 states)
|
||
|
||
The game tracks scanner status via an enum/string table at `0x25b8a40`–`0x25b8c00`:
|
||
|
||
| Offset | String | Meaning |
|
||
|---|---|---|
|
||
| `0x25b8a40` | `QR SCANNER BACKLIGHT` | Backlight control command |
|
||
| `0x25b8a58` | `QR SCANNER STATUS READY` | Scanner is ready for a scan |
|
||
| `0x25b8a70` | `QR SCANNER STATUS STRING` | Text string decoded from QR |
|
||
| `0x25b8a90` | `QR SCANNER STATUS ENCODED DATA` | Raw binary encoded data received |
|
||
| `0x25b8ab0` | `QR SCANNER STATUS MISSED STRING` | A scan was started but no decode |
|
||
| `0x25b8ad0` | `QR SCANNER STATUS OVERRUN` | Buffer overrun condition |
|
||
| `0x25b8af0` | `QR SCANNER STATUS UNSUPPORTED_AP` | Unsupported access point (WiFi) |
|
||
| `0x25b8b18` | `QR SCANNER STATUS FIFO OVERRUN` | Hardware FIFO overrun |
|
||
| `0x25b8b38` | `QR SCANNER STATUS CONFIG` | Configuration change event |
|
||
| `0x25b8b58` | `QR SCANNER STATUS ERROR` | Generic error |
|
||
| `0x25b8b70` | `QR SCANNER STATUS ERR1` | Error code 1 |
|
||
| `0x25b8b88` | `QR SCANNER STATUS ERR2` | Error code 2 |
|
||
| `0x25b8ba0` | `QR SCANNER STATUS ERR3` | Error code 3 |
|
||
| `0x25b8bb8` | `QR SCANNER STATUS ERR4` | Error code 4 |
|
||
| `0x25b8bd0` | `QR SCANNER STATUS ERR5` | Error code 5 |
|
||
| `0x25b8be8` | `QR SCANNER STATUS ERR6` | Error code 6 |
|
||
| `0x25b8c00` | `QR SCANNER STATUS NO READER` | Scanner disconnected |
|
||
|
||
### GPIO Antenna Switch (VA `0x950260`)
|
||
|
||
The QR scanner has a **dual-antenna RF switch** controlled via `gpiochip1`:
|
||
|
||
| GPIO | Label | Function |
|
||
|---|---|---|
|
||
| Line 3 | `ant1` | Antenna 1 |
|
||
| Line 7 | `ant2` | Antenna 2 |
|
||
|
||
Control logic:
|
||
- `arg=0`: Both antennas off (low)
|
||
- `arg=1`: `ant1` high, `ant2` low
|
||
- `arg=2`: `ant2` high, `ant1` low
|
||
|
||
## QR Parsing Classes
|
||
|
||
### C++ Class Hierarchy
|
||
|
||
The game uses C++ classes for QR code parsing, identified from RTTI/vtable references at `0x25fe1c0`–`0x25fe2d0`:
|
||
|
||
| Class | Offset | Role |
|
||
|---|---|---|
|
||
| `QrOfflineParser` | `0x25fe1c0` | Parses offline/local QR codes |
|
||
| `NetworkQrParser` | `0x25fe218` | Parses network/connectivity QR codes |
|
||
| `QrOfflineListener` | `0x25fe2d0` | Listens for offline QR scan events |
|
||
| `NetworkDataInterface` | `0x25fe1d8` | Base interface for network data |
|
||
| `CommandInterface` | `0x25fe1f0` | Base interface for commands |
|
||
| `NetworkData` | `0x25fe208` | Network data container |
|
||
|
||
### QR Code Format: `REG:T:`
|
||
|
||
The game uses a **proprietary QR code data format** identified by the prefix `REG:T:` at `0x25dbe30`:
|
||
|
||
- `REG:T:WPA` (offset `0x25dbe30`) — WiFi configuration QR code
|
||
- `REG:T:ETH` (offset `0x25dbe40`) — Ethernet/machine registration QR code
|
||
|
||
The format extends `REG:T:{TYPE}:{key}:{value}:{key}:{value}:...` with fields parsed programmatically.
|
||
|
||
### WiFi QR Data Flow
|
||
|
||
When a `REG:T:WPA` QR code is scanned:
|
||
|
||
1. `NetworkQrParser` extracts SSID, PSK, and encryption type
|
||
2. Validation: `"Not a valid WiFi QR code"` (`0x25a7200`)
|
||
3. Game builds `wpa_supplicant` config block:
|
||
```
|
||
ssid="%s"
|
||
scan_ssid=1
|
||
key_mgmt=%s (WPA-PSK)
|
||
pairwise=%s (TKIP or "CCMP TKIP")
|
||
group=%s
|
||
psk=%s
|
||
```
|
||
4. Writes to `/etc/wpa_supplicant.conf` (`0x25dfd68`)
|
||
5. Controls WiFi via `wpa_supplicant` control interface:
|
||
- `ADD_NETWORK` (`0x25d5688`)
|
||
- `SET_NETWORK` (`0x25d5808`)
|
||
- `ENABLE_NETWORK %s` (`0x25d5780`)
|
||
- `CTRL-EVENT-CONNECTED` (`0x25d57e8`)
|
||
- `CTRL-EVENT-DISCONNECTED` (`0x25d57e8`)
|
||
6. Control socket: `/var/run/wpa_supplicant/wlan0` (`0x25d5708`)
|
||
7. Also uses `/usr/sbin/wpa_cli status` (`0x25e26b8`)
|
||
|
||
### Stern Insider Connected QR Data Flow
|
||
|
||
When a Stern Insider Connected login QR code is scanned:
|
||
|
||
1. `QrOfflineParser` extracts user UUID from QR code
|
||
2. Flow: `QERT_SCANNED_USER_ACCOUNT` (`0x25dedd0`) → `ScannedUserAccountUUID` (`0x25dd568`) → `AuthenticatePlayer` (`0x25dd590`)
|
||
3. Player UUID is sent to backend via `PLAYER_AUTHENTICATE` (`0x25ecf18`)
|
||
4. Audit counters track results:
|
||
- `AUD_CONNECTIVITY_USERS_SCANNED` (`0x2594d60`)
|
||
- `AUD_CONNECTIVITY_USERS_JOINED` (`0x2594d80`)
|
||
- `AUD_CONNECTIVITY_BAD_QR_SCANS` (`0x2594ea8`)
|
||
- `AUD_CONNECTIVITY_BAD_USER_SCANS` (`0x2594e88`)
|
||
|
||
## Exploit Surface Analysis
|
||
|
||
### High Priority Targets
|
||
|
||
#### 1. `REG:T:WPA` → wpa_supplicant Command Injection
|
||
|
||
**Risk**: HIGH. The QR code content is parsed and passed to `wpa_supplicant` control interface commands (`ADD_NETWORK`, `SET_NETWORK`, `ENABLE_NETWORK`). If the SSID or PSK fields are not properly sanitized, an attacker could:
|
||
|
||
- Inject arbitrary `wpa_cli` or `wpa_supplicant` control interface commands
|
||
- Write to `/etc/wpa_supplicant.conf` with crafted content
|
||
- Potentially execute shell commands via the control interface
|
||
|
||
**Evidence**: The game uses `wpa_cli` at `/usr/sbin/wpa_cli status` (`0x25e26b8`). The control socket at `/var/run/wpa_supplicant/wlan0` (`0x25d5708`) accepts textual commands. SSID and PSK are inserted into format strings (`ssid="%s"`, `psk="%s"`) — if these use `sprintf`/`snprintf` without length limits, buffer overflow is possible.
|
||
|
||
#### 2. Serial Bridge Buffer Handling
|
||
|
||
**Risk**: MEDIUM-HIGH. The bridge protocol uses a **256-byte buffer** with a **1000 ms timeout**. The frame format uses STX/ETX/ESC framing with checksum. Potential issues:
|
||
|
||
- Buffer overflow if a message larger than 256 bytes is sent (the `read()` call reads up to 256 bytes, but the parser accumulates across multiple reads)
|
||
- Escape sequence mishandling (ESC `0x1B` sets bit 0x80 on next byte — crafted sequences could cause state confusion)
|
||
- Checksum bypass (the checksum is a simple sum complement)
|
||
|
||
#### 3. RapidJSON Parsing of QR Content
|
||
|
||
**Risk**: MEDIUM. The game uses **RapidJSON** library to parse QR-related data. Failure messages:
|
||
|
||
- `Failed to parse JSON.` (`0x259e9e0`)
|
||
- `INVALID JSON: expected "achievement_descriptors"` (`0x25dff48`)
|
||
- `INVALID JSON: expected "machine"` (`0x25e0088`)
|
||
- `INVALID JSON: failed to parse "machine"` (`0x25e00b0`)
|
||
|
||
RapidJSON assertion failures at `0x25d6348`–`0x25d6f20` (internal type checks). If assertions are compiled in (debug build), malformed JSON can crash the process. If assertions are compiled out, type confusion bugs may be exploitable.
|
||
|
||
#### 4. `qrCodeText` Buffer Handling
|
||
|
||
**Risk**: MEDIUM. The `qrCodeText` field is a raw string field that gets encoded into QR code data. If the text is used in `sprintf`/`snprintf` for display or file path construction without proper bounds checking, it could be a buffer overflow vector. QR codes are saved to `/connectivity/qr_code_storage/%d.bmp` using a numeric index — if the index is attacker-controlled, format string injection via `%d` is possible.
|
||
|
||
#### 5. Nodebus Secure Protocol
|
||
|
||
**Risk**: MEDIUM. The netbridge emulator (`netbridge_emu.py`) documents that secure nodebus requests (command `0x11`) use XOR encryption with session key rotation when `wire_address & 0xC0 == 0xC0`. If the encryption is weak or the session key derivation is predictable, a physical attacker with nodebus access could forge QR scan results.
|
||
|
||
### Medium Priority Targets
|
||
|
||
#### 6. GPIO Antenna Bypass
|
||
|
||
The dual-antenna system uses GPIO lines 3 and 7 on `gpiochip1`. If the antenna selection logic can be influenced by QR scan data, an attacker could potentially read from or interfere with the RF path.
|
||
|
||
#### 7. Audit Counter Manipulation
|
||
|
||
Audit counters (`AUD_CONNECTIVITY_BAD_QR_SCANS`, `AUD_CONNECTIVITY_USERS_SCANNED`, etc.) are tracked in shared memory or audit logs. If the QR parser crashes before incrementing error counters, brute-force scanning of QR codes could go undetected.
|
||
|
||
#### 8. Node4 Firmware Update Path
|
||
|
||
The `node4` bridge board has an LPC812/LPC1124 MCU that can be firmware-updated over the nodebus. If the update path is triggered by a crafted nodebus message, an attacker could flash malicious firmware that intercepts or modifies QR scan data.
|
||
|
||
### Low Priority / Design Notes
|
||
|
||
#### 9. `/tmp/qrx_.bmp` Race Condition
|
||
|
||
The QR code BMP is written to `/tmp/qrx_.bmp` — a predictable path in a world-writable directory. A local attacker could replace the QR code image between generation and display, but this requires local code execution on the Raspberry Pi.
|
||
|
||
#### 10. Pre-Generated QR Code Assets
|
||
|
||
The game includes pre-generated QR code images:
|
||
- `assets/nuk/images/Connectivity/QrCodes/quick_registration_qr_code.png`
|
||
- `assets/nuk/images/Connectivity/Icons/ScanQR/ScanQR.png`
|
||
|
||
These are imported into Godot but have **no script or scene references** — they are orphaned assets. The `quick_registration_qr_code.png` is a static QR code that may encode a fixed URL or machine identifier.
|
||
|
||
## Audit Counter Strings
|
||
|
||
| Offset | String | Purpose |
|
||
|---|---|---|
|
||
| `0x2594d60` | `AUD_CONNECTIVITY_USERS_SCANNED` | Users scanned via QR |
|
||
| `0x2594d80` | `AUD_CONNECTIVITY_USERS_JOINED` | Users joined via QR |
|
||
| `0x2594e88` | `AUD_CONNECTIVITY_BAD_USER_SCANS` | Failed user QR scans |
|
||
| `0x2594ea8` | `AUD_CONNECTIVITY_BAD_QR_SCANS` | Failed QR scans overall |
|
||
| `0x2594ec8` | `AUD_CONNECTIVITY_NET_CONNECTION_BAD_ACTION` | Bad network action |
|
||
| `0x25964b0` | `AUD_RULE_AREA_DISCOVER_POKEMON_SCAN_STARTED` | In-game scan started |
|
||
| `0x25964e0` | `AUD_RULE_AREA_DISCOVER_POKEMON_SCANNED` | In-game scan completed |
|
||
| `0x2596508` | `AUD_RULE_AREA_DISCOVER_POKEMON_SCAN_FAILED` | In-game scan failed |
|
||
|
||
## Godot UI Classes
|
||
|
||
| Class Name | Offset | Role |
|
||
|---|---|---|
|
||
| `NetPlayQrCode` | `0x25db058` | QR code display in network play |
|
||
| `NetWrongQrOverlay` | `0x25d9d20` | Error overlay for invalid QR |
|
||
| `MenuPageQrAdjustments` | `0x25ff0e8` | Menu page for QR adjustments |
|
||
| `QrRC` | `0x280770f` | QR resource class (abbreviated) |
|
||
|
||
## Diagnostic Messages
|
||
|
||
| Offset | String |
|
||
|---|---|
|
||
| `0x25dd3e8` | `Check QR scanner RJ45 nodebus cable` |
|
||
| `0x25dd410` | `Check QR scanner ribbon cable` |
|
||
| `0x25a85e0` | `Pull Interlock Switch To Power QR Scanner` |
|
||
| `0x25a5528` | `This login QR code is no longer valid` |
|
||
| `0x25a5578` | `This machine is not registered with Insider Connected` |
|
||
|
||
## Key Differences from conagent
|
||
|
||
The QR code system is **entirely separate** from `conagent`:
|
||
|
||
| Aspect | conagent | QR Scanner (game binary) |
|
||
|---|---|---|
|
||
| Binary | `/games/pokemon_pro/conagent` | `/games/pokemon_pro/game` |
|
||
| Role | Backend connectivity agent | Main game process |
|
||
| QR code gen | None | Uses `qrcodegen` library |
|
||
| QR code scan | None | Via hardware scanner + node4 bridge |
|
||
| WiFi config | No | Yes, via `wpa_supplicant` |
|
||
| User auth | API token/device auth | QR-based player UUID scan |
|
||
|
||
## Follow-up Targets
|
||
|
||
1. **Binary-level analysis**: Use Ghidra to decompile:
|
||
- `QrOfflineParser::parse` (find via vtable xref from `0x25fe1c0`)
|
||
- `NetworkQrParser::parse` (find via vtable xref from `0x25fe218`)
|
||
- The `REG:T:WPA` string splitting and SSID/PSK extraction code
|
||
- The `wpa_cli` control interface invocation site
|
||
- The serial bridge read/parse loop at VA `0x94b9d0`
|
||
|
||
2. **Dynamic testing**: If hardware or emulation is available:
|
||
- Fuzz the serial bridge protocol with crafted STX/ETX/ESC frames
|
||
- Test `REG:T:WPA` with SSID/PSK containing shell metacharacters
|
||
- Test `REG:T:WPA` with oversized SSID (>256 bytes) for buffer overflow
|
||
- Test RapidJSON parsing with malformed JSON in QR code content
|
||
|
||
3. **Node4 firmware analysis**: Disassemble `node4-LPC812-1_33_0.hex` and `node4-LPC1124_303-1_33_0.hex` as ARM Thumb to:
|
||
- Recover the UART baud rate configuration
|
||
- Understand the scanner module command passthrough protocol
|
||
- Verify the firmware update mechanism
|
||
|
||
4. **Physical inspection**: If hardware is available:
|
||
- Identify the scanner module model from the PCB
|
||
- Check if the scanner module has its own debug/firmware update port
|
||
- Verify the baud rate and protocol between node4 MCU and scanner module
|
||
|
||
5. **Nodebus security audit**: Verify the XOR encryption scheme for secure nodebus commands and assess whether it can be bypassed to inject forged QR scan results.
|