msd: add option to print ouith tree instead of static, some improvements to pfl_upg, mtk_pkg: add option to not delete decompressed lzhs part

This commit is contained in:
theubusu
2026-02-18 22:54:03 +01:00
parent ab727411dc
commit f4a146a389
11 changed files with 128 additions and 112 deletions
+9
View File
@@ -60,11 +60,14 @@ Options:
**Thanks to:** https://github.com/bugficks/msddecrypt **Thanks to:** https://github.com/bugficks/msddecrypt
**Options:** **Options:**
`msd10:save_cmac` - Save CMAC data for files that is skipped by default. `msd10:save_cmac` - Save CMAC data for files that is skipped by default.
`msd:print_ouith` - Prints the entire parsed OUITH header.
## MSD 1.1 ## MSD 1.1
**Used in:** Samsung TVs 2016+ **Used in:** Samsung TVs 2016+
**Notes:** **Depends on keys** - see keys.rs (keys 2015-2018, 2020 included) **Notes:** **Depends on keys** - see keys.rs (keys 2015-2018, 2020 included)
**Thanks to:** https://github.com/bugficks/msddecrypt **Thanks to:** https://github.com/bugficks/msddecrypt
**Options:**
`msd:print_ouith` - Prints the entire parsed OUITH header.
## MStar upgrade bin ## MStar upgrade bin
**Used in:** Many MStar-based TVs (Hisense, Toshiba...) **Used in:** Many MStar-based TVs (Hisense, Toshiba...)
@@ -77,15 +80,21 @@ Options:
## MediaTek PKG (New) ## MediaTek PKG (New)
**Used in:** Newer MediaTek-based TVs (TCL, Hisense, Sony, Philips, CVT...) **Used in:** Newer MediaTek-based TVs (TCL, Hisense, Sony, Philips, CVT...)
**Notes:** **Depends on keys** - see keys.rs (Keys for Philips and Sony included) **Notes:** **Depends on keys** - see keys.rs (Keys for Philips and Sony included)
**Options:**
`mtk_pkg:no_del_comp` - Don't delete LZHS compressed partition file after decompressing.
## MediaTek PKG (Old) ## MediaTek PKG (Old)
**Used in:** Older MediaTek-based TVs (Philips, Sony, Hisense...) **Used in:** Older MediaTek-based TVs (Philips, Sony, Hisense...)
**Notes:** All files should be supported, decryption + decompression **Notes:** All files should be supported, decryption + decompression
**Options:**
`mtk_pkg:no_del_comp` - Don't delete LZHS compressed partition file after decompressing.
## MediaTek PKG ## MediaTek PKG
**Used in:** MediaTek-based TVs (Sony, Philips, Panasonic, Sharp...) **Used in:** MediaTek-based TVs (Sony, Philips, Panasonic, Sharp...)
**Notes:** All files should be supported, decryption + decompression, however some Philips files use custom keys - most are included some could be missing **Notes:** All files should be supported, decryption + decompression, however some Philips files use custom keys - most are included some could be missing
**Thanks to:** https://github.com/openlgtv/epk2extract **Thanks to:** https://github.com/openlgtv/epk2extract
**Options:**
`mtk_pkg:no_del_comp` - Don't delete LZHS compressed partition file after decompressing.
## Novatek PKG (NFWB) ## Novatek PKG (NFWB)
**Used in:** Some older Novatek-based TVs (LG, Philips) **Used in:** Some older Novatek-based TVs (LG, Philips)
+27 -30
View File
@@ -5,9 +5,6 @@ use binrw::{BinRead, BinReaderExt};
use crate::utils::common; use crate::utils::common;
// whether to print the tree
static CONFIG_PRINT_TREE: bool = false;
#[derive(BinRead)] #[derive(BinRead)]
struct ChunkHeader { struct ChunkHeader {
size: u32, size: u32,
@@ -92,7 +89,7 @@ pub struct MSDItem {
//pub secure_hash: Option<Vec<u8>>, //pub secure_hash: Option<Vec<u8>>,
} }
pub fn parse_ouith_blob(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVersionExDesc>), Box<dyn std::error::Error>> { pub fn parse_ouith_blob(blob: &[u8], print_tree: bool) -> Result<(Vec<MSDItem>, Option<OUSWImageVersionExDesc>), Box<dyn std::error::Error>> {
let mut reader = Cursor::new(blob); let mut reader = Cursor::new(blob);
let mut items: Vec<MSDItem> = Vec::new(); let mut items: Vec<MSDItem> = Vec::new();
let mut info: Option<OUSWImageVersionExDesc> = None; let mut info: Option<OUSWImageVersionExDesc> = None;
@@ -103,31 +100,31 @@ pub fn parse_ouith_blob(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVe
while reader.stream_position()? < blob.len() as u64 { while reader.stream_position()? < blob.len() as u64 {
chunk_n += 1; chunk_n += 1;
let chunk: ChunkHeader = reader.read_be()?; let chunk: ChunkHeader = reader.read_be()?;
if CONFIG_PRINT_TREE { println!("\nChunk {} - Size: {}, Value: {}", chunk_n, chunk.size, chunk.value); }; if print_tree { println!("\nChunk {} - Size: {}, Value: {}", chunk_n, chunk.size, chunk.value); };
let chunk_end = reader.stream_position()? + chunk.size as u64; let chunk_end = reader.stream_position()? + chunk.size as u64;
//parse top level descriptor. it can only be ID 1(OUUpgradeItemDesc) or 2(OUGroupDesc) //parse top level descriptor. it can only be ID 1(OUUpgradeItemDesc) or 2(OUGroupDesc)
let top_descriptor: DescriptorHeader = reader.read_be()?; let top_descriptor: DescriptorHeader = reader.read_be()?;
if top_descriptor.tag == 0x01 { if top_descriptor.tag == 0x01 {
if CONFIG_PRINT_TREE { println!("OUUpgradeItemDesc(0x01) - Size: {}", top_descriptor.size); }; if print_tree { println!("OUUpgradeItemDesc(0x01) - Size: {}", top_descriptor.size); };
let item_id: u32 = reader.read_be()?; let item_id: u32 = reader.read_be()?;
if CONFIG_PRINT_TREE { println!(" Item ID: {}", item_id); }; if print_tree { println!(" Item ID: {}", item_id); };
//REQUIRED are items in order: OUDestinationDesc(0x03), OUDataProcessingDesc(0x07), OUGroupInfoDesc(0x13). OPTIONAL items: OUDependenciesDesc(0x04), OUDataPostProcessingDesc(0x08) //REQUIRED are items in order: OUDestinationDesc(0x03), OUDataProcessingDesc(0x07), OUGroupInfoDesc(0x13). OPTIONAL items: OUDependenciesDesc(0x04), OUDataPostProcessingDesc(0x08)
//In MSD files, no others seem to be used than the required ones. We will ignore all data after required descriptors. //In MSD files, no others seem to be used than the required ones. We will ignore all data after required descriptors.
let destination_descriptor: DescriptorHeader = reader.read_be()?; let destination_descriptor: DescriptorHeader = reader.read_be()?;
if destination_descriptor.tag != 0x03 {return Err(format!("Unexpected descriptor type in OUUpgradeItemDesc, Expected: 0x03, Got: 0x{:02x}!", destination_descriptor.tag).into())} if destination_descriptor.tag != 0x03 {return Err(format!("Unexpected descriptor type in OUUpgradeItemDesc, Expected: 0x03, Got: 0x{:02x}!", destination_descriptor.tag).into())}
if CONFIG_PRINT_TREE { println!(" OUDestinationDesc(0x03) - Size: {}", destination_descriptor.size); }; if print_tree { println!(" OUDestinationDesc(0x03) - Size: {}", destination_descriptor.size); };
let out_size: u32 = reader.read_be()?; let out_size: u32 = reader.read_be()?;
if CONFIG_PRINT_TREE { println!(" Out data size: {}", out_size); }; if print_tree { println!(" Out data size: {}", out_size); };
//OUDestinationDesc needs one of OUSWFileVersionDesc(0x0B), OUPartitionVersionDesc(0x0A), OUCMACDataDesc(0x11). Their structure is the same. so we can store the type //OUDestinationDesc needs one of OUSWFileVersionDesc(0x0B), OUPartitionVersionDesc(0x0A), OUCMACDataDesc(0x11). Their structure is the same. so we can store the type
let type_descriptor: DescriptorHeader = reader.read_be()?; let type_descriptor: DescriptorHeader = reader.read_be()?;
if ![0x0B, 0xA, 0x11].contains(&type_descriptor.tag) {return Err(format!("Unexpected descriptor type in OUDestinationDesc, Expected: one of 0x0B, 0x0A, 0x11, Got: 0x{:02x}!", type_descriptor.tag).into())} if ![0x0B, 0xA, 0x11].contains(&type_descriptor.tag) {return Err(format!("Unexpected descriptor type in OUDestinationDesc, Expected: one of 0x0B, 0x0A, 0x11, Got: 0x{:02x}!", type_descriptor.tag).into())}
if CONFIG_PRINT_TREE { println!(" Type descriptor(0x{:02x}) - Size: {}", type_descriptor.tag, type_descriptor.size); }; if print_tree { println!(" Type descriptor(0x{:02x}) - Size: {}", type_descriptor.tag, type_descriptor.size); };
let destination_info: CommonDestinationInfo = reader.read_be()?; let destination_info: CommonDestinationInfo = reader.read_be()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Name lenght: {}", destination_info.name_len); println!(" Name lenght: {}", destination_info.name_len);
println!(" Name: {}", destination_info.name()); println!(" Name: {}", destination_info.name());
println!(" Version: {}", destination_info.version); println!(" Version: {}", destination_info.version);
@@ -136,11 +133,11 @@ pub fn parse_ouith_blob(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVe
//OUDataProcessingDesc can have OUXOREncryptionDesc(0x0D), OUAESEncryptionDesc(0x0E), OUCompressionDesc(0x0F), OUSecureHashValidationDesc(0x18), OURSAValidationDesc(0x10), OUDataCopyDesc(0x16), OUKeepCurrentDataDesc(0x1E), OUCRC32ValidationDesc(0x12) //OUDataProcessingDesc can have OUXOREncryptionDesc(0x0D), OUAESEncryptionDesc(0x0E), OUCompressionDesc(0x0F), OUSecureHashValidationDesc(0x18), OURSAValidationDesc(0x10), OUDataCopyDesc(0x16), OUKeepCurrentDataDesc(0x1E), OUCRC32ValidationDesc(0x12)
let data_processing_descriptor: DescriptorHeader = reader.read_be()?; let data_processing_descriptor: DescriptorHeader = reader.read_be()?;
if data_processing_descriptor.tag != 0x07 {return Err(format!("Unexpected descriptor type in OUUpgradeItemDesc, Expected: 0x07, Got: 0x{:02x}!", data_processing_descriptor.tag).into())} if data_processing_descriptor.tag != 0x07 {return Err(format!("Unexpected descriptor type in OUUpgradeItemDesc, Expected: 0x07, Got: 0x{:02x}!", data_processing_descriptor.tag).into())}
if CONFIG_PRINT_TREE { println!(" OUDataProcessingDesc(0x07) - Size: {}", data_processing_descriptor.size); }; if print_tree { println!(" OUDataProcessingDesc(0x07) - Size: {}", data_processing_descriptor.size); };
let heading_size: u32 = reader.read_be()?; let heading_size: u32 = reader.read_be()?;
if CONFIG_PRINT_TREE { println!(" Heading size: {}", heading_size); }; if print_tree { println!(" Heading size: {}", heading_size); };
let data_size: u32 = reader.read_be()?; let data_size: u32 = reader.read_be()?;
if CONFIG_PRINT_TREE { println!(" Data size: {}", data_size); }; if print_tree { println!(" Data size: {}", data_size); };
let mut aes_encryption = false; let mut aes_encryption = false;
//let mut crc32_hash: Option<u32> = None; //let mut crc32_hash: Option<u32> = None;
@@ -152,9 +149,9 @@ pub fn parse_ouith_blob(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVe
if ![0x0D, 0x0E, 0x0F, 0x18, 0x10, 0x16, 0x1E, 0x12].contains(&descriptor.tag) {return Err(format!("Unexpected descriptor type in OUDataProcessingDesc, Expected: one of 0x0D, 0x0E, 0x0F, 0x18, 0x10, 0x16, 0x1E, 0x12, Got: 0x{:02x}!", descriptor.tag).into())} if ![0x0D, 0x0E, 0x0F, 0x18, 0x10, 0x16, 0x1E, 0x12].contains(&descriptor.tag) {return Err(format!("Unexpected descriptor type in OUDataProcessingDesc, Expected: one of 0x0D, 0x0E, 0x0F, 0x18, 0x10, 0x16, 0x1E, 0x12, Got: 0x{:02x}!", descriptor.tag).into())}
if descriptor.tag == 0x0E { if descriptor.tag == 0x0E {
//OUAESEncryptionDesc //OUAESEncryptionDesc
if CONFIG_PRINT_TREE { println!(" OUAESEncryptionDesc(0x0E) - Size: {}", descriptor.size); }; if print_tree { println!(" OUAESEncryptionDesc(0x0E) - Size: {}", descriptor.size); };
let aes_encryption_desc: OUAESEncryptionDesc = reader.read_be()?; let aes_encryption_desc: OUAESEncryptionDesc = reader.read_be()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Mode: {}", aes_encryption_desc.mode); println!(" Mode: {}", aes_encryption_desc.mode);
println!(" Key size: {}", aes_encryption_desc.key_size); println!(" Key size: {}", aes_encryption_desc.key_size);
println!(" Salt size: {}", aes_encryption_desc.salt_size); println!(" Salt size: {}", aes_encryption_desc.salt_size);
@@ -163,9 +160,9 @@ pub fn parse_ouith_blob(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVe
} }
else if descriptor.tag == 0x10 { else if descriptor.tag == 0x10 {
//OURSAValidationDesc //OURSAValidationDesc
if CONFIG_PRINT_TREE { println!(" OURSAValidationDesc(0x10) - Size: {}", descriptor.size); }; if print_tree { println!(" OURSAValidationDesc(0x10) - Size: {}", descriptor.size); };
let rsa_validation_desc: OURSAValidationDesc = reader.read_be()?; let rsa_validation_desc: OURSAValidationDesc = reader.read_be()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Mode: {}", rsa_validation_desc.mode); println!(" Mode: {}", rsa_validation_desc.mode);
println!(" Field 2: {}", rsa_validation_desc._unknown); println!(" Field 2: {}", rsa_validation_desc._unknown);
println!(" Signature size: {}", rsa_validation_desc.signature_size); println!(" Signature size: {}", rsa_validation_desc.signature_size);
@@ -173,16 +170,16 @@ pub fn parse_ouith_blob(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVe
} }
else if descriptor.tag == 0x12 { else if descriptor.tag == 0x12 {
//OUCRC32ValidationDesc //OUCRC32ValidationDesc
if CONFIG_PRINT_TREE { println!(" OUCRC32ValidationDesc(0x12) - Size: {}", descriptor.size); }; if print_tree { println!(" OUCRC32ValidationDesc(0x12) - Size: {}", descriptor.size); };
let crc32: u32 = reader.read_be()?; let crc32: u32 = reader.read_be()?;
if CONFIG_PRINT_TREE { println!(" CRC32: {:02x}", crc32); }; if print_tree { println!(" CRC32: {:02x}", crc32); };
//crc32_hash = Some(crc32); //crc32_hash = Some(crc32);
} }
else if descriptor.tag == 0x18 { else if descriptor.tag == 0x18 {
//OUSecureHashValidationDesc //OUSecureHashValidationDesc
if CONFIG_PRINT_TREE { println!(" OUSecureHashValidationDesc(0x18) - Size: {}", descriptor.size); }; if print_tree { println!(" OUSecureHashValidationDesc(0x18) - Size: {}", descriptor.size); };
let secure_hash_validation_desc: OUSecureHashValidationDesc = reader.read_be()?; let secure_hash_validation_desc: OUSecureHashValidationDesc = reader.read_be()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Mode: {}", secure_hash_validation_desc.mode); println!(" Mode: {}", secure_hash_validation_desc.mode);
println!(" Hash size: {}", secure_hash_validation_desc.hash_size); println!(" Hash size: {}", secure_hash_validation_desc.hash_size);
println!(" Hash: {}", hex::encode(&secure_hash_validation_desc.hash)); println!(" Hash: {}", hex::encode(&secure_hash_validation_desc.hash));
@@ -191,7 +188,7 @@ pub fn parse_ouith_blob(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVe
} }
else { else {
//type not implemented, ignore the data //type not implemented, ignore the data
if CONFIG_PRINT_TREE { println!(" Unimplemented descriptor(0x{:02x}) - Size: {}", descriptor.tag, descriptor.size); }; if print_tree { println!(" Unimplemented descriptor(0x{:02x}) - Size: {}", descriptor.tag, descriptor.size); };
let _descriptor_data = common::read_exact(&mut reader, descriptor.size as usize); let _descriptor_data = common::read_exact(&mut reader, descriptor.size as usize);
} }
} }
@@ -199,9 +196,9 @@ pub fn parse_ouith_blob(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVe
//OUGroupInfoDesc //OUGroupInfoDesc
let group_info_descriptor: DescriptorHeader = reader.read_be()?; let group_info_descriptor: DescriptorHeader = reader.read_be()?;
if group_info_descriptor.tag != 0x13 {return Err(format!("Unexpected descriptor type in OUUpgradeItemDesc, Expected: 0x13, Got: 0x{:02x}!", group_info_descriptor.tag).into())} if group_info_descriptor.tag != 0x13 {return Err(format!("Unexpected descriptor type in OUUpgradeItemDesc, Expected: 0x13, Got: 0x{:02x}!", group_info_descriptor.tag).into())}
if CONFIG_PRINT_TREE { println!(" OUGroupInfoDesc(0x13) - Size: {}", group_info_descriptor.size); }; if print_tree { println!(" OUGroupInfoDesc(0x13) - Size: {}", group_info_descriptor.size); };
let group_id: u32 = reader.read_be()?; let group_id: u32 = reader.read_be()?;
if CONFIG_PRINT_TREE { println!(" Group ID: {}", group_id); }; if print_tree { println!(" Group ID: {}", group_id); };
//create the msd item with all infos //create the msd item with all infos
let msd_item = MSDItem { let msd_item = MSDItem {
@@ -223,9 +220,9 @@ pub fn parse_ouith_blob(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVe
} }
else if top_descriptor.tag == 0x02 { else if top_descriptor.tag == 0x02 {
if CONFIG_PRINT_TREE { println!("OUGroupDesc(0x02) - Size: {}", top_descriptor.size); }; if print_tree { println!("OUGroupDesc(0x02) - Size: {}", top_descriptor.size); };
let group_desc: OUGroupDesc = reader.read_be()?; let group_desc: OUGroupDesc = reader.read_be()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Group ID: {}", group_desc.group_id); println!(" Group ID: {}", group_desc.group_id);
println!(" Field 2: {}", group_desc.field_2); println!(" Field 2: {}", group_desc.field_2);
println!(" Field 3: {}", group_desc.field_3); println!(" Field 3: {}", group_desc.field_3);
@@ -236,9 +233,9 @@ pub fn parse_ouith_blob(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVe
let version_descriptor: DescriptorHeader = reader.read_be()?; let version_descriptor: DescriptorHeader = reader.read_be()?;
if ![0x09, 0x19, 0x14, 0x15].contains(&version_descriptor.tag) {return Err(format!("Unexpected descriptor type in OUGroupDesc, Expected: one of 0x09, 0x19, 0x14, 0x15, Got: 0x{:02x}!", version_descriptor.tag).into())} if ![0x09, 0x19, 0x14, 0x15].contains(&version_descriptor.tag) {return Err(format!("Unexpected descriptor type in OUGroupDesc, Expected: one of 0x09, 0x19, 0x14, 0x15, Got: 0x{:02x}!", version_descriptor.tag).into())}
if version_descriptor.tag == 0x19 { if version_descriptor.tag == 0x19 {
if CONFIG_PRINT_TREE { println!(" OUSWImageVersionExDesc(0x12) - Size: {}", version_descriptor.size); }; if print_tree { println!(" OUSWImageVersionExDesc(0x12) - Size: {}", version_descriptor.size); };
let sw_image_version_ex_desc: OUSWImageVersionExDesc = reader.read_be()?; let sw_image_version_ex_desc: OUSWImageVersionExDesc = reader.read_be()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Name lenght: {}", sw_image_version_ex_desc.name_len); println!(" Name lenght: {}", sw_image_version_ex_desc.name_len);
println!(" Name: {}", sw_image_version_ex_desc.name()); println!(" Name: {}", sw_image_version_ex_desc.name());
println!(" Major version: {}", sw_image_version_ex_desc.major_ver); println!(" Major version: {}", sw_image_version_ex_desc.major_ver);
@@ -252,7 +249,7 @@ pub fn parse_ouith_blob(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVe
} }
else { else {
//type not implemented, ignore the data //type not implemented, ignore the data
if CONFIG_PRINT_TREE { println!(" Unimplemented descriptor(0x{:02x}) - Size: {}", version_descriptor.tag, version_descriptor.size); }; if print_tree { println!(" Unimplemented descriptor(0x{:02x}) - Size: {}", version_descriptor.tag, version_descriptor.size); };
let _descriptor_data = common::read_exact(&mut reader, version_descriptor.size as usize); let _descriptor_data = common::read_exact(&mut reader, version_descriptor.size as usize);
} }
+25 -28
View File
@@ -5,9 +5,6 @@ use binrw::{BinRead, BinReaderExt};
use crate::utils::common; use crate::utils::common;
// whether to print the tree
static CONFIG_PRINT_TREE: bool = false;
#[derive(BinRead)] #[derive(BinRead)]
struct DescriptorHeader { struct DescriptorHeader {
_flag: u8, _flag: u8,
@@ -107,7 +104,7 @@ pub struct MSDItem {
pub aes_salt: Option<Vec<u8>>, pub aes_salt: Option<Vec<u8>>,
} }
pub fn parse_blob_1_8(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVersionDesc>), Box<dyn std::error::Error>> { pub fn parse_blob_1_8(blob: &[u8], print_tree: bool) -> Result<(Vec<MSDItem>, Option<OUSWImageVersionDesc>), Box<dyn std::error::Error>> {
let mut reader = Cursor::new(blob); let mut reader = Cursor::new(blob);
let mut items: Vec<MSDItem> = Vec::new(); let mut items: Vec<MSDItem> = Vec::new();
let mut info: Option<OUSWImageVersionDesc> = None; let mut info: Option<OUSWImageVersionDesc> = None;
@@ -119,15 +116,15 @@ pub fn parse_blob_1_8(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVers
} }
let top_level_descriptor_count: u32 = reader.read_be()?; //BIG ENDIAN let top_level_descriptor_count: u32 = reader.read_be()?; //BIG ENDIAN
if CONFIG_PRINT_TREE { println!("\nTop level descriptor count: {}", top_level_descriptor_count); }; if print_tree { println!("\nTop level descriptor count: {}", top_level_descriptor_count); };
for _i in 0..top_level_descriptor_count { for _i in 0..top_level_descriptor_count {
//parse top level descriptor. it can only be ID 1(OUUpgradeItemDesc) or 2(OUGroupDesc) //parse top level descriptor. it can only be ID 1(OUUpgradeItemDesc) or 2(OUGroupDesc)
let top_descriptor: DescriptorHeader = reader.read_be()?; let top_descriptor: DescriptorHeader = reader.read_be()?;
if top_descriptor.tag == 0x01 { if top_descriptor.tag == 0x01 {
if CONFIG_PRINT_TREE { println!("OUUpgradeItemDesc(0x01) - Size: {}", top_descriptor.size); }; if print_tree { println!("OUUpgradeItemDesc(0x01) - Size: {}", top_descriptor.size); };
let upgrade_item_desc: OUUpgradeItemDesc = reader.read_be()?; let upgrade_item_desc: OUUpgradeItemDesc = reader.read_be()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Item ID: {}", upgrade_item_desc.item_id); println!(" Item ID: {}", upgrade_item_desc.item_id);
println!(" Unknown flag: {}", upgrade_item_desc.unk_flag); println!(" Unknown flag: {}", upgrade_item_desc.unk_flag);
println!(" Original size: {}", upgrade_item_desc.original_size); println!(" Original size: {}", upgrade_item_desc.original_size);
@@ -136,7 +133,7 @@ pub fn parse_blob_1_8(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVers
}; };
let subdesc_count: u32 = reader.read_le()?; //LITTLE ENDIAN?? let subdesc_count: u32 = reader.read_le()?; //LITTLE ENDIAN??
if CONFIG_PRINT_TREE { println!(" Subdescriptor count: {}", subdesc_count); }; if print_tree { println!(" Subdescriptor count: {}", subdesc_count); };
let mut name: Option<String> = None; let mut name: Option<String> = None;
//let mut crc32_hash: Option<u32> = None; //let mut crc32_hash: Option<u32> = None;
@@ -146,9 +143,9 @@ pub fn parse_blob_1_8(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVers
for _i in 0..subdesc_count { for _i in 0..subdesc_count {
let sub_descriptor: DescriptorHeader = reader.read_be()?; let sub_descriptor: DescriptorHeader = reader.read_be()?;
if sub_descriptor.tag == 0x0A { if sub_descriptor.tag == 0x0A {
if CONFIG_PRINT_TREE { println!(" OUPartitionVersionDesc(0x0A) - Size: {}", sub_descriptor.size); }; if print_tree { println!(" OUPartitionVersionDesc(0x0A) - Size: {}", sub_descriptor.size); };
let partition_version_desc: OUPartitionVersionDesc = reader.read_be()?; let partition_version_desc: OUPartitionVersionDesc = reader.read_be()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Name lenght: {}", partition_version_desc.name_len); println!(" Name lenght: {}", partition_version_desc.name_len);
println!(" Name: {}", partition_version_desc.name()); println!(" Name: {}", partition_version_desc.name());
println!(" Version: {}", partition_version_desc.version); println!(" Version: {}", partition_version_desc.version);
@@ -157,32 +154,32 @@ pub fn parse_blob_1_8(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVers
name = Some(partition_version_desc.name()); name = Some(partition_version_desc.name());
} }
else if sub_descriptor.tag == 0x07 { else if sub_descriptor.tag == 0x07 {
if CONFIG_PRINT_TREE { println!(" OUDataProcessingDesc(0x07) - Size: {}", sub_descriptor.size); }; if print_tree { println!(" OUDataProcessingDesc(0x07) - Size: {}", sub_descriptor.size); };
let data_processing_desc: OUDataProcessingDesc = reader.read_le()?; //LITTLE ENDIAN?? let data_processing_desc: OUDataProcessingDesc = reader.read_le()?; //LITTLE ENDIAN??
if CONFIG_PRINT_TREE { println!(" Subdescriptor count: {}", data_processing_desc.subdesc_count); }; if print_tree { println!(" Subdescriptor count: {}", data_processing_desc.subdesc_count); };
for _i in 0..data_processing_desc.subdesc_count { for _i in 0..data_processing_desc.subdesc_count {
let data_processing_sub_desc: DescriptorHeader = reader.read_be()?; let data_processing_sub_desc: DescriptorHeader = reader.read_be()?;
if data_processing_sub_desc.tag == 0x12 { if data_processing_sub_desc.tag == 0x12 {
if CONFIG_PRINT_TREE { println!(" OUCRC32ValidationDesc(0x12) - Size: {}", data_processing_sub_desc.size); }; if print_tree { println!(" OUCRC32ValidationDesc(0x12) - Size: {}", data_processing_sub_desc.size); };
let crc32_validation_desc: OUCRC32ValidationDesc = reader.read_be()?; let crc32_validation_desc: OUCRC32ValidationDesc = reader.read_be()?;
if CONFIG_PRINT_TREE { println!(" CRC32: {:02x}", crc32_validation_desc.crc32); }; if print_tree { println!(" CRC32: {:02x}", crc32_validation_desc.crc32); };
//crc32_hash = Some(crc32_validation_desc.crc32); //crc32_hash = Some(crc32_validation_desc.crc32);
} }
else if data_processing_sub_desc.tag == 0x10 { else if data_processing_sub_desc.tag == 0x10 {
if CONFIG_PRINT_TREE { println!(" OURSAValidationDesc(0x10) - Size: {}", data_processing_sub_desc.size); }; if print_tree { println!(" OURSAValidationDesc(0x10) - Size: {}", data_processing_sub_desc.size); };
let rsa_validation_desc: OURSAValidationDesc = reader.read_be()?; let rsa_validation_desc: OURSAValidationDesc = reader.read_be()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Signature size: {}", rsa_validation_desc.signature_size); println!(" Signature size: {}", rsa_validation_desc.signature_size);
println!(" Public key ID: {}", rsa_validation_desc.public_key_id); println!(" Public key ID: {}", rsa_validation_desc.public_key_id);
println!(" Signature: {}", hex::encode(&rsa_validation_desc.signature)); println!(" Signature: {}", hex::encode(&rsa_validation_desc.signature));
}; };
} }
else if data_processing_sub_desc.tag == 0x0E { else if data_processing_sub_desc.tag == 0x0E {
if CONFIG_PRINT_TREE { println!(" OUAESEncryptionDesc(0x0E) - Size: {}", data_processing_sub_desc.size); }; if print_tree { println!(" OUAESEncryptionDesc(0x0E) - Size: {}", data_processing_sub_desc.size); };
let aes_encryption_desc: OUAESEncryptionDesc = reader.read_be()?; let aes_encryption_desc: OUAESEncryptionDesc = reader.read_be()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Private key ID: {}", aes_encryption_desc.private_key_id); println!(" Private key ID: {}", aes_encryption_desc.private_key_id);
println!(" Salt size: {}", aes_encryption_desc.salt_size); println!(" Salt size: {}", aes_encryption_desc.salt_size);
println!(" Salt: {}", hex::encode(&aes_encryption_desc.salt)); println!(" Salt: {}", hex::encode(&aes_encryption_desc.salt));
@@ -193,19 +190,19 @@ pub fn parse_blob_1_8(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVers
aes_salt = Some(aes_encryption_desc.salt); aes_salt = Some(aes_encryption_desc.salt);
} }
else { else {
if CONFIG_PRINT_TREE { println!(" Unimplemented Descriptor(0x{:02x}) - Size: {}", data_processing_sub_desc.tag, data_processing_sub_desc.size); }; if print_tree { println!(" Unimplemented Descriptor(0x{:02x}) - Size: {}", data_processing_sub_desc.tag, data_processing_sub_desc.size); };
let _ = common::read_exact(&mut reader, data_processing_sub_desc.size as usize - 4)?; let _ = common::read_exact(&mut reader, data_processing_sub_desc.size as usize - 4)?;
} }
} }
} }
else if sub_descriptor.tag == 0x13 { else if sub_descriptor.tag == 0x13 {
if CONFIG_PRINT_TREE { println!(" OUGroupInfoDesc(0x13) - Size: {}", sub_descriptor.size); }; if print_tree { println!(" OUGroupInfoDesc(0x13) - Size: {}", sub_descriptor.size); };
let group_info_desc: OUGroupInfoDesc = reader.read_be()?; let group_info_desc: OUGroupInfoDesc = reader.read_be()?;
if CONFIG_PRINT_TREE { println!(" Group ID: {}", group_info_desc.group_id); }; if print_tree { println!(" Group ID: {}", group_info_desc.group_id); };
} }
else { else {
if CONFIG_PRINT_TREE { println!(" Unimplemented Descriptor(0x{:02x}) - Size: {}", sub_descriptor.tag, sub_descriptor.size); }; if print_tree { println!(" Unimplemented Descriptor(0x{:02x}) - Size: {}", sub_descriptor.tag, sub_descriptor.size); };
let _ = common::read_exact(&mut reader, sub_descriptor.size as usize - 4)?; let _ = common::read_exact(&mut reader, sub_descriptor.size as usize - 4)?;
} }
} }
@@ -227,22 +224,22 @@ pub fn parse_blob_1_8(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVers
} }
} }
else if top_descriptor.tag == 0x02 { else if top_descriptor.tag == 0x02 {
if CONFIG_PRINT_TREE { println!("OUGroupDesc(0x02) - Size: {}", top_descriptor.size); }; if print_tree { println!("OUGroupDesc(0x02) - Size: {}", top_descriptor.size); };
let group_desc: OUGroupDesc = reader.read_be()?; let group_desc: OUGroupDesc = reader.read_be()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Group ID: {}", group_desc.group_id); println!(" Group ID: {}", group_desc.group_id);
println!(" Unknown: {}", group_desc.unknown); println!(" Unknown: {}", group_desc.unknown);
}; };
let subdesc_count: u32 = reader.read_le()?; //LITTLE ENDIAN?? let subdesc_count: u32 = reader.read_le()?; //LITTLE ENDIAN??
if CONFIG_PRINT_TREE { println!(" Subdescriptor count: {}", subdesc_count); }; if print_tree { println!(" Subdescriptor count: {}", subdesc_count); };
for _i in 0..subdesc_count { for _i in 0..subdesc_count {
let sub_descriptor: DescriptorHeader = reader.read_be()?; let sub_descriptor: DescriptorHeader = reader.read_be()?;
if sub_descriptor.tag == 0x19 { if sub_descriptor.tag == 0x19 {
if CONFIG_PRINT_TREE { println!(" OUSWImageVersionDesc(0x19) - Size: {}", sub_descriptor.size); }; if print_tree { println!(" OUSWImageVersionDesc(0x19) - Size: {}", sub_descriptor.size); };
let sw_image_version_desc: OUSWImageVersionDesc = reader.read_be()?; let sw_image_version_desc: OUSWImageVersionDesc = reader.read_be()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Name lenght: {}", sw_image_version_desc.name_len); println!(" Name lenght: {}", sw_image_version_desc.name_len);
println!(" Name: {}", sw_image_version_desc.name()); println!(" Name: {}", sw_image_version_desc.name());
println!(" Major ver: {}", sw_image_version_desc.major_ver); println!(" Major ver: {}", sw_image_version_desc.major_ver);
@@ -254,7 +251,7 @@ pub fn parse_blob_1_8(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVers
info = Some(sw_image_version_desc); info = Some(sw_image_version_desc);
} else { } else {
if CONFIG_PRINT_TREE { println!(" Unimplemented Descriptor (0x{:02x}) - Size: {}", sub_descriptor.tag, sub_descriptor.size); }; if print_tree { println!(" Unimplemented Descriptor (0x{:02x}) - Size: {}", sub_descriptor.tag, sub_descriptor.size); };
let _ = common::read_exact(&mut reader, sub_descriptor.size as usize - 4)?; let _ = common::read_exact(&mut reader, sub_descriptor.size as usize - 4)?;
} }
} }
+27 -30
View File
@@ -5,9 +5,6 @@ use binrw::{BinRead, BinReaderExt};
use crate::utils::common; use crate::utils::common;
// whether to print the tree
static CONFIG_PRINT_TREE: bool = false;
#[derive(BinRead)] #[derive(BinRead)]
struct DescriptorHeader { struct DescriptorHeader {
_flag: u8, _flag: u8,
@@ -109,7 +106,7 @@ pub struct MSDItem {
pub aes_salt: Option<Vec<u8>>, pub aes_salt: Option<Vec<u8>>,
} }
pub fn parse_blob_1_9(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVersionDesc>), Box<dyn std::error::Error>> { pub fn parse_blob_1_9(blob: &[u8], print_tree: bool) -> Result<(Vec<MSDItem>, Option<OUSWImageVersionDesc>), Box<dyn std::error::Error>> {
let mut reader = Cursor::new(blob); let mut reader = Cursor::new(blob);
let mut items: Vec<MSDItem> = Vec::new(); let mut items: Vec<MSDItem> = Vec::new();
let mut info: Option<OUSWImageVersionDesc> = None; let mut info: Option<OUSWImageVersionDesc> = None;
@@ -124,15 +121,15 @@ pub fn parse_blob_1_9(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVers
} }
let top_level_descriptor_count: u32 = reader.read_le()?; let top_level_descriptor_count: u32 = reader.read_le()?;
if CONFIG_PRINT_TREE { println!("\nTop level descriptor count: {}", top_level_descriptor_count); }; if print_tree { println!("\nTop level descriptor count: {}", top_level_descriptor_count); };
for _i in 0..top_level_descriptor_count { for _i in 0..top_level_descriptor_count {
//parse top level descriptor. it can only be ID 1(OUUpgradeItemDesc) or 2(OUGroupDesc) or 0x37(OUSecureDowngradeDesc) //parse top level descriptor. it can only be ID 1(OUUpgradeItemDesc) or 2(OUGroupDesc) or 0x37(OUSecureDowngradeDesc)
let top_descriptor: DescriptorHeader = reader.read_le()?; let top_descriptor: DescriptorHeader = reader.read_le()?;
if top_descriptor.tag == 0x01 { if top_descriptor.tag == 0x01 {
if CONFIG_PRINT_TREE { println!("OUUpgradeItemDesc(0x01) - Size: {}", top_descriptor.size); }; if print_tree { println!("OUUpgradeItemDesc(0x01) - Size: {}", top_descriptor.size); };
let upgrade_item_desc: OUUpgradeItemDesc = reader.read_le()?; let upgrade_item_desc: OUUpgradeItemDesc = reader.read_le()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Item ID: {}", upgrade_item_desc.item_id); println!(" Item ID: {}", upgrade_item_desc.item_id);
println!(" Unknown flag: {}", upgrade_item_desc.unk_flag); println!(" Unknown flag: {}", upgrade_item_desc.unk_flag);
println!(" Original size: {}", upgrade_item_desc.original_size); println!(" Original size: {}", upgrade_item_desc.original_size);
@@ -141,7 +138,7 @@ pub fn parse_blob_1_9(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVers
}; };
let subdesc_count: u32 = reader.read_le()?; let subdesc_count: u32 = reader.read_le()?;
if CONFIG_PRINT_TREE { println!(" Subdescriptor count: {}", subdesc_count); }; if print_tree { println!(" Subdescriptor count: {}", subdesc_count); };
let mut name: Option<String> = None; let mut name: Option<String> = None;
//let mut crc32_hash: Option<u32> = None; //let mut crc32_hash: Option<u32> = None;
@@ -151,9 +148,9 @@ pub fn parse_blob_1_9(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVers
for _i in 0..subdesc_count { for _i in 0..subdesc_count {
let sub_descriptor: DescriptorHeader = reader.read_le()?; let sub_descriptor: DescriptorHeader = reader.read_le()?;
if sub_descriptor.tag == 0x0A { if sub_descriptor.tag == 0x0A {
if CONFIG_PRINT_TREE { println!(" OUPartitionVersionDesc(0x0A) - Size: {}", sub_descriptor.size); }; if print_tree { println!(" OUPartitionVersionDesc(0x0A) - Size: {}", sub_descriptor.size); };
let partition_version_desc: OUPartitionVersionDesc = reader.read_le()?; let partition_version_desc: OUPartitionVersionDesc = reader.read_le()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Name lenght: {}", partition_version_desc.name_len); println!(" Name lenght: {}", partition_version_desc.name_len);
println!(" Name: {}", partition_version_desc.name()); println!(" Name: {}", partition_version_desc.name());
}; };
@@ -161,32 +158,32 @@ pub fn parse_blob_1_9(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVers
name = Some(partition_version_desc.name()); name = Some(partition_version_desc.name());
} }
else if sub_descriptor.tag == 0x07 { else if sub_descriptor.tag == 0x07 {
if CONFIG_PRINT_TREE { println!(" OUDataProcessingDesc(0x07) - Size: {}", sub_descriptor.size); }; if print_tree { println!(" OUDataProcessingDesc(0x07) - Size: {}", sub_descriptor.size); };
let data_processing_desc: OUDataProcessingDesc = reader.read_le()?; let data_processing_desc: OUDataProcessingDesc = reader.read_le()?;
if CONFIG_PRINT_TREE { println!(" Subdescriptor count: {}", data_processing_desc.subdesc_count); }; if print_tree { println!(" Subdescriptor count: {}", data_processing_desc.subdesc_count); };
for _i in 0..data_processing_desc.subdesc_count { for _i in 0..data_processing_desc.subdesc_count {
let data_processing_sub_desc: DescriptorHeader = reader.read_le()?; let data_processing_sub_desc: DescriptorHeader = reader.read_le()?;
if data_processing_sub_desc.tag == 0x12 { if data_processing_sub_desc.tag == 0x12 {
if CONFIG_PRINT_TREE { println!(" OUCRC32ValidationDesc(0x12) - Size: {}", data_processing_sub_desc.size); }; if print_tree { println!(" OUCRC32ValidationDesc(0x12) - Size: {}", data_processing_sub_desc.size); };
let crc32_validation_desc: OUCRC32ValidationDesc = reader.read_le()?; let crc32_validation_desc: OUCRC32ValidationDesc = reader.read_le()?;
if CONFIG_PRINT_TREE { println!(" CRC32: {:02x}", crc32_validation_desc.crc32); }; if print_tree { println!(" CRC32: {:02x}", crc32_validation_desc.crc32); };
//crc32_hash = Some(crc32_validation_desc.crc32); //crc32_hash = Some(crc32_validation_desc.crc32);
} }
else if data_processing_sub_desc.tag == 0x10 { else if data_processing_sub_desc.tag == 0x10 {
if CONFIG_PRINT_TREE { println!(" OURSAValidationDesc(0x10) - Size: {}", data_processing_sub_desc.size); }; if print_tree { println!(" OURSAValidationDesc(0x10) - Size: {}", data_processing_sub_desc.size); };
let rsa_validation_desc: OURSAValidationDesc = reader.read_le()?; let rsa_validation_desc: OURSAValidationDesc = reader.read_le()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Signature size: {}", rsa_validation_desc.signature_size); println!(" Signature size: {}", rsa_validation_desc.signature_size);
println!(" Public key ID: {}", rsa_validation_desc.public_key_id); println!(" Public key ID: {}", rsa_validation_desc.public_key_id);
println!(" Signature: {}", hex::encode(&rsa_validation_desc.signature)); println!(" Signature: {}", hex::encode(&rsa_validation_desc.signature));
}; };
} }
else if data_processing_sub_desc.tag == 0x0E { else if data_processing_sub_desc.tag == 0x0E {
if CONFIG_PRINT_TREE { println!(" OUAESEncryptionDesc(0x0E) - Size: {}", data_processing_sub_desc.size); }; if print_tree { println!(" OUAESEncryptionDesc(0x0E) - Size: {}", data_processing_sub_desc.size); };
let aes_encryption_desc: OUAESEncryptionDesc = reader.read_le()?; let aes_encryption_desc: OUAESEncryptionDesc = reader.read_le()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Salt size: {}", aes_encryption_desc.salt_size); println!(" Salt size: {}", aes_encryption_desc.salt_size);
println!(" Salt: {}", hex::encode(&aes_encryption_desc.salt)); println!(" Salt: {}", hex::encode(&aes_encryption_desc.salt));
println!(" Processed size: {}", aes_encryption_desc.processed_size); println!(" Processed size: {}", aes_encryption_desc.processed_size);
@@ -196,19 +193,19 @@ pub fn parse_blob_1_9(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVers
aes_salt = Some(aes_encryption_desc.salt); aes_salt = Some(aes_encryption_desc.salt);
} }
else { else {
if CONFIG_PRINT_TREE { println!(" Unimplemented Descriptor(0x{:02x}) - Size: {}", data_processing_sub_desc.tag, data_processing_sub_desc.size); }; if print_tree { println!(" Unimplemented Descriptor(0x{:02x}) - Size: {}", data_processing_sub_desc.tag, data_processing_sub_desc.size); };
let _ = common::read_exact(&mut reader, data_processing_sub_desc.size as usize - 4)?; let _ = common::read_exact(&mut reader, data_processing_sub_desc.size as usize - 4)?;
} }
} }
} }
else if sub_descriptor.tag == 0x13 { else if sub_descriptor.tag == 0x13 {
if CONFIG_PRINT_TREE { println!(" OUGroupInfoDesc(0x13) - Size: {}", sub_descriptor.size); }; if print_tree { println!(" OUGroupInfoDesc(0x13) - Size: {}", sub_descriptor.size); };
let group_info_desc: OUGroupInfoDesc = reader.read_le()?; let group_info_desc: OUGroupInfoDesc = reader.read_le()?;
if CONFIG_PRINT_TREE { println!(" Group ID: {}", group_info_desc.group_id); }; if print_tree { println!(" Group ID: {}", group_info_desc.group_id); };
} }
else { else {
if CONFIG_PRINT_TREE { println!(" Unimplemented Descriptor(0x{:02x}) - Size: {}", sub_descriptor.tag, sub_descriptor.size); }; if print_tree { println!(" Unimplemented Descriptor(0x{:02x}) - Size: {}", sub_descriptor.tag, sub_descriptor.size); };
let _ = common::read_exact(&mut reader, sub_descriptor.size as usize - 4)?; let _ = common::read_exact(&mut reader, sub_descriptor.size as usize - 4)?;
} }
} }
@@ -230,19 +227,19 @@ pub fn parse_blob_1_9(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVers
} }
} }
else if top_descriptor.tag == 0x02 { else if top_descriptor.tag == 0x02 {
if CONFIG_PRINT_TREE { println!("OUGroupDesc(0x02) - Size: {}", top_descriptor.size); }; if print_tree { println!("OUGroupDesc(0x02) - Size: {}", top_descriptor.size); };
let group_desc: OUGroupDesc = reader.read_le()?; let group_desc: OUGroupDesc = reader.read_le()?;
if CONFIG_PRINT_TREE { println!(" Group ID: {}", group_desc.group_id); }; if print_tree { println!(" Group ID: {}", group_desc.group_id); };
let subdesc_count: u32 = reader.read_le()?; //LITTLE ENDIAN?? let subdesc_count: u32 = reader.read_le()?; //LITTLE ENDIAN??
if CONFIG_PRINT_TREE { println!(" Subdescriptor count: {}", subdesc_count); }; if print_tree { println!(" Subdescriptor count: {}", subdesc_count); };
for _i in 0..subdesc_count { for _i in 0..subdesc_count {
let sub_descriptor: DescriptorHeader = reader.read_le()?; let sub_descriptor: DescriptorHeader = reader.read_le()?;
if sub_descriptor.tag == 0x19 { if sub_descriptor.tag == 0x19 {
if CONFIG_PRINT_TREE { println!(" OUSWImageVersionDesc(0x19) - Size: {}", sub_descriptor.size); }; if print_tree { println!(" OUSWImageVersionDesc(0x19) - Size: {}", sub_descriptor.size); };
let sw_image_version_desc: OUSWImageVersionDesc = reader.read_le()?; let sw_image_version_desc: OUSWImageVersionDesc = reader.read_le()?;
if CONFIG_PRINT_TREE { if print_tree {
println!(" Name lenght: {}", sw_image_version_desc.name_len); println!(" Name lenght: {}", sw_image_version_desc.name_len);
println!(" Name: {}", sw_image_version_desc.name()); println!(" Name: {}", sw_image_version_desc.name());
println!(" Major ver: {}", sw_image_version_desc.major_ver); println!(" Major ver: {}", sw_image_version_desc.major_ver);
@@ -251,15 +248,15 @@ pub fn parse_blob_1_9(blob: &[u8]) -> Result<(Vec<MSDItem>, Option<OUSWImageVers
info = Some(sw_image_version_desc); info = Some(sw_image_version_desc);
} else { } else {
if CONFIG_PRINT_TREE { println!(" Unimplemented Descriptor (0x{:02x}) - Size: {}", sub_descriptor.tag, sub_descriptor.size); }; if print_tree { println!(" Unimplemented Descriptor (0x{:02x}) - Size: {}", sub_descriptor.tag, sub_descriptor.size); };
let _ = common::read_exact(&mut reader, sub_descriptor.size as usize - 4)?; let _ = common::read_exact(&mut reader, sub_descriptor.size as usize - 4)?;
} }
} }
} }
else if top_descriptor.tag == 0x37 { else if top_descriptor.tag == 0x37 {
if CONFIG_PRINT_TREE { println!("OUSecureDowngradeDesc(0x37) - Size: {}", top_descriptor.size); }; if print_tree { println!("OUSecureDowngradeDesc(0x37) - Size: {}", top_descriptor.size); };
let secure_downgrade_desc: OUSecureDowngradeDesc = reader.read_le()?; let secure_downgrade_desc: OUSecureDowngradeDesc = reader.read_le()?;
if CONFIG_PRINT_TREE { println!(" Image generation timestamp: {}", secure_downgrade_desc.image_generation_date); }; if print_tree { println!(" Image generation timestamp: {}", secure_downgrade_desc.image_generation_date); };
} }
else { else {
return Err(format!("Unexpected top level descriptor type 0x{:02x}!", top_descriptor.tag).into()); return Err(format!("Unexpected top level descriptor type 0x{:02x}!", top_descriptor.tag).into());
+3 -2
View File
@@ -28,6 +28,7 @@ pub fn is_msd10_file(app_ctx: &AppContext) -> Result<Option<Box<dyn Any>>, Box<d
pub fn extract_msd10(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<dyn std::error::Error>> { pub fn extract_msd10(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<dyn std::error::Error>> {
let mut file = app_ctx.file().ok_or("Extractor expected file")?; let mut file = app_ctx.file().ok_or("Extractor expected file")?;
let save_cmac = app_ctx.options.iter().any(|e| e == "msd10:save_cmac"); let save_cmac = app_ctx.options.iter().any(|e| e == "msd10:save_cmac");
let print_ouith_tree = app_ctx.options.iter().any(|e| e == "msd:print_ouith");
let header: FileHeader = file.read_le()?; let header: FileHeader = file.read_le()?;
println!("\nNumber of sections: {}", header.section_count); println!("\nNumber of sections: {}", header.section_count);
@@ -81,7 +82,7 @@ pub fn extract_msd10(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box
//parse TOC //parse TOC
if firmware_type == "tizen" { if firmware_type == "tizen" {
let toc = decrypt_aes_salted_tizen(&toc_data, &passphrase_bytes)?; let toc = decrypt_aes_salted_tizen(&toc_data, &passphrase_bytes)?;
let (items, info) = parse_blob_1_8(&toc)?; let (items, info) = parse_blob_1_8(&toc, print_ouith_tree)?;
if let Some(info) = info { if let Some(info) = info {
println!("\nImage info:\n{} {}.{} {}/{}/{}", println!("\nImage info:\n{} {}.{} {}/{}/{}",
@@ -121,7 +122,7 @@ pub fn extract_msd10(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box
} else if firmware_type == "old" { } else if firmware_type == "old" {
let toc = decrypt_aes_salted_old(&toc_data, &passphrase_bytes)?; let toc = decrypt_aes_salted_old(&toc_data, &passphrase_bytes)?;
let (items, info) = parse_ouith_blob(&toc)?; let (items, info) = parse_ouith_blob(&toc, print_ouith_tree)?;
if let Some(info) = info { if let Some(info) = info {
println!("\nImage info:\n{} {}.{} {}/{}/20{}", println!("\nImage info:\n{} {}.{} {}/{}/20{}",
+2 -1
View File
@@ -26,6 +26,7 @@ pub fn is_msd11_file(app_ctx: &AppContext) -> Result<Option<Box<dyn Any>>, Box<d
pub fn extract_msd11(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<dyn std::error::Error>> { pub fn extract_msd11(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<dyn std::error::Error>> {
let mut file = app_ctx.file().ok_or("Extractor expected file")?; let mut file = app_ctx.file().ok_or("Extractor expected file")?;
let print_ouith_tree = app_ctx.options.iter().any(|e| e == "msd:print_ouith");
let header: FileHeader = file.read_le()?; let header: FileHeader = file.read_le()?;
println!("\nNumber of sections: {}", header.section_count); println!("\nNumber of sections: {}", header.section_count);
@@ -73,7 +74,7 @@ pub fn extract_msd11(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box
let toc_data = common::read_file(&file, toc_offset as u64, toc_size as usize)?; let toc_data = common::read_file(&file, toc_offset as u64, toc_size as usize)?;
let toc = decrypt_aes_salted_tizen(&toc_data, &passphrase_bytes)?; let toc = decrypt_aes_salted_tizen(&toc_data, &passphrase_bytes)?;
let (items, info) = parse_blob_1_9(&toc)?; let (items, info) = parse_blob_1_9(&toc, print_ouith_tree)?;
if let Some(info) = info { if let Some(info) = info {
println!("\nImage info:\n{} {}.{}", println!("\nImage info:\n{} {}.{}",
+5 -2
View File
@@ -43,6 +43,7 @@ pub fn is_mtk_pkg_file(app_ctx: &AppContext) -> Result<Option<Box<dyn Any>>, Box
pub fn extract_mtk_pkg(app_ctx: &AppContext, ctx: Box<dyn Any>) -> Result<(), Box<dyn std::error::Error>> { pub fn extract_mtk_pkg(app_ctx: &AppContext, ctx: Box<dyn Any>) -> Result<(), Box<dyn std::error::Error>> {
let mut file = app_ctx.file().ok_or("Extractor expected file")?; let mut file = app_ctx.file().ok_or("Extractor expected file")?;
let ctx = ctx.downcast::<MtkPkgContext>().expect("Missing context"); let ctx = ctx.downcast::<MtkPkgContext>().expect("Missing context");
let no_del_comp = app_ctx.options.iter().any(|e| e == "mtk_pkg:no_del_comp");
let file_size = file.metadata()?.len(); let file_size = file.metadata()?.len();
let header = ctx.decrypted_header; let header = ctx.decrypted_header;
@@ -149,8 +150,10 @@ pub fn extract_mtk_pkg(app_ctx: &AppContext, ctx: Box<dyn Any>) -> Result<(), Bo
match decompress_lzhs_fs_file2file(&out_file, lzhs_out_path) { match decompress_lzhs_fs_file2file(&out_file, lzhs_out_path) {
Ok(()) => { Ok(()) => {
println!("- Decompressed Successfully!"); println!("- Decompressed Successfully!");
//after successfull decompression remove the temporary .lzhs file if !no_del_comp {
fs::remove_file(&output_path)?; //after successfull decompression remove the temporary .lzhs file
fs::remove_file(&output_path)?;
}
}, },
Err(e) => { Err(e) => {
eprintln!("Failed to decompress partition!, Error: {}. Saving compressed data...", e); eprintln!("Failed to decompress partition!, Error: {}. Saving compressed data...", e);
+5 -2
View File
@@ -46,6 +46,7 @@ pub fn is_mtk_pkg_new_file(app_ctx: &AppContext) -> Result<Option<Box<dyn Any>>,
pub fn extract_mtk_pkg_new(app_ctx: &AppContext, ctx: Box<dyn Any>) -> Result<(), Box<dyn std::error::Error>> { pub fn extract_mtk_pkg_new(app_ctx: &AppContext, ctx: Box<dyn Any>) -> Result<(), Box<dyn std::error::Error>> {
let mut file = app_ctx.file().ok_or("Extractor expected file")?; let mut file = app_ctx.file().ok_or("Extractor expected file")?;
let ctx = ctx.downcast::<MtkPkgNewContext>().expect("Missing context"); let ctx = ctx.downcast::<MtkPkgNewContext>().expect("Missing context");
let no_del_comp = app_ctx.options.iter().any(|e| e == "mtk_pkg:no_del_comp");
let file_size = file.metadata()?.len(); let file_size = file.metadata()?.len();
@@ -119,8 +120,10 @@ pub fn extract_mtk_pkg_new(app_ctx: &AppContext, ctx: Box<dyn Any>) -> Result<()
match decompress_lzhs_fs_file2file(&out_file, lzhs_out_path) { match decompress_lzhs_fs_file2file(&out_file, lzhs_out_path) {
Ok(()) => { Ok(()) => {
println!("-- Decompressed Successfully!"); println!("-- Decompressed Successfully!");
//after successfull decompression remove the temporary .lzhs file if !no_del_comp {
fs::remove_file(&output_path)?; //after successfull decompression remove the temporary .lzhs file
fs::remove_file(&output_path)?;
}
}, },
Err(e) => { Err(e) => {
eprintln!("Failed to decompress partition!, Error: {}. Saving compressed data...", e); eprintln!("Failed to decompress partition!, Error: {}. Saving compressed data...", e);
+5 -2
View File
@@ -36,6 +36,7 @@ pub fn is_mtk_pkg_old_file(app_ctx: &AppContext) -> Result<Option<Box<dyn Any>>,
pub fn extract_mtk_pkg_old(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<dyn std::error::Error>> { pub fn extract_mtk_pkg_old(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<dyn std::error::Error>> {
let mut file = app_ctx.file().ok_or("Extractor expected file")?; let mut file = app_ctx.file().ok_or("Extractor expected file")?;
let no_del_comp = app_ctx.options.iter().any(|e| e == "mtk_pkg:no_del_comp");
let file_size = file.metadata()?.len(); let file_size = file.metadata()?.len();
let encrypted_header = common::read_exact(&mut file, HEADER_SIZE)?; let encrypted_header = common::read_exact(&mut file, HEADER_SIZE)?;
@@ -89,8 +90,10 @@ pub fn extract_mtk_pkg_old(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(
match decompress_lzhs_fs_file2file_old(&out_file, lzhs_out_path) { match decompress_lzhs_fs_file2file_old(&out_file, lzhs_out_path) {
Ok(()) => { Ok(()) => {
println!("- Decompressed Successfully!"); println!("- Decompressed Successfully!");
//after successfull decompression remove the temporary .lzhs file if !no_del_comp {
fs::remove_file(&output_path)?; //after successfull decompression remove the temporary .lzhs file
fs::remove_file(&output_path)?;
}
}, },
Err(e) => { Err(e) => {
eprintln!("Failed to decompress partition!, Error: {}. Saving compressed data...", e); eprintln!("Failed to decompress partition!, Error: {}. Saving compressed data...", e);
+13 -1
View File
@@ -48,7 +48,10 @@ pub struct Header {
} }
impl Header { impl Header {
pub fn description(&self) -> String { pub fn description(&self) -> String {
common::string_from_bytes(&self.description_bytes) common::string_from_bytes(&self.description_bytes).replace('\r', "\n")
}
pub fn is_encrypted(&self) -> bool {
(self.mask & 0x2000_0000) != 0
} }
} }
@@ -64,4 +67,13 @@ impl FileHeader {
pub fn file_name(&self) -> String { pub fn file_name(&self) -> String {
common::string_from_bytes(&self.file_name_bytes) common::string_from_bytes(&self.file_name_bytes)
} }
pub fn is_folder(&self) -> bool {
(self.attributes[3] & (1 << 1)) != 0
}
pub fn has_extended_name(&self) -> bool {
(self.attributes[2] & (1 << 7)) != 0
}
pub fn _is_package(&self) -> bool {
(self.attributes[3] & (1 << 1)) != 0
}
} }
+3 -10
View File
@@ -39,7 +39,7 @@ pub fn extract_pfl_upg(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), B
println!("Data size: {}", header.data_size); println!("Data size: {}", header.data_size);
let mut decrypted_data; let mut decrypted_data;
if (header.mask & 0x2000_0000) != 0 { if header.is_encrypted() {
println!("File is encrypted."); println!("File is encrypted.");
let mut key = None; let mut key = None;
let mut n_hex = None; let mut n_hex = None;
@@ -95,16 +95,14 @@ pub fn extract_pfl_upg(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), B
while (data_reader.position() as usize) < data_reader.get_ref().len() { while (data_reader.position() as usize) < data_reader.get_ref().len() {
let file_header: FileHeader = data_reader.read_le()?; let file_header: FileHeader = data_reader.read_le()?;
//its a folder not a file if file_header.is_folder() {
if (file_header.attributes[3] & (1 << 1)) != 0 {
println!("\nFolder - {}", file_header.file_name()); println!("\nFolder - {}", file_header.file_name());
let output_path = Path::new(&app_ctx.output_dir).join(file_header.file_name().trim_start_matches('/')); let output_path = Path::new(&app_ctx.output_dir).join(file_header.file_name().trim_start_matches('/'));
fs::create_dir_all(output_path)?; fs::create_dir_all(output_path)?;
continue continue
} }
//extended name is used let file_name = if file_header.has_extended_name() {
let file_name = if (file_header.attributes[2] & (1 << 7)) != 0 {
let ex_name_size = file_header.header_size - 76; //76 is base file header size let ex_name_size = file_header.header_size - 76; //76 is base file header size
//println!("extended name {}, org name: {}", ex_name_size, file_header.file_name()); //println!("extended name {}, org name: {}", ex_name_size, file_header.file_name());
let ex_name_bytes = common::read_exact(&mut data_reader, ex_name_size as usize)?; let ex_name_bytes = common::read_exact(&mut data_reader, ex_name_size as usize)?;
@@ -134,11 +132,6 @@ pub fn extract_pfl_upg(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), B
out_file.write_all(&data[..file_header.real_size as usize])?; out_file.write_all(&data[..file_header.real_size as usize])?;
//if it contains a PFL upg in itself to extract
//if (file_header.attributes[3] & (1 << 2)) != 0 {
// println!("Container file");
//}
println!("- Saved file!"); println!("- Saved file!");
} }