diff --git a/src/formats.rs b/src/formats.rs index 42693bf..3c15d68 100644 --- a/src/formats.rs +++ b/src/formats.rs @@ -7,4 +7,5 @@ pub mod novatek; pub mod msd10; pub mod msd11; pub mod sddl_sec; -pub mod epk2; \ No newline at end of file +pub mod epk2; +pub mod epk; \ No newline at end of file diff --git a/src/formats/epk.rs b/src/formats/epk.rs new file mode 100644 index 0000000..1e61924 --- /dev/null +++ b/src/formats/epk.rs @@ -0,0 +1,55 @@ +use std::fs::File; + +use crate::common; +use crate::formats; + +pub fn is_epk_file(file: &File) -> bool { + let versions = common::read_file(&file, 1712, 36).expect("Failed to read from file."); + + if check_epk_version(&versions).is_some() { + true + } else { + false + } +} + +fn check_epk_version(versions: &[u8]) -> Option { + let epk2_pattern = "____XXXX.XXXX.XXXX__XX.XX.XXX_______"; + let epk3_pattern = "____X.X.X___________X.X.X___________"; + + if match_with_pattern(&versions, epk2_pattern) { + Some("epk2".to_string()) + } else if match_with_pattern(&versions, epk3_pattern) { + Some("epk3".to_string()) + } else { + None + } +} + +fn match_with_pattern(data: &[u8], pattern: &str) -> bool { + for (&b, p) in data.iter().zip(pattern.bytes()) { + match p { + b'_' if b != 0x00 => return false, + b'X' if !b.is_ascii_digit() => return false, + b'.' if b != b'.' => return false, + _ if p != b'_' && p != b'X' && p != b'.' => return false, + _ => {} + } + } + true +} + +pub fn extract_epk(file: &File, output_folder: &str) -> Result<(), Box> { + + let versions = common::read_file(&file, 1712, 36)?; + let epk_version = check_epk_version(&versions); + + if epk_version == Some("epk2".to_string()) { + println!("EPK2 detected!\n"); + formats::epk2::extract_epk2(file, output_folder)?; + } else if epk_version == Some("epk3".to_string()) { + println!("EPK3 detected! Not supported yet."); + } + + Ok(()) +} \ No newline at end of file diff --git a/src/formats/epk2.rs b/src/formats/epk2.rs index 8cf9c9e..0020218 100644 --- a/src/formats/epk2.rs +++ b/src/formats/epk2.rs @@ -38,7 +38,17 @@ fn decrypt_aes128_ecb(key: &[u8], ciphertext: &[u8]) -> Result, Box Result<(), Box> { - let _epak = common::read_exact(&mut file, 4)?; // epak magic + + file.seek(SeekFrom::Start(128))?; + + //check if header is encrypted + let epak = common::read_exact(&mut file, 4)?; // epak magic + if epak == b"epak" { + println!("Header is not encrypted."); + } else { + println!("Header is encrypted. Not supported yet"); + return Ok(()); + } let file_size_bytes = common::read_exact(&mut file, 4)?; let file_size = u32::from_le_bytes(file_size_bytes.try_into().unwrap()); @@ -79,7 +89,14 @@ pub fn extract_epk2(mut file: &File, output_folder: &str) -> Result<(), Box Result<(), Box> { else if formats::epk1::is_epk1_file(&file) { println!("EPK1 file detected!"); formats::epk1::extract_epk1(&file, &output_path)?; - } + } + //epk2 with unencrypted header else if formats::epk2::is_epk2_file(&file) { println!("EPK2 file detected!"); formats::epk2::extract_epk2(&file, &output_path)?; - } + } + //epk with encrypted header - it can be epk2 or epk3 so we need to check + else if formats::epk::is_epk_file(&file) { + println!("EPK file detected!"); + formats::epk::extract_epk(&file, &output_path)?; + } else if formats::pfl_upg::is_pfl_upg_file(&file) { println!("PFL UPG file detected!"); formats::pfl_upg::extract_pfl_upg(&file, &output_path)?;