mirror of
https://github.com/Ap0dexMe0/unixtract.git
synced 2026-07-16 05:04:22 +02:00
mstar: add support for old secure format, add option to keep unknown dest
This commit is contained in:
+40
-34
@@ -126,45 +126,51 @@ pub fn extract_mstar(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box
|
||||
|
||||
println!("\nPart - Offset: {}, Size: {} --> {}", offset, size, partname);
|
||||
|
||||
if partname == "unknown" {
|
||||
println!("- Unknown destination, skipping!");
|
||||
} else {
|
||||
let data = common::read_file(&file, offset, size.try_into().unwrap())?;
|
||||
let out_data;
|
||||
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", partname));
|
||||
|
||||
if compression == CompressionType::Lzma {
|
||||
println!("- Decompressing LZMA...");
|
||||
out_data = decompress_lzma(&data)?;
|
||||
} else if compression == CompressionType::DoubleLzma {
|
||||
println!("- Decompressing LZMA (Pass 1)...");
|
||||
let pass_1 = decompress_lzma(&data)?;
|
||||
println!("- Decompressing LZMA (Pass 2)...");
|
||||
out_data = decompress_lzma(&pass_1)?;
|
||||
} else if compression == CompressionType::Lz4 {
|
||||
println!("- Decompressing lz4, expected size: {}", lz4_expect_size);
|
||||
out_data = decompress_lz4(&data, lz4_expect_size.try_into().unwrap())?;
|
||||
} else if compression == CompressionType::Lzo {
|
||||
println!("- Decompessing LZO..");
|
||||
unlzop_to_file(&data, output_path)?;
|
||||
println!("-- Saved file!");
|
||||
i += 1;
|
||||
continue
|
||||
} else if compression == CompressionType::Sparse {
|
||||
println!("- Unsparsing...");
|
||||
unsparse_to_file(&data, output_path)?;
|
||||
println!("-- Saved file!");
|
||||
i += 1;
|
||||
continue
|
||||
let data = common::read_file(&file, offset, size.try_into().unwrap())?;
|
||||
let out_data;
|
||||
let output_path = if partname == "unknown" {
|
||||
if app_ctx.has_option("mstar:keep_unknown") {
|
||||
println!("- Warning, unknown destination - saving to _unknown_{}.bin", offset);
|
||||
Path::new(&app_ctx.output_dir).join(format!("_unknown_{}.bin", offset))
|
||||
} else {
|
||||
out_data = data;
|
||||
println!("- Warning, unknown destination - skipping...");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
Path::new(&app_ctx.output_dir).join(format!("{}.bin", partname))
|
||||
};
|
||||
|
||||
fs::create_dir_all(&app_ctx.output_dir)?;
|
||||
let mut out_file = OpenOptions::new().append(true).create(true).open(output_path)?;
|
||||
out_file.write_all(&out_data)?;
|
||||
if compression == CompressionType::Lzma {
|
||||
println!("- Decompressing LZMA...");
|
||||
out_data = decompress_lzma(&data)?;
|
||||
} else if compression == CompressionType::DoubleLzma {
|
||||
println!("- Decompressing LZMA (Pass 1)...");
|
||||
let pass_1 = decompress_lzma(&data)?;
|
||||
println!("- Decompressing LZMA (Pass 2)...");
|
||||
out_data = decompress_lzma(&pass_1)?;
|
||||
} else if compression == CompressionType::Lz4 {
|
||||
println!("- Decompressing lz4, expected size: {}", lz4_expect_size);
|
||||
out_data = decompress_lz4(&data, lz4_expect_size.try_into().unwrap())?;
|
||||
} else if compression == CompressionType::Lzo {
|
||||
println!("- Decompessing LZO..");
|
||||
unlzop_to_file(&data, output_path)?;
|
||||
println!("-- Saved file!");
|
||||
i += 1;
|
||||
continue
|
||||
} else if compression == CompressionType::Sparse {
|
||||
println!("- Unsparsing...");
|
||||
unsparse_to_file(&data, output_path)?;
|
||||
println!("-- Saved file!");
|
||||
i += 1;
|
||||
continue
|
||||
} else {
|
||||
out_data = data;
|
||||
}
|
||||
|
||||
fs::create_dir_all(&app_ctx.output_dir)?;
|
||||
let mut out_file = OpenOptions::new().append(true).create(true).open(output_path)?;
|
||||
out_file.write_all(&out_data)?;
|
||||
println!("-- Saved file!");
|
||||
}
|
||||
|
||||
i += 1;
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
use binrw::BinRead;
|
||||
|
||||
pub static MSTAR_DEFAULT_UPGRADE_KEY: [u8; 16] = [0x00, 0x07, 0xff, 0x41, 0x54, 0x53, 0x4d, 0x92, 0xfc, 0x55, 0xaa, 0x0f, 0xff, 0x01, 0x10, 0xe0];
|
||||
pub static CHUNK_ID: &[u8; 8] = b"MSTAR...";
|
||||
pub static CHUNK_END: &[u8; 8] = b"...mstar";
|
||||
|
||||
#[derive(BinRead)]
|
||||
pub struct ChunkFileFooter {
|
||||
_chunk_id: [u8; 8],
|
||||
pub segment_size: u32,
|
||||
pub file_data_offset: u32,
|
||||
pub file_data_len: u32,
|
||||
_file_hash_offset: u32,
|
||||
_file_hash_len: u32,
|
||||
_file_signature_offset: u32,
|
||||
_file_signature_len: u32,
|
||||
_reserved: [u8; 84],
|
||||
_chunk_end: [u8; 8],
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
mod include;
|
||||
use std::any::Any;
|
||||
use crate::{AppContext, InputTarget};
|
||||
|
||||
use std::path::Path;
|
||||
use std::fs::{self, File, OpenOptions};
|
||||
use std::io::{Cursor, Write};
|
||||
use binrw::BinReaderExt;
|
||||
|
||||
use crate::utils::common;
|
||||
use crate::utils::aes::decrypt_aes128_ecb;
|
||||
use crate::formats::mstar::{extract_mstar, is_mstar_file};
|
||||
use include::*;
|
||||
|
||||
pub struct MstarSecureCtx {
|
||||
dec_footer: Vec<u8>,
|
||||
}
|
||||
|
||||
pub fn is_mstar_secure_old_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 file_size = file.metadata()?.len();
|
||||
if file_size < 128 {
|
||||
return Ok(None);
|
||||
}
|
||||
let enc_footer = common::read_file(&file, file_size - 128, 128)?;
|
||||
let dec_footer = decrypt_aes128_ecb(&MSTAR_DEFAULT_UPGRADE_KEY, &enc_footer)?;
|
||||
|
||||
if &dec_footer[0..8] == CHUNK_ID && &dec_footer[120..128] == CHUNK_END {
|
||||
Ok(Some(Box::new(MstarSecureCtx {dec_footer})))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_mstar_secure_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 ctx = ctx.downcast::<MstarSecureCtx>().expect("Missing context");
|
||||
|
||||
let hdr: ChunkFileFooter = Cursor::new(ctx.dec_footer).read_le()?;
|
||||
println!("Info -\nSegment size: {}\nFile data offset: {}\nFile data len: {}", hdr.segment_size, hdr.file_data_offset, hdr.file_data_len);
|
||||
|
||||
let enc_data = common::read_file(&mut file, hdr.file_data_offset as u64, hdr.file_data_len as usize)?;
|
||||
|
||||
println!("Decrypting...");
|
||||
let dec_data = decrypt_aes128_ecb(&MSTAR_DEFAULT_UPGRADE_KEY, &enc_data)?;
|
||||
|
||||
let output_path = Path::new(&app_ctx.output_dir).join("_decrypted.bin");
|
||||
fs::create_dir_all(&app_ctx.output_dir)?;
|
||||
let mut out_file = OpenOptions::new().write(true).create(true).open(&output_path)?;
|
||||
out_file.write_all(&dec_data)?;
|
||||
|
||||
println!("- Saved decrypted file!");
|
||||
|
||||
//run standard mstar ext into same directory
|
||||
let r_out_file = File::open(&output_path)?;
|
||||
let in_ctx: AppContext = AppContext {
|
||||
input: InputTarget::File(r_out_file),
|
||||
output_dir: app_ctx.output_dir.clone(),
|
||||
options: app_ctx.options.clone()
|
||||
};
|
||||
|
||||
//do check just in case and extract
|
||||
if let Some(result) = is_mstar_file(&in_ctx)? {
|
||||
extract_mstar(&in_ctx, result)?;
|
||||
} else {
|
||||
return Err("detection failed on decrypted data".into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user