From f760f08300357d93149c26e4e2f125a7fc0ae1e6 Mon Sep 17 00:00:00 2001 From: Markus Fritsche Date: Wed, 15 Apr 2026 15:55:29 +0200 Subject: [PATCH] spi_check: +TPL plaintext verification and optional --blob byte-match Discovered the rkspi wrapper format during offline RC4 probing: the RKNS-wrapper sector at 0x8000 is plaintext. Zero padding fills 0x8200..0x85FF. Encoded metadata sits at 0x8600. The TPL (DDR blob) starts at 0x8800 in plaintext -- not RC4 encrypted as I first guessed. New checks: - TPL entry signature (0x01 0x00 0x00 0x14 = b +4 skipping header) at offset 0x8800 -- catches silent TPL corruption - optional --blob : byte-by-byte compare SPI[0x8800:+len(blob)] against a reference DDR blob file, reports sha256 + first-diff offset on mismatch Validated against stock SPI with stock blob (PASS, sha 13c04c4f), patched SPI with patched blob (PASS, sha 85799151), and the cross-pair (FAIL with diagnostics). Closes the remaining gap in phase-1 static validation -- now we catch not just |image has no idbloader| but also |image has the wrong DDR bytes|. --- spi_check.py | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/spi_check.py b/spi_check.py index d0fef97..8c6a2cc 100755 --- a/spi_check.py +++ b/spi_check.py @@ -19,18 +19,20 @@ Exit codes: Usage: rk3588_spi_check.py """ -import struct +import argparse, hashlib, struct import sys IDBL_OFFSET = 0x8000 RKNS_MAGIC = 0x534E4B52 # "RKNS" LE — rkspi boot header +TPL_OFFSET = 0x8800 # plaintext DDR blob (TPL) starts here in rkspi layout +TPL_ENTRY = bytes.fromhex("01000014") # first 4 bytes of the RK3588 DDR blob entry PAYLOAD_END = 0x60000 # stock u-boot places next section here def die(code, msg): print(f"FAIL: {msg}", file=sys.stderr) sys.exit(code) -def main(path): +def main(path, blob_path=None): with open(path, "rb") as f: data = f.read() print(f"SPI image: {path} size=0x{len(data):x} ({len(data)} B)") @@ -63,11 +65,33 @@ def main(path): flag_like = struct.unpack_from("