From 838e0271ce138f7ee57d09006816fe5b22fb9dbe Mon Sep 17 00:00:00 2001 From: theubusu <80545678+theubusu@users.noreply.github.com> Date: Thu, 11 Sep 2025 20:26:51 +0200 Subject: [PATCH] initial --- .gitignore | 1 + Cargo.lock | 251 +++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 7 ++ src/common.rs | 10 ++ src/formats/mod.rs | 1 + src/formats/mstar.rs | 81 ++++++++++++++ src/main.rs | 41 +++++++ 7 files changed, 392 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/common.rs create mode 100644 src/formats/mod.rs create mode 100644 src/formats/mstar.rs create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..b943780 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,251 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anstream" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "clap" +version = "4.5.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "unixtract" +version = "0.1.0" +dependencies = [ + "clap", +] + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..65950ac --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "unixtract" +version = "0.1.0" +edition = "2024" + +[dependencies] +clap = { version = "4.5", features = ["derive"] } \ No newline at end of file diff --git a/src/common.rs b/src/common.rs new file mode 100644 index 0000000..81edbf5 --- /dev/null +++ b/src/common.rs @@ -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, Box> { + file.seek(SeekFrom::Start(offset))?; + let mut buffer = vec![0u8; size]; + let _bytes_read = file.read(&mut buffer)?; + + Ok(buffer) +} \ No newline at end of file diff --git a/src/formats/mod.rs b/src/formats/mod.rs new file mode 100644 index 0000000..b0e487c --- /dev/null +++ b/src/formats/mod.rs @@ -0,0 +1 @@ +pub mod mstar; \ No newline at end of file diff --git a/src/formats/mstar.rs b/src/formats/mstar.rs new file mode 100644 index 0000000..1b894dd --- /dev/null +++ b/src/formats/mstar.rs @@ -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; + } + +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..714c26a --- /dev/null +++ b/src/main.rs @@ -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> { + 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(()) +}