From 46a2cef9933e54fd41b1a5ba4869f241b01791c8 Mon Sep 17 00:00:00 2001 From: brliron Date: Tue, 26 Sep 2023 14:03:24 +0200 Subject: [PATCH] patterns: Added Android VBMeta image pattern (#169) --- README.md | 1 + patterns/vbmeta.hexpat | 215 +++++++++++++++++++++ tests/patterns/test_data/vbmeta.hexpat.img | Bin 0 -> 1920 bytes 3 files changed, 216 insertions(+) create mode 100644 patterns/vbmeta.hexpat create mode 100644 tests/patterns/test_data/vbmeta.hexpat.img diff --git a/README.md b/README.md index ead1a41..8c8f397 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | Ubiquiti | | [`patterns/ubiquiti.hexpat`](patterns/ubiquiti.hexpat) | Ubiquiti Firmware (update) image | | UEFI | | [`patterns/uefi.hexpat`](patterns/uefi.hexpat)` | UEFI structs for parsing efivars | | UF2 | | [`patterns/uf2.hexpat`](patterns/uf2.hexpat) | [USB Flashing Format](https://github.com/microsoft/uf2) | +| VBMeta | | [`patterns/vbmeta.hexpat`](patterns/vbmeta.hexpat) | Android VBMeta image | | VDF | | [`patterns/vdf.hexpat`](patterns/vdf.hexpat) | Binary Value Data Format (.vdf) files | | VHDX | | [`patterns/vhdx.hexpat`](patterns/vhdx.hexpat) | Microsoft Hyper-V Virtual Hard Disk format | | WAV | `audio/x-wav` | [`patterns/wav.hexpat`](patterns/wav.hexpat) | RIFF header, WAVE header, PCM header | diff --git a/patterns/vbmeta.hexpat b/patterns/vbmeta.hexpat new file mode 100644 index 0000000..47f21b8 --- /dev/null +++ b/patterns/vbmeta.hexpat @@ -0,0 +1,215 @@ +#pragma description Android VBMeta image + +#pragma endian big +#include + +using uint8_t = u8; +using uint32_t = u32; +using uint64_t = u64; + +#define AVB_MAGIC_LEN 4 +#define AVB_RELEASE_STRING_SIZE 48 + +enum AvbAlgorithmType : uint32_t { + AVB_ALGORITHM_TYPE_NONE, + AVB_ALGORITHM_TYPE_SHA256_RSA2048, + AVB_ALGORITHM_TYPE_SHA256_RSA4096, + AVB_ALGORITHM_TYPE_SHA256_RSA8192, + AVB_ALGORITHM_TYPE_SHA512_RSA2048, + AVB_ALGORITHM_TYPE_SHA512_RSA4096, + AVB_ALGORITHM_TYPE_SHA512_RSA8192, + _AVB_ALGORITHM_NUM_TYPES +}; + +struct AvbVBMetaImageHeader { + /* 0: Four bytes equal to "AVB0" (AVB_MAGIC). */ + char magic[AVB_MAGIC_LEN]; + /* 4: The major version of libavb required for this header. */ + uint32_t required_libavb_version_major; + /* 8: The minor version of libavb required for this header. */ + uint32_t required_libavb_version_minor; + /* 12: The size of the signature block. */ + uint64_t authentication_data_block_size; + /* 20: The size of the auxiliary data block. */ + uint64_t auxiliary_data_block_size; + /* 28: The verification algorithm used, see |AvbAlgorithmType| enum. */ + AvbAlgorithmType algorithm_type; + /* 32: Offset into the "Authentication data" block of hash data. */ + uint64_t hash_offset; + /* 40: Length of the hash data. */ + uint64_t hash_size; + /* 48: Offset into the "Authentication data" block of signature data. */ + uint64_t signature_offset; + /* 56: Length of the signature data. */ + uint64_t signature_size; + /* 64: Offset into the "Auxiliary data" block of public key data. */ + uint64_t public_key_offset; + /* 72: Length of the public key data. */ + uint64_t public_key_size; + /* 80: Offset into the "Auxiliary data" block of public key metadata. */ + uint64_t public_key_metadata_offset; + /* 88: Length of the public key metadata. Must be set to zero if there + * is no public key metadata. + */ + uint64_t public_key_metadata_size; + /* 96: Offset into the "Auxiliary data" block of descriptor data. */ + uint64_t descriptors_offset; + /* 104: Length of descriptor data. */ + uint64_t descriptors_size; + /* 112: The rollback index which can be used to prevent rollback to + * older versions. + */ + uint64_t rollback_index; + /* 120: Flags from the AvbVBMetaImageFlags enumeration. This must be + * set to zero if the vbmeta image is not a top-level image. + */ + uint32_t flags; + /* 124: The location of the rollback index defined in this header. + * Only valid for the main vbmeta. For chained partitions, the rollback + * index location must be specified in the AvbChainPartitionDescriptor + * and this value must be set to 0. + */ + uint32_t rollback_index_location; + /* 128: The release string from avbtool, e.g. "avbtool 1.0.0" or + * "avbtool 1.0.0 xyz_board Git-234abde89". Is guaranteed to be NUL + * terminated. Applications must not make assumptions about how this + * string is formatted. + */ + char release_string[AVB_RELEASE_STRING_SIZE]; + /* 176: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE + * bytes. This must be set to zeroes. + */ + padding[80]; +}; + +enum AvbDescriptorTag : uint64_t { + AVB_DESCRIPTOR_TAG_PROPERTY, + AVB_DESCRIPTOR_TAG_HASHTREE, + AVB_DESCRIPTOR_TAG_HASH, + AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE, + AVB_DESCRIPTOR_TAG_CHAIN_PARTITION, +}; + +struct AvbPropertyDescriptor { + uint64_t key_num_bytes; + uint64_t value_num_bytes; + char key[key_num_bytes]; + padding[1]; + char value[value_num_bytes]; + padding[1]; +} [[inline]]; + +bitfield AvbHashtreeDescriptorFlags { + AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB : 1; + AVB_HASHTREE_DESCRIPTOR_FLAGS_CHECK_AT_MOST_ONCE : 1; +} [[bitfield_order(std::core::BitfieldOrder::LeastToMostSignificant, 32)]]; + +struct AvbHashtreeDescriptor { + uint32_t dm_verity_version; + uint64_t image_size; + uint64_t tree_offset; + uint64_t tree_size; + uint32_t data_block_size; + uint32_t hash_block_size; + uint32_t fec_num_roots; + uint64_t fec_offset; + uint64_t fec_size; + char hash_algorithm[32]; + uint32_t partition_name_len; + uint32_t salt_len; + uint32_t root_digest_len; + AvbHashtreeDescriptorFlags flags; + padding[60]; // reserved + char partition_name[partition_name_len]; + u8 salt[salt_len]; + u8 root_digest[root_digest_len]; +} [[inline]]; + +struct AvbHashDescriptor { + uint64_t image_size; + char hash_algorithm[32]; + uint32_t partition_name_len; + uint32_t salt_len; + uint32_t digest_len; + uint32_t flags; + padding[60]; // reserved + char partition_name[partition_name_len]; + u8 salt[salt_len]; + u8 digest[digest_len]; +} [[inline]]; + +struct AvbKernelCmdlineDescriptor { + uint32_t flags; + uint32_t kernel_cmdline_length; + char kernel_cmdline[kernel_cmdline_length]; +} [[inline]]; + +struct AvbChainPartitionDescriptor { + uint32_t rollback_index_location; + uint32_t partition_name_len; + uint32_t public_key_len; + padding[64]; // reserved + char partition_name[partition_name_len]; + u8 public_key[public_key_len]; +} [[inline]]; + +struct AvbDescriptor { + AvbDescriptorTag tag; + uint64_t num_bytes_following; + u8 data[num_bytes_following] [[hidden]]; + + match (tag) { + (AvbDescriptorTag::AVB_DESCRIPTOR_TAG_PROPERTY) : AvbPropertyDescriptor descriptor @ addressof(data); + (AvbDescriptorTag::AVB_DESCRIPTOR_TAG_HASHTREE) : AvbHashtreeDescriptor descriptor @ addressof(data); + (AvbDescriptorTag::AVB_DESCRIPTOR_TAG_HASH) : AvbHashDescriptor descriptor @ addressof(data); + (AvbDescriptorTag::AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE) : AvbKernelCmdlineDescriptor descriptor @ addressof(data); + (AvbDescriptorTag::AVB_DESCRIPTOR_TAG_CHAIN_PARTITION): AvbChainPartitionDescriptor descriptor @ addressof(data); + } + + if ($ >= end) + break; +}; + +struct AuthenticationData +{ + u8 authentication_data_block[authentication_data_block_size] [[hidden]]; + + u8 hash[hash_size] @ addressof(authentication_data_block) + hash_offset; + u8 signature[signature_size] @ addressof(authentication_data_block) + signature_offset; +}; + +struct AuxiliaryData +{ + u8 auxiliary_data_block[auxiliary_data_block_size] [[hidden]]; + + u8 public_key[public_key_size] @ addressof(auxiliary_data_block) + public_key_offset; + u8 public_key_metadata[public_key_metadata_size] @ addressof(auxiliary_data_block) + public_key_metadata_offset; + + if (descriptors_size > 0) { + u8 descriptors_block[descriptors_size] @ addressof(auxiliary_data_block) + descriptors_offset [[hidden]]; + AvbDescriptor descriptors[200] @ addressof(descriptors_block); + } +}; + +struct AvbVBMetaImage +{ + AvbVBMetaImageHeader header; + + AuthenticationData + authentication_data; + + AuxiliaryData + auxiliary_data; +}; + +AvbVBMetaImage image @ 0; diff --git a/tests/patterns/test_data/vbmeta.hexpat.img b/tests/patterns/test_data/vbmeta.hexpat.img new file mode 100644 index 0000000000000000000000000000000000000000..bbcb2fd544bc6e60647e5db9b6ccf8a845145a60 GIT binary patch literal 1920 zcmcIkX*?7N8=o=8&5}lH9OGyh8b^(_m~ySjl_PhKnK6l+n^xntH?^ZN(}3mcKc;}KffQ|=l6S_|Nl8ZJGV;QOaA8@JblW(Kbpiu0^ME*t-G4Zg$0Lp!uiSXPj(~VsWmdnI}ZKp z8lT7A6SJ_uQ0C`dUc4Y9L)U8(0fHXzXRbW95oZVXnD#3>;{u?lCwnSecu`V_4>Apm zh4{}I_VDs_R!UynUD@x6%`ap59^>cf8UJO|&7wAYtv1Vh^$fcxF5XoX!_LXzyBwo{>-@b=VRiw?%N*uixEpQaQ>pI0mLT zjLSrH9$C3n@%n{^MDEtM57$@GIV!rE_>z;DPV`~B-jn9Il|7%y>HIVSURn<}$--YD zU31m~=`x!v8#86-^?zj8`3>IT(&XA5+t{oX&hrQaU;*o9wMsTMkO9%&MtvY+Oi}va zi7|?1W2IEUg*QY{!@}KgZr-r3q+^ff*tMZNZk32&2R&qRu+jZQtO#D8@>VsPS3I+` zZ5DCKGTrf!9Ev<)%4k?lUJ|{M=7y9&$LZuU9T-aJ4d%OpvPTQf*h>~7}94J z+UoV-pcCb0x2C$zA;Yw~jRZl@{^$rm>(Y22ENpKm&7h)i_?0`oX{ZLwXpCbxO-+{o zEX+o>Mg>yPx1c7Hl^PXcE!3f$of6OSDTYwfYc{S5TpDR|Ot@1A#Tg8lpMYOw{|+>K zwIESkfuLf%njAPT+D&W!;|59}*8h7?Ks>ccBC|#%s}^o6?rwppR zdjbTK=$OrmO5%{z0SIE|Bp-OM_9l_GsHUK}?0X-yBofq?$yc7zU0_?ky+A9qSdQit z2TJZY*9A5a{?g@}z_#*(^`X>t#`tuaubBN>GL(ZPFg$L^*Y(>YPZ%w>z4Q=bSZ>1< zYHhZL_fpPGMfrR}?*)xILu`=3@=Q6T`UPJzq(ZIM;nsT@mK~agjOIqSbv?S+vOCz8Iz?v^pOVU%!5&Bv*Vn94LwQ{B4N; zUTn`(&l4m;nW|OHexBtWdxF>Hk^va)Myb`~)YAjfcpDp)cbf^S5q?z;GqfdtF|i6m!{ zRTv%u+{)+GO`^A3O2oCS?zj?&#MuuF`PR}R?1NBYw6;QDQWl@E5c9TdCBaSmKSS)( z1s$llbD)T}h$rm{MRe)2vper7E~A(d(z=b_BHcULO?~Jaye*eP&vbJ72?oY|RlyRcBzw-}% zi4i@fA5(rY_a-We^L6@pb3JgLCXVywK4{{FH>@=*p*bmIp<(0&;gl_)6eAy=@tf-x zqc(x+n;#w;H@1G+8Us$N!;GN?H!}vg-r00if?xG|{l0IA$D7)Oy7peIE`N>LUu5&w z99hWPKzt;toyu$`l=r(F-IE;}fmf@{?U@%^E~(zD3NlKd$#udSZa5+u^lkn zUT+Sn)KJrBTcCLmNLQ=2nJP>0&*)RKCQpbJRehNpBzH~!tSowIPLwa%ywFZcpY26S z_4|n~A@lKJik`vf?B1-mmfH5DXpx+CM*Ib%N04E$eU=6s*USJ>Hr01x2BPn~Hgk_7 z?U+ari+gXXE65phyrX@!JlA}<4lx9mXC}b;lGh%$T(*K@ z1Q*m0X96Me!!x<+F`9B&jXGM%jQHpc8C3_9oM{pMCe-}Zn&WAE13HeY7P#hKC1HXO zANoD<^6+uHQ-lboV2`A7L3kuhapT-t9#U6NheB5Ilw*2j1amuDZ9Vc);=o<=fQJD-H(^0OVff4VFuc$|pW$zrR}`=S literal 0 HcmV?d00001