mirror of
https://github.com/Ap0dexMe0/unixtract.git
synced 2026-07-15 21:00:03 +02:00
EOD 11.09.2025
This commit is contained in:
Generated
+48
@@ -52,6 +52,16 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.2.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54"
|
||||||
|
dependencies = [
|
||||||
|
"find-msvc-tools",
|
||||||
|
"shlex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.47"
|
version = "4.5.47"
|
||||||
@@ -98,6 +108,12 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "find-msvc-tools"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -110,6 +126,31 @@ version = "1.70.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.175"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lz4"
|
||||||
|
version = "1.28.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a20b523e860d03443e98350ceaac5e71c6ba89aea7d960769ec3ce37f4de5af4"
|
||||||
|
dependencies = [
|
||||||
|
"lz4-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lz4-sys"
|
||||||
|
version = "1.11.1+lz4-1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell_polyfill"
|
name = "once_cell_polyfill"
|
||||||
version = "1.70.1"
|
version = "1.70.1"
|
||||||
@@ -134,6 +175,12 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@@ -162,6 +209,7 @@ name = "unixtract"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
|
"lz4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ edition = "2024"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.5", features = ["derive"] }
|
clap = { version = "4.5", features = ["derive"] }
|
||||||
|
lz4 = "1.23.1"
|
||||||
+78
-14
@@ -1,8 +1,11 @@
|
|||||||
use std::fs::{File};
|
use std::fs::{self, File, OpenOptions};
|
||||||
|
use std::path::{Path};
|
||||||
|
use std::io::{Write};
|
||||||
|
use lz4::block::decompress;
|
||||||
use crate::common;
|
use crate::common;
|
||||||
|
|
||||||
pub fn is_mstar_file(file: &File) -> bool {
|
pub fn is_mstar_file(file: &File) -> bool {
|
||||||
let header = common::read_file(&file, 0, 32768).expect("REASON");
|
let header = common::read_file(&file, 0, 32768).expect("Failed to read from file.");
|
||||||
let header_string = String::from_utf8_lossy(&header);
|
let header_string = String::from_utf8_lossy(&header);
|
||||||
|
|
||||||
if header_string.contains("filepartload") & header_string.contains("MstarUpgrade") | header_string.contains("CtvUpgrade") {
|
if header_string.contains("filepartload") & header_string.contains("MstarUpgrade") | header_string.contains("CtvUpgrade") {
|
||||||
@@ -12,18 +15,43 @@ pub fn is_mstar_file(file: &File) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_mstar(file: &File) {
|
fn parse_number(s: &str) -> Option<u64> {
|
||||||
println!("extract mstar file");
|
if let Some(hex_str) = s.strip_prefix("0x") {
|
||||||
|
u64::from_str_radix(hex_str, 16).ok()
|
||||||
|
} else {
|
||||||
|
u64::from_str_radix(s, 16).ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut script = common::read_file(&file, 0, 32768).expect("REASON");
|
fn decompress_lz4(compressed_data: &[u8], original_size: i32) -> Result<Vec<u8>, std::io::Error> {
|
||||||
|
match decompress(compressed_data, Some(original_size)) {
|
||||||
|
Ok(decompressed) => Ok(decompressed),
|
||||||
|
Err(e) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extract_mstar(file: &File, output_folder: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
println!();
|
||||||
|
let mut script = common::read_file(&file, 0, 32768)?;
|
||||||
|
|
||||||
if let Some(pos) = script.iter().position(|x| [0x00, 0xFF].contains(x)) {
|
if let Some(pos) = script.iter().position(|x| [0x00, 0xFF].contains(x)) {
|
||||||
script.truncate(pos);
|
script.truncate(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
let script_string = String::from_utf8_lossy(&script);
|
let mut script_string = String::from_utf8_lossy(&script);
|
||||||
//println!("{}", script_string);
|
//println!("{}", script_string);
|
||||||
|
|
||||||
|
if script_string == "" {
|
||||||
|
//try ts hisense
|
||||||
|
println!("Failed to get script at 0x0, trying 0x1000...");
|
||||||
|
script = common::read_file(&file, 4096, 32768)?;
|
||||||
|
script_string = String::from_utf8_lossy(&script);
|
||||||
|
|
||||||
|
if script_string == "" {
|
||||||
|
println!("Failed to get script.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let lines: Vec<&str> = script_string.lines().map(|l| l.trim()).collect();
|
let lines: Vec<&str> = script_string.lines().map(|l| l.trim()).collect();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
||||||
@@ -34,8 +62,8 @@ pub fn extract_mstar(file: &File) {
|
|||||||
let parts: Vec<&str> = line.split_whitespace().collect();
|
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
|
||||||
if parts.len() >= 5 {
|
if parts.len() >= 5 {
|
||||||
let offset = parts[3];
|
let offset = parse_number(parts[3]).unwrap_or(0);
|
||||||
let size = parts[4];
|
let size = parse_number(parts[4]).unwrap_or(0);
|
||||||
|
|
||||||
//try to get partname from comment
|
//try to get partname from comment
|
||||||
let mut partname = if let Some(idx) = line.find('#') {
|
let mut partname = if let Some(idx) = line.find('#') {
|
||||||
@@ -45,6 +73,7 @@ pub fn extract_mstar(file: &File) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut compression = "none";
|
let mut compression = "none";
|
||||||
|
let mut lz4_expect_size = 0;
|
||||||
let mut j = i + 1;
|
let mut j = i + 1;
|
||||||
while j < lines.len() && !lines[j].starts_with("filepartload") {
|
while j < lines.len() && !lines[j].starts_with("filepartload") {
|
||||||
//get compression method
|
//get compression method
|
||||||
@@ -54,6 +83,18 @@ pub fn extract_mstar(file: &File) {
|
|||||||
compression = "lz4";
|
compression = "lz4";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if lines[j].starts_with("lz4"){
|
||||||
|
let parts: Vec<&str> = lines[j].split_whitespace().collect();
|
||||||
|
lz4_expect_size = parse_number(parts[5]).unwrap_or(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if its boot partition
|
||||||
|
if lines[j].starts_with("mmc write.boot") {
|
||||||
|
if partname == "unknown" {
|
||||||
|
partname = "boot"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// try to get partname from nand/mmc/ubi writes
|
// 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"){
|
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();
|
let parts: Vec<&str> = lines[j].split_whitespace().collect();
|
||||||
@@ -62,20 +103,43 @@ pub fn extract_mstar(file: &File) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if its boot partition
|
|
||||||
if lines[j].starts_with("mmc write.boot") {
|
|
||||||
if partname == "unknown" {
|
|
||||||
partname = "boot"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
j += 1;
|
j += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("offset: {} size: {} --> {} (compression: {})", offset, size, partname, compression);
|
println!("offset: {} size: {} --> {} (compression: {})", offset, size, partname, compression);
|
||||||
|
|
||||||
|
let data = common::read_file(&file, offset, size.try_into().unwrap())?;
|
||||||
|
|
||||||
|
//println!("{:02x?}", &data[0]);
|
||||||
|
//println!("{}", data.len());
|
||||||
|
|
||||||
|
let out_data;
|
||||||
|
|
||||||
|
if compression == "lzma" {
|
||||||
|
// TODO: do lzma decompression
|
||||||
|
out_data = data;
|
||||||
|
} else if compression == "lz4" {
|
||||||
|
println!("- Decompressing lz4, expected size: {}", lz4_expect_size);
|
||||||
|
out_data = decompress_lz4(&data, lz4_expect_size.try_into().unwrap())?;
|
||||||
|
//out_data = data;
|
||||||
|
} else {
|
||||||
|
out_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
let output_path = Path::new(&output_folder).join(partname.to_owned() + ".bin");
|
||||||
|
|
||||||
|
fs::create_dir_all(&output_folder)?;
|
||||||
|
let mut out_file = OpenOptions::new()
|
||||||
|
.append(true)
|
||||||
|
.create(true)
|
||||||
|
.open(output_path)?;
|
||||||
|
|
||||||
|
out_file.write_all(&out_data)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
+3
-3
@@ -27,15 +27,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
//println!("file");
|
//println!("file");
|
||||||
let file = File::open(path)?;
|
let file = File::open(path)?;
|
||||||
|
|
||||||
|
println!();
|
||||||
|
|
||||||
if formats::mstar::is_mstar_file(&file) {
|
if formats::mstar::is_mstar_file(&file) {
|
||||||
println!("Mstar upgrade file detected!");
|
println!("Mstar upgrade file detected!");
|
||||||
formats::mstar::extract_mstar(&file);
|
formats::mstar::extract_mstar(&file, &output_path)?;
|
||||||
} else {
|
} else {
|
||||||
println!("File format not recognized!");
|
println!("File format not recognized!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user