using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace MV485.util { //+------------------------+ ← Offset 0x000000 //| Image Header | 固定32字节 //+------------------------+ ← Offset 0x000020 //| Padding | 填充到 header-size 对齐(例如 0x400) //+------------------------+ ← Offset 0x000400 //| Image Payload | 实际的 bin 内容(运行代码) //+------------------------+ //| TLV Info | 包括哈希、签名等(SHA256、ECDSA 等) //+------------------------+ //| TLV Entries | 一个或多个 TLV 条目 //+------------------------+ //偏移 | 长度 | 字段名 | 描述 //0x00 | 4 | ih_magic | 魔数 0x96F3B83D //0x04 | 4 | ih_load_addr | 加载地址(对于 RAM Load 有用) //0x08 | 2 | ih_hdr_size | 头部大小,一般为 0x400 //0x0A | 2 | _pad1 | 保留字段 //0x0C | 4 | ih_img_size | 镜像内容长度(不含头部) //0x10 | 4 | ih_flags | 标志位,如是否加密 //0x14 | 1 | iv_major | 主版本号 //0x15 | 1 | iv_minor | 次版本号 //0x16 | 2 | iv_revision | 修订号 //0x18 | 4 | iv_build_num | 构建号 //0x1C | 4 | _pad2 | 保留字段 //3D B8 F3 96 ← ih_magic = 0x96F3B83D //00 00 00 00 ← ih_load_addr = 0x00000000 //04 00 ← ih_hdr_size = 0x0004(注意实际是 0x400) //00 00 //A0 69 0A 00 ← ih_img_size = 0x000A69A0(约680KB) //00 00 00 00 ← ih_flags = 0 //5C 5B 5A 00 ← version:iv_major=0x5C, iv_minor=0x5B, iv_revision=0x005A //... public class ImageHeader { public uint Magic; // 0x00 固定 magic: 0x96f3b83d public uint LoadAddr; // // 0x04 固件加载地址 public ushort HeaderSize; // 0x08 Header 大小(如 0x400) public ushort Pad1; // 0x0A 对齐用 public uint ImageSize; // 0x0C 固件正文大小(不含 Header) public uint Flags; // 0x10 标志位 public byte VersionMajor; // 0x14~0x1B 版本号(major/minor/revision/build) public byte VersionMinor; public ushort VersionRevision; public uint VersionBuildNum; public uint Pad2; public static ImageHeader FromBinaryReader(BinaryReader reader) { return new ImageHeader { Magic = reader.ReadUInt32(), LoadAddr = reader.ReadUInt32(), HeaderSize = reader.ReadUInt16(), Pad1 = reader.ReadUInt16(), ImageSize = reader.ReadUInt32(), Flags = reader.ReadUInt32(), VersionMajor = reader.ReadByte(), VersionMinor = reader.ReadByte(), VersionRevision = reader.ReadUInt16(), VersionBuildNum = reader.ReadUInt32(), Pad2 = reader.ReadUInt32() }; } } public class TlvInfo { public ushort Magic; // 0x6907 public ushort TotalLength; // TLV区总长度(包括这4字节) public static TlvInfo FromBinaryReader(BinaryReader reader) { return new TlvInfo { Magic = reader.ReadUInt16(), TotalLength = reader.ReadUInt16() }; } } //尾部 TLV 区域结构 //每项4字节头 + 数据 //类型(it_type) | 含义 //0x01 | 公钥哈希 //0x10 | 镜像 SHA256 //0x22 | ECDSA256 签名 //0x20 | RSA2048 签名(PSS) public class TlvEntry { public byte Type; // 类型,如 0x10 表示 SHA256,0x22 表示 ECDSA256 public byte Pad; // 保留 public ushort Length; // 后续数据长度 public byte[] Value; public static TlvEntry FromBinaryReader(BinaryReader reader) { var entry = new TlvEntry { Type = reader.ReadByte(), Pad = reader.ReadByte(), Length = reader.ReadUInt16() }; entry.Value = reader.ReadBytes(entry.Length); return entry; } } public class BinVerifier { public static bool VerifyBin(string binFilePath, out string expectedHashHex, out string actualHashHex) { expectedHashHex = ""; actualHashHex = ""; using (var fs = new FileStream(binFilePath, FileMode.Open, FileAccess.Read)) using (var reader = new BinaryReader(fs)) { // Step 1: 读取 image_header var header = ImageHeader.FromBinaryReader(reader); fs.Position = 0; var fullHeader = reader.ReadBytes(header.HeaderSize); // Step 2: 读取 image body var body = reader.ReadBytes((int)header.ImageSize); // Step 3: 读取 TLV info var tlvInfo = TlvInfo.FromBinaryReader(reader); if (tlvInfo.Magic != 0x6907) throw new InvalidDataException("Invalid TLV magic number."); int tlvRemaining = tlvInfo.TotalLength - 4; byte[] hashValue = null; while (tlvRemaining > 0) { var entry = TlvEntry.FromBinaryReader(reader); if (entry.Type == 0x10 && entry.Length == 32) // SHA256 type { hashValue = entry.Value; break; } tlvRemaining -= 4 + entry.Length; } if (hashValue == null) throw new InvalidDataException("SHA256 hash not found in TLV."); expectedHashHex = BitConverter.ToString(hashValue).Replace("-", "").ToLowerInvariant(); // Step 4: 计算 SHA256(header + body) using (var sha = SHA256.Create()) { var calculatedHash = sha.ComputeHash(fullHeader.Concat(body).ToArray()); actualHashHex = BitConverter.ToString(calculatedHash).Replace("-", "").ToLowerInvariant(); } return expectedHashHex == actualHashHex; } } } //------------------------------ }