
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:
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
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:
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:
python3 external/tools/sign_tool.py \
-i exploit/extra/images/fwbl1.img \
-o exploit/extra/images/fwbl1.img \
-k external/keys/exynos9830_crecker/crecker_private.pem \
-H external/keys/exynos9830_crecker/crecker.hmac \
-s 0x3000 \
-r 23 \
-ma 0x9830 \
-m 0x142 \
-e 11 \
-t external/keys/exynos9830_crecker/crecker_stage2_tee_pubkey.bin \
-re external/keys/exynos9830_crecker/crecker_stage2_ree_pubkey.bin
Short form when sign_tool.py, fwbl1.img, and the crecker_* files are in the current directory:
python3 sign_tool.py -i fwbl1.img -o fwbl1.img -k crecker_private.pem -H crecker.hmac -s 0x3000 -r 23 -ma 0x9830 -m 0x142 -e 11 -t crecker_stage2_tee_pubkey.bin -re crecker_stage2_ree_pubkey.bin
Run commands from the repository root unless noted otherwise.
The observed Exynos 9830 boot procedure is:
Note: The mem.bin dump payload can only be used when no working sboot is installed.
Send uh.bin over Heimdall to the bootloader:
heimdall flash --BOOTLOADER uh.bin
Run the dump flow:
python3 exploit/exploit.py --dump
Review the generated exynos990.bootrom.bin dump.
Portions of the Python recovery tooling in this repository were adapted from halal-beef/hubble.
That upstream project is published under the GNU GPL v2.0, and this repository keeps a GPL-2.0 license for compatibility. See LICENSE and NOTICE.md.
The Exynos990 custom-key payload under external/payloads/exynos990_boot_custom_key/ is based on the
boot-custom-key payload skeleton and control-flow idea from
VDavid003/exynos-usbdl, a fork of
frederic/exynos-usbdl. It has been substantially rewritten and
adapted for the Exynos9830 / Exynos990 GET_CONFIGURATION chain, and is not a verbatim copy of the upstream
payload. Because the referenced upstream project is licensed under the GNU GPL v3.0, this payload is kept
under GPL-3.0-only; see external/payloads/exynos990_boot_custom_key/LICENSE.
| 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 |
| 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. |
| 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 |
| Command | Mode | Default payload | Notes |
|---|
python3 exploit/exploit.py --ufs | UFS path | loader.bin | Starts the UFS payload flow. |
python3 exploit/exploit.py --signed | Signed Boot Chain | Exynos990_boot_custom_key.bin | Re-signs the SBoot image set, sends images. |
python3 exploit/exploit.py --dump | Boot ROM dump | mem.bin | Receives 0x20000 bytes into exynos990.bootrom.bin. |
| Step | Note |
|---|
| 1 | Enter download mode. |
| 2 | Create or update sboot.bin with exploit/merge.py when needed. |
| 3 | Use the signed custom-key flow to reach Crecker mode, an ODIN-style mode that accepts the target image flow. |
| 4 | Send the new sboot.bin through ODIN, Heimdall, or another compatible sender. |
| 5 | Run the UFS payload. |
| 6 | Optional: install CreckerRom for One UI 7 and Strong Integrity workflows. |
| 7 | Optional: lock the bootloader after the target setup is complete. |
| Step | Stage | Notes |
|---|
| 1 | BootROM | Initial ROM execution. |
| 2 | BL1 | Full handoff from BootROM. |
| 3 | EPBL | Full handoff from BL1. |
| 4 | EPBL | Sets up a minimal SMC handler. |
| 5 | BL2 | EPBL loads BL2. |
| 6 | BL2 | Partial handoff to BL2. |
| 7 | LK | BL2 uses EPBL to load LK, but LK does not immediately execute. |
| 8 | EL3 Monitor | BL2 uses EPBL to load EL3 Monitor. |
| 9 | EL3 Monitor | EPBL decrypts EL3 Monitor. |
| 10 | EL3 Monitor | Full handoff to EL3 Monitor. |
| 11 | EL3 Monitor | Initializes and sets up the extended SMC handler. |
| 12 | LK | Execution jumps to LK. |
| 13 | LK / EL3 Monitor | LK calls into the EL3 Monitor SMC handler to load TrustZone parts. |
| 14 | ODIN / custom target | Boot continues to ODIN or the configured target. |
| Part | Start | End |
|---|
fwbl1.img | 0x0 | 0x3000 |
epbl.img | 0x3000 | 0x16000 |
bl2.img | 0x16000 | 0x82000 |
lk.bin | 0xDB000 | 0x35B000 |
el3_mon.img | 0x35B000 | 0x39B000 |
| Stage | Load address |
|---|
BL1 | 0x02022000 |
EPBL | 0x02026000 |
BL2 | 0x15600000 |
LK | 0xE8000000 |
EL3_MONITOR | 0xBFE80000 |
_boot_device source ID | Boot source path |
|---|
1 | UFS path, shared UFS load flow. |
2 | eMMC/SDMMC init path, mmc_card_detect_and_init flow. |
3 | SDMMC/MMC device 0, mmc_read_blocks(0, ...). |
4 | USB load path. |
5 | SDMMC/MMC device 1, mmc_read_blocks(1, ...). |
6 | UFS alternate mode, same core UFS flow as 1 with a different mode flag. |
7 | Non-MMC/UFS/USB raw controller read path. |
0xB / 11 | USB fallback path, then same USB handler as 4. |
| Source ID | Value | Meaning |
|---|
1 | 0x20 | UFS |
2 | 0x14 | eMMC |
3 | 0x00 | SDMMC_CH2 |
4 / 0xB | 0x40 | USB |
| Credit | Contribution |
|---|
| Chimera Tool | First discovery of the exploit circa 2021-2022. Chimera provides advanced Exynos servicing capabilities across many devices, including capabilities based on this exploit. |
| CVE-2024-56426 | The CVE that this project is based on. |
| Christopher Wade | Reported CVE-2024-56426 to Samsung. |
| kethily-daniel | Provided access to the tool used for USB packet tracing and sample extraction. |
| BotchedRPR | Helped with the initial research and creation of carte2. |
| VDavid003 | Helped reverse engineer the PoC through packet dumps and personally tested on devices. |
| halal-beef / hubble | Provided initial USB packet dumps and analysis of the PoC during the research lifecycle, backend code used by the exploit script, and SoC layouts used by the split and merge scripts. |
| VDavid003 / exynos-usbdl | Provided the GPLv3 custom-key payload skeleton and Exynos USB download reference flow used as the basis for the Exynos990 custom-key payload. |
| R0rt1z2 | Helped with payload creation; some work was based on his project, kaeru. |
| AntiEngineer | Shared ARM knowledge, hints, and research support. |
| AA | Vulnerability inspiration and first use outside of Chimera. |