鸿蒙5解包 鸿蒙5的系统包UPDATE.APP用的还是老版本安卓包的结构,但是现有的工具好像不能识别分区名,分块的分区数据导出也有问题,参考YKG/huawei_UPDATE.APP_unpacktool 的解包工具重新实现了下。 写好的代码放在GitHub 了。
系统包的文件头首先是92字节的0x00,接着是每个分区的数据块,数据块开头是55AA5AA5,数据块结构如下。
偏移
大小
数据
0x0
4
Magic 55AA5AA5
0x4
4
数据头长度
0x8
4
Magic 0x00000001
0xC
8
硬件ID
0x14
4
序号 (应该是废弃了)
0x18
4
分区数据长度
0x1C
16
日期
0x2C
16
时间
0x3C
16
分区名
0x4C
16
0x00
0x5C
2
头部自定义CRC16
0x5E
2
0x1000 数据块计算CRC16时每块的大小
0x60
2
0x00
0x62
数据头长度-0x62
数据块CRC16表 (按上面定义的块大小分块计算)
数据头长度
分区数据长度
分区数据
数据头长度+分区数据长度
pad将分区数据对其到4字节
按数据块结构循环解析到EOF即可,需要注意的是如果记录中存在相同的分区名,数据要append到前一个已经导出的分区数据后面。老版本的工具无法解包主要就是没有处理这一步。
用ImHex写了个Pattern。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import std .mem; import type.magic; char ZeroPadding[92 ] @ 0x00 ;struct BlockHeader { type::Magic<"\x55\xAA\x5A\xA5" > [[name("Signature" )]]; u32 headerLength [[name("Header Length" )]]; type::Magic<"\x01\x00\x00\x00" > [[name("Magic Number" )]]; char hardwareId[8 ] [[name("Hardware ID" )]]; u32 sequence [[name("Sequence out of use?" )]]; u32 dataLength [[name("Partition Data Length" )]]; char date[16 ] [[name("Date" )]]; char time[16 ] [[name("Time" )]]; char partitionName[16 ] [[name("Partition Name" )]]; char blank1[16 ] [[name("Blank1 16 bytes 0x00" )]]; char headerChecksum[2 ] [[name("Header Checksum" )]]; u16 chunkSize [[name("Data chunk size for CRC" )]]; char blank2[2 ] [[name("Blank 2 bytes 0x00" )]]; char checksum[headerLength - 98 ] [[name("Data Checksum" )]]; }; struct Block { BlockHeader blockHeader; char data[blockHeader.dataLength]; char Padding[(4 - ($ % 4 )) % 4 ]; } [[name(blockHeader.partitionName)]]; Block block[while ($ < std ::mem::size())] @ $;
忘了从XDA哪个上古贴子翻出来的算法了,算出来是对的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class UpdateCrc16 : """ Customized CRC16 """ def __init__ (self, initial_sum=0xFFFF , polynomial=0x8408 , xor_value=0xFFFF ): self ._polynomial = polynomial self ._xor_value = xor_value self ._initial_sum = initial_sum self ._table = self ._initialize_table() def _initialize_table (self ): table = [0 ] * 256 for i in range (256 ): value = 0 temp = i for _ in range (8 ): if ((value ^ temp) & 0x0001 ) != 0 : value = (value >> 1 ) ^ self ._polynomial else : value >>= 1 temp >>= 1 table[i] = value return table def compute_sum (self, mv: memoryview ) -> int : current_sum = self ._initial_sum for byte in mv: current_sum = ((current_sum >> 8 ) ^ self ._table[(current_sum ^ byte) & 0xFF ]) & 0xFFFF final_sum = (current_sum ^ self ._xor_value) & 0xFFFF return final_sum
鸿蒙6解包 最近更新了鸿蒙6,发现包结构变了,现在用的是OpenHarmony_L2的结构,解包工具代码可以直接从openharmony的仓库 找到。
包结构现代了不少,基本用TLV结构记录数据,校验值现在直接用了SHA-256。写了下ImHex的Pattern方便分析。代码同样放在GitHub 了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 #include <std/string.pat> #define UPGRADE_COMPINFO_SIZE_L2 87 #define COMPONENT_ADDR_SIZE_L2 32 enum HeaderTLVType : u16 { header_tlv_type_not_l2 = 0x11 , header_tlv_type_l2 = 1 , }; enum ComponentType : u8 { IMG = 0 , ZIP = 1 , UNKNOWN = 0xFF }; struct ComponentInfo { char component_name[COMPONENT_ADDR_SIZE_L2]; u16 component_id; u8 component_res_type; u8 component_flag; ComponentType component_type; char component_version[10 ]; u32 component_size; u32 component_original_size; char digest[32 ]; }; struct FileHeader { HeaderTLVType header_tlv_type; u16 upgrade_pkg_header_size; u32 pkg_info_length; u32 update_file_version; char product_update_id[64 ]; char software_version[64 ]; u16 time_tlv_type; u16 upgrade_pkg_time_size; char date[16 ]; char time[16 ]; u16 compinfo_tlv_type; u16 compinfo_len; u8 component_count = compinfo_len / UPGRADE_COMPINFO_SIZE_L2; ComponentInfo component_infos[component_count]; }; struct HashInfoHeader { u16 sign_tlv_type; u32 signdata_len; char signdata[signdata_len]; }; FileHeader file_header @ 0x0 ; char describe_package_id[16 ] @ $;HashInfoHeader hash_info_header @ $; u8 chunk_index; struct ChunkData { char chunk_data[file_header.component_infos[chunk_index].component_size] [[name(std ::string ::to_string(file_header.component_infos[chunk_index].component_name))]]; chunk_index += 1 ; }; ChunkData chunk_datas[file_header.component_count] @ $;