
CVE-2024-56426 Exynos9830 Bootrom Exploit - SM-G985F
[!CAUTION] The current key bundle and generated files are fusing-capable. Once a device has been fused, the eFuse change is irreversible and the device must continue to use boot images and key material that match the fused key. Using these files or flows is at your own risk because of the fusing behavior; all consequences remain the responsibility of the user running them. Verify the eFuse file, private keys, signed FWBL1, LK /
sboot.binimages, and target device before running any fusing flow.
| Path | Purpose |
|---|---|
bootLoaderFiles/ | Bootloader binaries, split bootloader parts, original images, decrypted images, and dump artifacts. |
bootromNotes/ | Boot ROM notes, flowcharts, and USB context offsets. |
exploit/ | Python tooling, exploit runner, split/merge scripts, payload build helper, and SoC data. |
exploit/extra/images/ | Working bootloader images consumed by the exploit flows. |
exploit/extra/payloads/ | Built payload binaries copied from external/payloads/. |
external/ | Payload sources, build Makefile, decompiled notes, shared key material, and helper tools. |
external/keys/exynos9830_crecker/ | Shared Exynos9830 / Exynos990 custom-key bundle used by the signed-loader flow. |
exynos990reverseEng/ | Exynos 990 reverse engineering project files. |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu
brew tap messense/macos-cross-toolchains
brew install aarch64-unknown-linux-gnu
python3 -m pip install -r requirements.txt
requirements.txt includes coloredlogs, cryptography, hexdump, libusb, pyusb, and pycryptodome.
On Windows, the BootROM USB device 04e8:1234 must use a WinUSB/libusb-compatible
driver before PyUSB can open it. See exploit/windows/README.md.
The repository includes a WinUSB driver package at
exploit/windows/Exynos_USB_Device.inf, with its matching catalog and certificate
import file in the same directory.
sboot.binpython3 exploit/split.py bootLoaderFiles/originalSboot_K/sboot.bin -o exploit/extra/images
The split script writes image parts and a split_manifest.json file into the output directory.
The LK image must use the ROM secure boot key 2 command IDs for the custom-key flow:
| Key 1 command | Value | Key 2 command | Value |
|---|---|---|---|
CMD_W_ROM_SEC_BOOT_KEY1 | 0x001 | CMD_W_ROM_SEC_BOOT_KEY2 | 0x016 |
CMD_W_USE_ROM_SEC_BOOT_KEY1 | 0x002 | CMD_W_USE_ROM_SEC_BOOT_KEY2 | 0x017 |
CMD_C_ROM_SEC_BOOT_KEY1 | 0x100 | CMD_C_ROM_SEC_BOOT_KEY2 | 0x114 |
CMD_R_USE_ROM_SEC_BOOT_KEY1 | 0x101 | CMD_R_USE_ROM_SEC_BOOT_KEY2 | 0x115 |
When applying the LK patch TSV inside the Ghidra project, the helper was called through Ghidra headless like this:
GHIDRA=/path/to/ghidra_12.0.4_PUBLIC
REPO=$(pwd)
"$GHIDRA/support/analyzeHeadless" "$REPO/exynos990reverseEng" exynos990 \
-process lk.bin \
-noanalysis \
-scriptPath "$REPO/external/ghidra" \
-postScript ApplyLkPatches.java "$REPO/external/ghidra/lk_985_selected_patches.tsv"
Embed the 32-byte eFuse key into lk.bin at offset 0x205008, replacing the stock key:
dd if=external/keys/exynos9830_crecker/crecker.efuse of=exploit/extra/images/lk.bin bs=1 seek=$((0x205008)) count=32 conv=notrunc
xxd -g1 -s $((0x205008)) -l 32 exploit/extra/images/lk.bin
python3 exploit/merge.py exploit/extra/images Exynos9830
The merge script writes sboot.bin in the current working directory.
Build the payload projects under external/payloads/ and copy the resulting binaries into exploit/extra/payloads/:
./exploit/build_payloads.sh
| Payload | Output path | Purpose |
|---|---|---|
mem.bin | exploit/extra/payloads/mem.bin | Boot ROM memory dump payload. |
loader.bin | exploit/extra/payloads/loader.bin | UFS path payload used by --ufs. |
Exynos990_boot_custom_key.bin | exploit/extra/payloads/Exynos990_boot_custom_key.bin | Custom-key signed-loader payload used by --signed. |
The UFS loader and custom-key payload embed a 32-byte efuse file at build time.
By default the Makefile reads external/keys/exynos9830_crecker/crecker.efuse;
override this with CUSTOM_KEY_EFUSE=/path/to/crecker.efuse when needed.
The preflight step run by exploit/exploit.py re-signs the SBoot image set in
exploit/extra/images/ in place before each signed run. No separate signed
output is kept. The signing step uses the intentionally tracked shared key
bundle under external/keys/exynos9830_crecker/.
Equivalent repo-root command for the complete image set:
python3 external/tools/sign_sboot_images.py \
--images-dir exploit/extra/images \
--keys-dir external/keys/exynos9830_crecker
This signs:
| Image | Key material used | Rollback revision |
|---|---|---|
fwbl1.img | BL1 private key + Stage2 TEE/REE pubkeys | 23 |
epbl.img | Stage2 TEE private key | 23 |
bl2.img | Stage2 REE private key | 23 |
lk.bin | Stage2 REE private key | 23 |
el3_mon.img | Stage2 TEE private key | 23 |
ldfw.img | Stage2 TEE private key, inner + outer | 23 |
tzsw.img | Stage2 TEE private key, inner + outer | 23 |
The batch signer passes decimal 23 for every image and does not reuse an
older rollback value already present in an existing footer.
epbl.img is re-encrypted first when needed, then signed over the final bytes.
ldfw.img and tzsw.img still need the external AVB flow if their AVB content
is meant to be refreshed.
The FWBL1-only command is: