INDEPENTEST · ANDROID R&D DOCS ONLY — NO FIRMWARE, NO PACs
Field manual — unlock & root

Cubot
KingKong ES 3

Unisoc T615 (UMS9230_6h10) · UFS · A/B slots

CVE-2022-38694 exec_addr 0x65015f08 BUILD F071_V16_20260309
GUÍA EN ESPAÑOL →

Wipes the device. Back up first. Verified only on the build stamped above — re-verify before using on any other build.

Difficulty
Medium / Hard
Host OS
Linux only
USB
2.0, direct — no hubs
Recovery
BROM always answers

The boot chain — and where each hack lands

One exploit, two separate interventions. The unlock (Steps 1–5) neuters the lock check inside splloader. Root (Step 6) is a later, unrelated patch to Android's own init_boot image.

BROM 1782:4d00 splloader lock check uboot Android boot done CVE-2022-38694 exec_addr 0x65015f08 → FDL1/FDL2 patch lock check Steps 1–5 · unlock Magisk patches init_boot.img Step 6 · root
The exploit only ever touches the BROM→splloader hop; root is a completely separate, later patch to Android's own init_boot image — unlocking does not require rooting, and rooting requires an already-unlocked bootloader.

Cast of characters

TermWhat it does
BROMFactory boot ROM, burned into the chip — never erasable. Your panic button if anything goes wrong.
FDL1 / FDL2Helper programs smuggled past BROM. FDL1 wakes RAM; FDL2 can read, write, or erase any flash partition.
spd_dump verbsr read · w write · e erase · read_part raw read · reset reboot
splloaderFirst stage of the normal boot chain. Holds the bootloader-lock check that Steps 1–5 patch.
ubootThe regular bootloader (gives you fastboot). Swapped for a cooperative copy mid-unlock, restored after.
miscdataSmall hidden partition holding the unlock flag.
prodnv / nvitem / l_fixnvFactory radio calibration (IMEI, Wi-Fi/BT MAC). NEVER READ/WRITE/ERASE

The guide

00

Set up the tools

Download the unlock package from Releasescubot_es3_unlock_package_amd64.zip for a normal PC (x86-64), cubot_es3_unlock_package_arm64.zip for ARM64 machines — unzip, and build:

cd cubot_es3_unlock_package make gcc gen_spl-unlock.c -o gen_spl-unlock gcc chsize.c -o chsize

Verify you built the right thing — both checks must pass:

./spd_dump --help # must NOT list a "baudrate" command grep reopen_port common.c # must find the reconnect fix

You'll also need Android's adb and fastboot for Step 6 — install them now so you're not stuck mid-guide:

sudo apt install android-tools-adb android-tools-fastboot adb --version && fastboot --version

Where every file comes from

spd_dump, gen_spl-unlock, chsizeBuilt from the package source just now
fdl1-dl.bin, fdl2-dl.bin, fdl2-cboot.bin, misc-wipe.bin, custom_exec_no_verify_65015f08.binShip ready-made inside the package — don't rename or move them
splloader.bin, uboot.binYou dump them off your own phone in Step 1
spl-unlock.bingen_spl-unlock creates it from your dumped splloader.bin — the lock check, neutered
u-boot-spl-16k-sign.bin, uboot_bak.binYour renamed Step 1 backups — restore the phone in Step 5
init_boot.imgNot in the package — extracted from your own stock PAC, below
magisk_patched-*.imgThe Magisk app creates it on the phone (Step 6)

Getting init_boot.img out of the stock PAC — a .pac file is Unisoc's all-in-one firmware container; you need exactly one image out of it.

  1. Download the official firmware zip for the build stamped at the top of this page from Cubot's support page → KingKong ES 3 → CUBOT_KINGKONG_ES_3_F071_V16_20260309. Unzip it — inside is the .pac file (~3 GB).
  2. Extract the PAC on Linux:
    git clone https://github.com/bismoy-bot/PAC-Extractor cd PAC-Extractor python3 extractor.py /path/to/your/firmware.pac extracted
  3. Inside extracted/, find init_boot.img (rename from init_boot_a.img if needed) and copy it into the package folder.

Stay inside the package folder the whole time — dumps land in the current directory.

01

Back up & patch your loaders

Enter BROM: power off → hold Volume Down → plug USB (or press Power) → keep holding. If 1782:4d00 doesn't appear, retry with Volume Up. Confirm:

lsusb | grep -i '1782:4d00'

Dump splloader + uboot off the phone:

spd_dump --wait 300 exec_addr 0x65015f08 fdl fdl1-dl.bin 0x65000800 fdl fdl2-dl.bin 0x9efffe00 exec r splloader r uboot e splloader e splloader_bak reset

Opens BROM with the exploit → loads FDL1+FDL2 → reads splloader/uboot into files → erases the splloader slots (rewritten in Step 5) → reboots.

Wait for the reset. find port failed → close and re-run — do not continue past that error.

Generate the unlock payload, resize + stash the backups:

gen_spl-unlock splloader.bin chsize uboot.bin mv splloader.bin u-boot-spl-16k-sign.bin mv uboot.bin uboot_bak.bin
02

Write the working FDL2

Temporarily replaces the uboot partition with fdl2-cboot.bin, a cooperative copy of FDL2 — stock uboot would refuse to take part in what comes next. Your original returns in Step 5.

Re-enter BROM (Step 1), then:

spd_dump --wait 300 exec_addr 0x65015f08 fdl fdl1-dl.bin 0x65000800 fdl fdl2-dl.bin 0x9efffe00 exec w uboot fdl2-cboot.bin reset

Wait ~10 seconds after the reset.

03

Run the unlock

Sends the neutered spl-unlock.bin up through BROM and runs it — the mere act of it running flips the unlock flag in miscdata. That flag flip IS the unlock; there's no "restore" dance after.

Re-enter BROM, then:

spd_dump exec_addr 0x65015f08 fdl spl-unlock.bin 0x65000800

What you'll see, and why it's all good:

  • 🔄 CHECK_BAUD FAIL — expected. The patched build reconnects by itself.
  • CHECK_BAUD FDL1BSL_REP_VER: "SPRD3"CMD_CONNECT FDL1this IS the success signal.
  • ⏱️ timeout reached after that — this is what you want, not an error. Don't re-run; move to Step 4. (Only re-run if you never saw CMD_CONNECT FDL1.)
04

Verify the unlock

Don't trust what the tool printed — read the flag itself out of miscdata:

spd_dump exec_addr 0x65015f08 fdl fdl1-dl.bin 0x65000800 fdl fdl2-dl.bin 0x9efffe00 exec verbose 2 read_part miscdata 8192 64 m.bin reset

Check m.bin with xxd m.bin:

64 zero bytes → still locked, repeat Step 3 32-byte string + two 16-byte hashes → unlocked

A trailing timeout here is normal.

05

Restore & wipe

Puts the phone back together — writes your original splloader/uboot backups back, and writes misc-wipe.bin to force the factory reset an unlock requires.

spd_dump exec_addr 0x65015f08 fdl fdl1-dl.bin 0x65000800 fdl fdl2-dl.bin 0x9efffe00 exec r boot w splloader u-boot-spl-16k-sign.bin w uboot uboot_bak.bin w misc misc-wipe.bin reset

Let the phone factory-reset and boot. Orange/unlocked warning screen = success.

06

Root with Magisk

The bootloader is unlocked — root is just Magisk patching init_boot.img and flashing the patched copy, done in fastbootd (userspace fastboot), not the plain bootloader.

Install the Magisk app on the phone if you haven't already. Boot Android → Settings → About Phone → tap Build Number ×7 → Developer Options → USB debugging. Then:

adb push init_boot.img /sdcard/Download/

In the Magisk app: Install → Select and Patch a File → init_boot.img, pull the patched image back, and flash it in fastbootd:

adb pull /sdcard/Download/magisk_patched-*.img . mv magisk_patched-*.img init_boot_a.img adb reboot fastboot # goes STRAIGHT to fastbootd — skips the bootloader fastboot devices # must show "<serial> fastbootd" — confirm before flashing fastboot flash init_boot_a init_boot_a.img fastboot reboot

Open Magisk → root active. Done — unlocked and rooted.

Troubleshooting

SymptomFix
LIBUSB_ERROR_BUSYsudo systemctl stop ModemManager, replug
LIBUSB_ERROR_NO_DEVICEStart spd_dump first, then plug the phone
find port failedClose and re-run the same command
Connection drops / won't detectMake sure you're on USB 2.0
Two CHECK_BAUD FAIL → device removedYour build is missing the reconnect fix — rebuild (common.c must contain reopen_port)
Boot loop / soft brickBROM (Step 1) always answers — reflash stock firmware, redo the guide
In spd_dumpNEVER run repartition, erase_all, or ufs repart/rawerase/setattr — they truncate the GPT

More