This commit is contained in:
theubusu
2025-09-11 20:26:51 +02:00
commit 838e0271ce
7 changed files with 392 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
use std::fs::{File};
use std::io::{Read, Seek, SeekFrom};
pub fn read_file(mut file: &File, offset: u64, size: usize) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
file.seek(SeekFrom::Start(offset))?;
let mut buffer = vec![0u8; size];
let _bytes_read = file.read(&mut buffer)?;
Ok(buffer)
}
+1
View File
@@ -0,0 +1 @@
pub mod mstar;
+81
View File
@@ -0,0 +1,81 @@
use std::fs::{File};
use crate::common;
pub fn is_mstar_file(file: &File) -> bool {
let header = common::read_file(&file, 0, 32768).expect("REASON");
let header_string = String::from_utf8_lossy(&header);
if header_string.contains("filepartload") & header_string.contains("MstarUpgrade") | header_string.contains("CtvUpgrade") {
true
} else {
false
}
}
pub fn extract_mstar(file: &File) {
println!("extract mstar file");
let mut script = common::read_file(&file, 0, 32768).expect("REASON");
if let Some(pos) = script.iter().position(|x| [0x00, 0xFF].contains(x)) {
script.truncate(pos);
}
let script_string = String::from_utf8_lossy(&script);
//println!("{}", script_string);
let lines: Vec<&str> = script_string.lines().map(|l| l.trim()).collect();
let mut i = 0;
while i < lines.len() {
let line = lines[i];
if line.starts_with("filepartload") {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() >= 5 {
let offset = parts[3];
let size = parts[4];
//try to get partname from comment
let mut partname = if let Some(idx) = line.find('#') {
line[idx + 1..].trim()
} else {
"unknown"
};
let mut compression = "none";
let mut j = i + 1;
while j < lines.len() && !lines[j].starts_with("filepartload") {
//get compression method
if lines[j].contains("mscompress7") {
compression = "lzma";
} else if lines[j].contains("lz4") {
compression = "lz4";
}
// try to get partname from nand/mmc/ubi writes
if lines[j].starts_with("mmc write") | lines[j].starts_with("nand write") | lines[j].starts_with("ubi write"){
let parts: Vec<&str> = lines[j].split_whitespace().collect();
if partname == "unknown" {
partname = parts[3]
}
}
// check if its boot partition
if lines[j].starts_with("mmc write.boot") {
if partname == "unknown" {
partname = "boot"
}
}
j += 1;
}
println!("offset: {} size: {} --> {} (compression: {})", offset, size, partname, compression);
}
}
i += 1;
}
}
+41
View File
@@ -0,0 +1,41 @@
use clap::Parser;
use std::path::{PathBuf};
use std::fs::{File};
mod formats;
mod common;
#[derive(Parser, Debug)]
struct Args {
input_target: String,
output_folder: String,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("unixtract Firmware extractor v0.0");
let args = Args::parse();
let target_path = args.input_target;
println!("Input target: {}", target_path);
let output_path = args.output_folder;
println!("Output folder: {}", output_path);
let path = PathBuf::from(target_path);
if path.is_dir() {
println!("Directory");
} else {
//println!("file");
let file = File::open(path)?;
if formats::mstar::is_mstar_file(&file) {
println!("Mstar upgrade file detected!");
formats::mstar::extract_mstar(&file);
} else {
println!("File format not recognized!");
}
}
Ok(())
}