Reverse Engineering U-Boot gvsdupdate

Step-by-step reverse engineering of the proprietary gvsdupdate command found inside the Ingenic T23 SoC U-Boot firmware image.

While developing my custom Ingenic T23 SoC emulator, I needed to understand how U Boot processes automatic firmware updates from SD cards. First I extracted uboot.bin directly from the raw SPI NOR flash dump firmware_dump.bin. In this article, I document my step by step reverse engineering of the proprietary gvsdupdate command found inside the extracted U Boot image.

SD Card File Discovery Sequence

During early startup, I observed that U Boot mounts partition 0: on the SD card controller and checks for update files in a strict priority order:

  1. 0:jzt23Nall.bin (Full binary image update)
  2. 0:jzt23Nsd.bin (SD card recovery image update)
  3. 0:jzt23Nota.bin (Over the air update package)

If none of these files exist on the SD card, U Boot prints the following warning messages:

Warning, file: 0:jzt23Nall.bin does not exist
Warning, file: 0:jzt23Nota.bin does not exist

When I placed an update file on the SD card, U Boot opened the file and began processing:

open file 0:jzt23Nsd.bin success! start read data!

Container Architecture and Header Structure

By analyzing memory strings and MIPS assembly instructions in the extracted uboot.bin, I determined that the update file uses a Type Length Value container format.

flowchart LR
    subgraph Header ["Header Section (TLV Records)"]
        direction TB
        M["Magic Tag: gvfw / gsfw (4 Bytes)"]
        T1["TLV Tag: title (Package Title)"]
        T2["TLV Tag: type (Update Category)"]
        T3["TLV Tag: sha512 (Payload Hash)"]
        T4["TLV Tag: sign (RSA Signature)"]
        T5["TLV Tag: last (Header End)"]
        M --> T1 --> T2 --> T3 --> T4 --> T5
    end

    subgraph Payload ["Encrypted Payload (AES-CBC)"]
        direction TB
        P1["Subimage: uboot"]
        P2["Subimage: kernel"]
        P3["Subimage: rootfs"]
        P4["Subimage: app"]
        P5["Subimage: config"]
        P1 --> P2 --> P3 --> P4 --> P5
    end

    Header ==> Payload

Magic Identifiers

The package file begins at byte offset zero with one of two magic string tags: • gvfw (Goke / Guan視 Vision Firmware) • gsfw (Guan視 Secure Firmware)

If the magic tag or header flags do not match, U Boot logs an error and halts:

read firmware flag error
firmware flag error[%x]

Header TLV Records

Following the magic header, I found that U Boot parses sequential Type Length Value records:

title: Contains the descriptive title of the update package. • type: Indicates the specific update category. • sha512: Holds the SHA 512 cryptographic hash of the encrypted payload. • sign: Holds the RSA digital signature generated over the SHA 512 digest. • last: Marks the end of the header section.

Complete Verification Flow

Here is the complete verification pipeline I reconstructed from my disassembly of uboot.bin:

flowchart TD
    Start["Open SD Card Update File (0:jzt23Nsd.bin)"] --> Magic{"Magic Tag Check<br>(gvfw / gsfw)"}
    Magic -->|Invalid| Error1["Halt: firmware flag error"]
    Magic -->|Valid| ParseTLV["Parse Header TLV Records<br>(sha512, sign)"]
    ParseTLV --> VerifySign{"Verify RSA Signature & SHA-512"}
    VerifySign -->|Failed| Error2["Halt: sign error"]
    VerifySign -->|Valid| Decrypt["Decrypt Payload via AES-CBC"]
    Decrypt -->|Failed| Error3["Halt: decrypt update pack error"]
    Decrypt -->|Valid| CRC["Extract Subimages & Verify CRC32"]
    CRC --> Flash["Program SPI Storage (sf erase & sf write)"]
    Flash --> BootCheck{"Updated uboot Partition?"}
    BootCheck -->|Yes| Reboot["Print: updated uboot, reboot now!"]
    BootCheck -->|No| Continue["Continue Normal Boot Sequence"]

Detailed Verification Steps

  1. Header Validation: I traced how U Boot verifies the gvfw or gsfw string and checks initial flags.
  2. Signature and Hash Verification: I found that U Boot calculates a SHA 512 digest over the encrypted payload and validates the sign record using an embedded RSA public key. If this check fails, U Boot logs:
read firmware sign error
sign error
  1. Payload Decryption: After signature verification succeeds, U Boot decrypts the payload using AES CBC. The key is derived from the hardware EFUSE chip ID and a vendor key string.
  2. Subimage Parsing and CRC32 Validation: I discovered that U Boot extracts individual subimages (such as uboot, kernel, rootfs, app, and config) and computes standard CRC32 checksums:
CRC32 for %08lx ... %08lx ==> %08lx
  1. SPI NOR Flash Programming: Finally, U Boot executes sf erase and sf write commands to program the flash partitions. If the uboot partition was updated, it prints updated uboot, reboot now! and resets the board.

Key and Cryptographic Requirements

From my analysis, I established the exact cryptographic requirements needed to construct a valid update package:

Payload Hash: SHA 512 digest stored inside the sha512 TLV record. • Digital Signature: RSA signature stored inside the sign TLV record. • Payload Encryption: AES 128 or 256 CBC encryption. • Image Integrity Check: IEEE 802.3 CRC32 checksum for each subimage.