Files
unixtract/src/formats/epk.rs
T

118 lines
3.8 KiB
Rust
Raw Normal View History

2026-02-05 15:18:26 +01:00
use std::any::Any;
2026-02-05 18:53:35 +01:00
use crate::{AppContext, formats::Format};
2026-02-05 15:18:26 +01:00
pub fn format() -> Format {
2026-02-05 18:53:35 +01:00
Format { name: "epk", detector_func: is_epk_file, extractor_func: extract_epk }
2026-02-05 15:18:26 +01:00
}
2025-10-08 00:40:29 +02:00
use crate::utils::common;
2025-10-08 00:40:29 +02:00
use crate::formats;
2026-02-05 15:18:26 +01:00
pub struct EpkContext {
epk_version: u8,
}
2026-02-05 18:53:35 +01:00
pub fn is_epk_file(app_ctx: &AppContext) -> Result<Option<Box<dyn Any>>, Box<dyn std::error::Error>> {
2026-02-05 15:18:26 +01:00
let versions = common::read_file(app_ctx.file, 1712, 36)?;
2025-10-08 00:40:29 +02:00
2026-02-05 15:18:26 +01:00
if let Some(epk_version) = check_epk_version(&versions) {
Ok(Some(Box::new(EpkContext {epk_version})))
2025-10-08 00:40:29 +02:00
} else {
2026-02-05 15:18:26 +01:00
Ok(None)
2025-10-08 00:40:29 +02:00
}
}
2026-02-05 15:18:26 +01:00
fn check_epk_version(versions: &[u8]) -> Option<u8> {
2025-10-08 16:46:21 +02:00
// _ - 0x00 X - a number . - a dot
let epk2_pattern = "____XXXX.XXXX.XXXX__XX.XX.XXX_______";
let epk3_pattern = "____X.X.X___________X.X.X___________";
let epk3_new_pattern = "____XX.X.X__________XX.X.X__________";
2025-10-08 00:40:29 +02:00
if match_with_pattern(&versions, epk2_pattern) {
2026-02-05 15:18:26 +01:00
Some(2)
2025-10-08 00:40:29 +02:00
} else if match_with_pattern(&versions, epk3_pattern) {
2026-02-05 15:18:26 +01:00
Some(3)
2025-10-08 16:46:21 +02:00
} else if match_with_pattern(&versions, epk3_new_pattern) {
2026-02-05 15:18:26 +01:00
Some(3)
2025-10-08 16:46:21 +02:00
}else {
2025-10-08 00:40:29 +02:00
None
}
}
fn match_with_pattern(data: &[u8], pattern: &str) -> bool {
for (&b, p) in data.iter().zip(pattern.bytes()) {
match p {
2025-10-08 13:04:41 +02:00
b'_' if b != 0x00 => return false,
2025-10-08 00:40:29 +02:00
b'X' if !b.is_ascii_digit() => return false,
2025-10-08 13:04:41 +02:00
b'.' if b != b'.' => return false,
2025-10-08 00:40:29 +02:00
_ => {}
}
}
true
}
2026-02-05 18:53:35 +01:00
pub fn extract_epk(app_ctx: &AppContext, ctx: Option<Box<dyn Any>>) -> Result<(), Box<dyn std::error::Error>> {
2026-02-05 15:18:26 +01:00
let ctx = ctx.and_then(|c| c.downcast::<EpkContext>().ok()).ok_or("Context is invalid or missing!")?;
let versions = common::read_file(app_ctx.file, 1712, 36)?;
let platform_version = common::string_from_bytes(&versions[4..20]);
let sdk_version = common::string_from_bytes(&versions[20..36]);
println!("Platform version: {}\nSDK version: {}", platform_version, sdk_version);
2025-10-08 00:40:29 +02:00
2026-02-05 15:18:26 +01:00
if ctx.epk_version == 2 {
2025-10-08 00:40:29 +02:00
println!("EPK2 detected!\n");
2026-02-05 15:18:26 +01:00
formats::epk2::extract_epk2(app_ctx, None)?;
} else if ctx.epk_version == 3 {
println!("EPK3 detected!\n");
2026-02-05 15:18:26 +01:00
formats::epk3::extract_epk3(app_ctx, None)?;
2025-10-08 00:40:29 +02:00
}
Ok(())
}
//COMMON EPK FUNCTIONS
pub fn find_key<'a>(key_array: &'a [(&'a str, &'a str)], data: &[u8], expected_magic: &[u8]) -> Result<Option<(&'a str, Vec<u8>)>, Box<dyn std::error::Error>> {
for (key_hex, name) in key_array {
let key_bytes = hex::decode(key_hex)?;
let decrypted = match decrypt_aes_ecb_auto(&key_bytes, data) {
Ok(d) => d,
Err(_) => continue,
};
if decrypted.starts_with(expected_magic) {
return Ok(Some((name, key_bytes)));
}
}
Ok(None)
}
use aes::Aes128;
use aes::Aes256;
use ecb::{Decryptor, cipher::{BlockDecryptMut, KeyInit, generic_array::GenericArray}};
type Aes128EcbDec = Decryptor<Aes128>;
type Aes256EcbDec = Decryptor<Aes256>;
pub fn decrypt_aes_ecb_auto(key: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let mut buffer = ciphertext.to_vec();
if key.len() == 32 {
// aes256
let key_array: [u8; 32] = key.try_into()?;
let mut decryptor = Aes256EcbDec::new(&key_array.into());
for chunk in buffer.chunks_exact_mut(16) {
let block: &mut [u8; 16] = chunk.try_into()?;
decryptor.decrypt_block_mut(GenericArray::from_mut_slice(block));
}
} else {
// aes128
let key_array: [u8; 16] = key.try_into()?;
let mut decryptor = Aes128EcbDec::new(&key_array.into());
for chunk in buffer.chunks_exact_mut(16) {
let block: &mut [u8; 16] = chunk.try_into()?;
decryptor.decrypt_block_mut(GenericArray::from_mut_slice(block));
}
}
Ok(buffer)
2025-10-08 00:40:29 +02:00
}