The content below documents my exploration and reproduction of bootrom vulnerabilities in the Kirin 990 5G processor. Some operations involved third-party tools or AI assistance. Since I am not a professional researcher in this field, the content may contain unvalidated assumptions or omissions. If you plan to reproduce the vulnerability based on this document, please verify all details carefully to avoid misguidance.
The exploitation of bootrom vulnerabilities in the Kirin 990 5G is primarily based on the "check mate30" vulnerability chain discovered by the TASZK team (Black Hat USA 2021) and the Pangu team (Checkmate Mate30). However, publicly available practical details remain limited.
Links to original research documents:
- TASZK Team:(https://i.blackhat.com/USA21/Wednesday-Handouts/US-21-Komaromy-How-To-Tame-Your-Unicorn-wp.pdf)
- Pangu Team (Checkmate Mate30): checkm30
All boot firmware of the Kirin 990 5G (except bootrom) is stored in encrypted form. Permission handover between boot stages requires:
- The previous-stage bootloader invokes a security module to decrypt the next-stage firmware.
- A signature verification is performed on the decrypted content.
- If verification passes, execution rights are transferred to the next-stage bootloader.
The Kirin 990’s firmware decryption relies on the crypto engine (hardware decryption module) within the TEE (Trusted Execution Environment). The decryption key is stored in the chip’s EFUSE (unique per chip) and is only directly accessible by the TEE. Boot stages (e.g., bootrom, xloader) do not store the key—they only pass the encrypted firmware to the TEE and receive the decrypted plaintext firmware.
During the boot process, the loading address of each firmware stage is fixed, as shown below:
| Firmware Name | Boot Stage | Storage/Running Address | Description |
|---|---|---|---|
| XLOADER | Loaded by bootrom | 0x00022000 (SRAM) | Address remains the same before/after decryption |
| FASTBOOT | Xloader download phase | 0x1A400000 (DDR) | Temporary storage address only |
| FASTBOOT | After main CPU startup (bootloader mode) | 0x3A400000 (DDR) | Actual running address |
| BL2 | Loaded by xloader | 0x1E400000 (DDR) | New stage in Kirin 990 for pre-verification |
| UCE | Loaded by xloader | 0x60000000 (DDR) | Post-xloader stage, responsible for DDR initialization |
Additional note on FASTBOOT loading address:
- During the xloader download phase, FASTBOOT is stored at 0x1A400000 (DDR).
- After xloader loads BL2 and starts the main CPU to enter bootloader mode, FASTBOOT runs at 0x3A400000.
- Difference between retail and engineering firmware: Retail firmware lacks the function symbol table at the end of FASTBOOT; other logic (e.g., decryption, loading流程) is identical.
Practical verification shows that the decryption phase in the boot process cannot be bypassed:
- Even if bootrom vulnerabilities are used to bypass xloader’s signature verification, uploading pre-decrypted plaintext xloader will still cause runtime failures due to "decryption inconsistency."
- It is inferred that subsequent stages (BL2, FASTBOOT, UCE) have the same limitation—direct loading of plaintext firmware is currently not feasible.
Compatibility note for firmware decryption:
Since the AES key of the crypto engine is burned into EFUSE (unique per chip), the Kirin 990 theoretically supports decryption of all firmware versions (including HarmonyOS 4.x) as long as xloader can normally call TEE interfaces. This assumes no fundamental changes to the firmware’s encrypted format (e.g., VRL header structure).
Due to the full encryption of Kirin 990 5G firmware, the traditional exploitation method for older devices ("tamper firmware + bypass verification") is no longer applicable. Instead, exploitation relies on "memory manipulation + patch injection", with the core workflow as follows:
- Send encrypted firmware to the device → The device decrypts it via TEE to obtain plaintext firmware.
- Use bootrom vulnerabilities (e.g., header resend, tail chunk increment) to gain "arbitrary address write" capability.
- Based on the known firmware loading address, send binary patches to the corresponding firmware location in DDR memory.
- Trigger execution of the tampered firmware to achieve goals such as signature verification bypass or bootloader unlocking.
Below are key issues involved in the exploitation process (some are unvalidated assumptions requiring further verification):
Use publicly disclosed bootrom vulnerabilities (e.g., header resend, tail chunk increment) to bypass download address restrictions. By overwriting the return value (e.g., LR register) of the usb/download_xloader function, you can:
- Bypass signature verification.
- Dump plaintext firmware via blind payload decryption.
Key memory addresses (for verification):
- Initial stack pointer (SRAM stack top): 0x000673FC
- Possible LR register positions: 0x673FC - 0x34 = 0x673C8 or 0x673C8 + 36 = 0x673EC (verify independently).
Public references for "bypass signature verification to load payload" already exist and are not elaborated here. More efficient firmware decryption methods than "blind payload" exist, but their compatibility may be version-dependent and require further verification.
In addition to blind payloads, efficient decryption and dumping can be achieved by patching the 0xCD inquiry command of xloader:
- The original 0xCD command only returns 1 byte of specific data. After patching, it can read 512 bytes of data from a specified memory address (including the bootrom segment) in one go.
- Patched xloader supports reading from UFS and mapping content to a specified DDR address. The dumped firmware is TEE-decrypted plaintext (including GPT partition tables, xloader, and other boot firmware).
- Dumping workflow:
- Trigger UFS reading via xloader_payload → Map plaintext firmware to DDR.
- Use an inquiry script (e.g., inquiry.py) to read and save plaintext from DDR.
After obtaining plaintext firmware, load it into IDA with the following parameters to ensure address alignment with the actual device:
| Firmware Name | IDA Loading Parameters | Description |
|---|---|---|
| Bootrom | 32-bit ARM little-endian, start address 0x0 | Only the ROM region (0x00000000-0x00020000) is read-only |
| Xloader | 32-bit ARM little-endian, start address 0x22000 | Contains a 4096-byte VRL header (automatically recognized by IDA) |
| FASTBOOT | 64-bit ARM little-endian, start address 0x3A400000 | Actual running address after main CPU startup |
-
Reverse Engineering Targets:
- Modify xloader’s signature verification logic.
- Modify FASTBOOT’s
fblock/userlock(for bootloader unlocking) anddts_init(for screen activation).
-
Patch Extraction:
- Export binary data from the modified location in IDA.
- Pad the patch to 16-byte alignment (fill with 0x00 if insufficient) to match DDR memory access granularity.
-
Injection Logic:
- Calculate the patch target address based on the "mapping relationship between IDA start address and actual memory address."
- Use bootrom vulnerabilities to write the patch to the corresponding DDR address (e.g., xloader’s decrypted base address is 0x22000—directly overflow to write the target location).
| File Name | Description |
|---|---|
| xloader_complete_dump.bin | Plaintext xloader firmware |
| xloader_payload.bin | Xloader payload for decryption and dumping (encrypted, contains exploit logic) |
| load.py | Sends xloader_payload to the device and triggers execution; use inquiry.py to dump memory afterward |
| inquiry.py | Dumps memory from a specified DDR address (based on the modified 0xCD command) |
| bootrom_complete_dump.bin | Plaintext bootrom of Kirin 990 5G |
| uce_complete_dump.bin | Plaintext UCE firmware (usability unknown) |
| uce_file.bin | Encrypted UCE firmware (usability unknown) |
| elspfastboot_complete_dump.bin | Plaintext FASTBOOT for ELSP engineering devices (contains OEM unlock function; try for permanent userlock unlocking) |
| liofastbootdec.bin | Plaintext FASTBOOT for LIO engineering devices |
| IDA-related files | Contains symbol tables for 2 engineering FASTBOOT firmwares and IDA import scripts |
| imagorin | Original temporary bootloader firmware for LIO/ELSP models (encrypted, unmodified) |
-
Requirement Python >= 3.13.0
-
Physical Operation Risk:
Shorting the Test Point (located on the back of the Kirin 990 motherboard with a 0.1mm pitch) requires a microscope. Improper operation may damage the PCB. -
Legal Risk:
Firmware decryption and modification may violate the Regulations on the Protection of Computer Software. These files are for technical research on personally owned devices only—unauthorized device operations are strictly prohibited.
This project is licensed under the MIT License—see the LICENSE file for details