RESTRUCTURING 1

- change formats to have their own folders with mod + include files + anything they want
- change format list to be defined in formats.rs instead of in each format
- move utils to their respective formats
- some minor code changes in some formats
This commit is contained in:
theubusu
2026-02-17 17:28:59 +01:00
parent 9fe39280cd
commit aa2249f024
69 changed files with 1678 additions and 1629 deletions
+64
View File
@@ -0,0 +1,64 @@
use crate::utils::common;
use binrw::BinRead;
#[derive(BinRead)]
pub struct RufHeader {
_magic_bytes: [u8; 6],
_upgrade_type_bytes: [u8; 2],
_unk1: u32,
date_time_bytes: [u8; 32],
buyer_bytes: [u8; 8],
model_bytes: [u8; 32],
region_info_bytes: [u8; 32],
pub version_bytes: [u8; 4],
pub data_size: u32,
_unk2: [u8; 20],
pub dual_ruf_flag: u32,
_unk3: [u8; 44],
pub payload_count: u16,
_payload_entry_size: u16,
pub payloads_start_offset: u32,
}
impl RufHeader {
pub fn date_time(&self) -> String {
common::string_from_bytes(&self.date_time_bytes)
}
pub fn buyer(&self) -> String {
common::string_from_bytes(&self.buyer_bytes)
}
pub fn model(&self) -> String {
common::string_from_bytes(&self.model_bytes)
}
pub fn region_info(&self) -> String {
common::string_from_bytes(&self.region_info_bytes)
}
pub fn is_dual_ruf(&self) -> bool {
if self.dual_ruf_flag == 0x44 {true} else {false}
}
}
#[derive(BinRead)]
pub struct RufEntry {
_metadata: [u8; 32],
pub payload_type_bytes: u32,
pub size: u32,
_unk1: u32,
_unk2: [u8; 20],
}
impl RufEntry {
pub fn payload_type(&self) -> &str {
if self.payload_type_bytes == 1 {
return "squashfs"
} else if self.payload_type_bytes == 2 {
return "cfe"
} else if self.payload_type_bytes == 3 {
return "vmlinuz"
} else if self.payload_type_bytes == 4 {
return "loader"
} else if self.payload_type_bytes == 5 {
return "splash"
} else {
return "unknown"
}
}
}
+119
View File
@@ -0,0 +1,119 @@
mod include;
use std::any::Any;
use crate::AppContext;
use std::path::{Path, PathBuf};
use std::fs::{self, File, OpenOptions};
use binrw::BinReaderExt;
use std::io::{Write, Seek, SeekFrom, Cursor};
use crate::utils::common;
use crate::keys;
use crate::utils::aes::{decrypt_aes128_cbc_pcks7};
use include::*;
pub fn is_ruf_file(app_ctx: &AppContext) -> Result<Option<Box<dyn Any>>, Box<dyn std::error::Error>> {
let file = match app_ctx.file() {Some(f) => f, None => return Ok(None)};
let header = common::read_file(&file, 0, 6)?;
if header == b"RUF\x00\x00\x00" {
Ok(Some(Box::new(())))
} else {
Ok(None)
}
}
pub fn extract_ruf(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 header: RufHeader = file.read_be()?;
if header.is_dual_ruf() {
println!("\nDual RUF detected! Extracting 1st RUF...\n");
actually_extract_ruf(file, &app_ctx.output_dir.join("RUF_1"), 0)?;
println!("\nExtracting 2nd RUF...\n");
actually_extract_ruf(file, &app_ctx.output_dir.join("RUF_2"), 41943088)?;
} else {
actually_extract_ruf(file, &app_ctx.output_dir, 0)?;
}
println!("\nExtraction finished!");
Ok(())
}
fn actually_extract_ruf(mut file: &File, output_folder: &PathBuf, start_offset: u64) -> Result<(), Box<dyn std::error::Error>> {
file.seek(SeekFrom::Start(start_offset))?;
let header: RufHeader = file.read_be()?;
println!("File info:\nBuyer: {} \nModel: {} \nRegion Info: {} \nDateTime: {}\nVersion:{:02x?} \nData Size: {} \nDual RUF: {}",
header.buyer(), header.model(), header.region_info(), header.date_time(), header.version_bytes, header.data_size, header.is_dual_ruf());
println!("\nPayload count: {}", header.payload_count);
file.seek(SeekFrom::Start(start_offset + header.payloads_start_offset as u64))?;
let mut entries: Vec<RufEntry> = Vec::new();
let mut vi = 0;
for _i in 0..28 {
if vi == header.payload_count {
break
}
let entry: RufEntry = file.read_be()?;
if entry.payload_type_bytes == 0 && entry.size == 0 {
continue
} else {
vi += 1
}
println!("{}/{}: Type: {}({}), Size: {}",
vi, header.payload_count, entry.payload_type_bytes, entry.payload_type(), entry.size);
entries.push(entry);
}
let mut key: Option<&str> = None;
let key_bytes;
let iv_bytes: [u8; 16] = [0x00; 16];
//find key
for (prefix, value) in keys::RUF {
if header.model().starts_with(prefix) {
key = Some(value);
break;
}
}
if let Some(k) = key {
println!("\nKey: {}", k);
key_bytes = hex::decode(k)?.as_slice().try_into()?;
} else {
println!("\nSorry, this firmware is not supported!");
std::process::exit(1);
}
file.seek(SeekFrom::Start(start_offset + 2048))?;
let encrypted_data = common::read_exact(&mut file, header.data_size as usize)?;
println!("Decrypting data...");
let decrypted_data = decrypt_aes128_cbc_pcks7(&encrypted_data, &key_bytes, &iv_bytes)?;
let mut data_reader = Cursor::new(decrypted_data);
let mut ei = 1;
for entry in entries {
println!("\n({}/{}) - {}({}), Size: {}",
ei, header.payload_count, entry.payload_type_bytes, entry.payload_type(), entry.size);
let data = common::read_exact(&mut data_reader, entry.size as usize)?;
let output_path = Path::new(&output_folder).join(format!("{}_{}.bin", entry.payload_type_bytes, entry.payload_type()));
fs::create_dir_all(&output_folder)?;
let mut out_file = OpenOptions::new().write(true).create(true).open(output_path)?;
out_file.write_all(&data)?;
println!("- Saved file!");
ei += 1;
}
Ok(())
}