123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- 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;
- }
- }
- }
- //------------------------------
- }
|