
UNISOC BootROM/FDL flasher for macOS: patched spd_dump with CVE-2022-38694 exec_addr2, protocol reference, partition rules, backup verification (UMS9621)
English | 简体中文
macOS port of the UNISOC (Spreadtrum) BootROM/FDL flashing toolchain. Based on
ilyakurdyukov/spreadtrum_flash
(MIT), with exec_addr2 — the CVE-2022-38694 signature-verification bypass of
the closed-source spd_dump — reimplemented, completing the full chain on
macOS (arm64 + libusb):
BootROM → CVE out-of-bounds write → FDL1 → FDL2 → GPT parse → partition R/W → reset
Verified on UMS9621 (T158), Android 13, kernel 5.15, GKI (init_boot) layout. Address-compatible with the UMS9620 family; other SoCs: see Porting.
Dependencies: Xcode CLT, brew install libusb.
./scripts/build-macos.sh # produces ./spd_dump
With the device powered off and disconnected, hold Reset (or the
model-specific key combination) while plugging in USB; the device enumerates
as 1782:4d00. The BootROM answers only for roughly 20 seconds after
enumeration, then goes silent (still enumerated). Automation must trigger on
the absent→present edge (see scripts/runner.sh).
./spd_dump --wait 3 exec_addr2 0x65017f08 verbose 1 \
fdl fdl1-dl.bin 0x65000800 \
fdl fdl2-dl.bin 0xbefffe00 \
disable_transcode partition_list gpt.xml
| Option | Description |
|---|---|
exec_addr2 <addr> | CVE bypass; auto-loads custom_exec_no_verify_<addr>.bin; |
python3 scripts/backup_gen.py gpt.xml backup/ --img-dir data/
./spd_dump --wait 3 verbose 0 disable_transcode $(cat backup_args.txt)
backup_gen.py generates the read_part sequence from the GPT (resume-safe;
GPT size unit is MB) and patches vbmeta* images offline with AVB flags=3
(equivalent to verity 0).
python3 scripts/flash_gen.py gpt.xml data/ flash_ops.txt
N=$(grep -c 'write_part\|erase_part' flash_ops.txt)
{ yes yes | head -n $N; sleep 3600; } | ./spd_dump --wait 3 verbose 0 \
disable_transcode $(cat flash_ops.txt | tr '\n' ' ')
flash_gen.py applies the partition rules (runtimenv → erase, fixnv/calinv
skipped, slotless aliases deduplicated by mtime) and appends
erase_part userdata + reset.
Details in docs/protocol-notes.md (Chinese):
verbose 1
terminates that loop early0x8A (DOWN_SIZE_ERROR) is also returned for: standalone downloads to
protected addresses, writes to runtimenv, oversized read blocksnr_fixnv1) hang the session;
rules in docs/partition-rules.md (Chinese)Cross-checking static partitions (dtb etc.) against known same-model images by md5 validates the read path end-to-end.
| Item | Source |
|---|---|
| fdl1/fdl2 load addresses | Model's pac firmware XML (extract via SPD Research Tool) |
| CVE blob & stack address | TomKing062/CVE-2022-38694 soc/<chip>/ |
| FDL images | Extracted from the model's stock firmware (DHTB-signed headers) |
src/Headless-device Magisk su pre-authorization: docs/headless-magisk-su.md (Chinese).
BootROM-level operations carry a brick risk; back up first. Provided AS IS.
fdl <file> <addr> | FDL image and SoC-specific SRAM load address |
disable_transcode | Must be sent once at the start of every new process (state persists across processes) |
| Check | Expected value |
|---|
| Size | Byte-exact match against GPT |
| boot / init_boot | ANDROID! @0 |
| vendor_boot | VNDRBOOT @0 |
| vbmeta family | AVB0 @0, flags @0x78 |
| splloader/trustos/uboot/fdl | DHTB @0 |
| super | gDla @4096 and @8192 (dual geometry copies), first 4K reserved zeros |
| NV | NV (0x4E56) @0 or @0x200 |