mirror of
https://github.com/Ap0dexMe0/unixtract.git
synced 2026-07-15 21:00:03 +02:00
EOD 12.09.2025
Samsung old module
This commit is contained in:
Generated
+136
@@ -2,6 +2,17 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.20"
|
||||
@@ -52,12 +63,39 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cbc"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.36"
|
||||
@@ -68,6 +106,22 @@ dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.47"
|
||||
@@ -114,6 +168,15 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
version = "3.3.0"
|
||||
@@ -129,18 +192,58 @@ version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||
dependencies = [
|
||||
"block-padding",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
@@ -182,6 +285,12 @@ dependencies = [
|
||||
"crc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "md5"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.1"
|
||||
@@ -206,6 +315,17 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
@@ -229,6 +349,12 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.19"
|
||||
@@ -239,9 +365,13 @@ checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
|
||||
name = "unixtract"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"cbc",
|
||||
"clap",
|
||||
"lz4",
|
||||
"lzma-rs",
|
||||
"md5",
|
||||
"sha1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -250,6 +380,12 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.3"
|
||||
|
||||
@@ -7,3 +7,7 @@ edition = "2024"
|
||||
clap = { version = "4.5", features = ["derive"] }
|
||||
lz4 = "1.23.1"
|
||||
lzma-rs = "0.3"
|
||||
aes = "0.8.4"
|
||||
cbc = "0.1.2"
|
||||
md5 = "0.7"
|
||||
sha1 = "0.10"
|
||||
@@ -1 +1,2 @@
|
||||
pub mod mstar;
|
||||
pub mod samsung_old;
|
||||
@@ -3,13 +3,14 @@ use std::path::{Path};
|
||||
use std::io::{Write, Cursor};
|
||||
use lz4::block::decompress;
|
||||
use lzma_rs::lzma_decompress;
|
||||
|
||||
use crate::common;
|
||||
|
||||
pub fn is_mstar_file(file: &File) -> bool {
|
||||
let header = common::read_file(&file, 0, 32768).expect("Failed to read from file.");
|
||||
let header_string = String::from_utf8_lossy(&header);
|
||||
|
||||
if header_string.contains("filepartload") & header_string.contains("MstarUpgrade") | header_string.contains("CtvUpgrade") | header_string.contains("LetvUpgrade"){
|
||||
if header_string.contains("filepartload"){
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -40,7 +41,6 @@ fn decompress_lz4(compressed_data: &[u8], original_size: i32) -> Result<Vec<u8>,
|
||||
}
|
||||
|
||||
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)?;
|
||||
|
||||
@@ -89,6 +89,7 @@ pub fn extract_mstar(file: &File, output_folder: &str) -> Result<(), Box<dyn std
|
||||
let mut compression = "none";
|
||||
let mut lz4_expect_size = 0;
|
||||
let mut j = i + 1;
|
||||
// get lines after this filepartload, before the next one
|
||||
while j < lines.len() && !lines[j].starts_with("filepartload") {
|
||||
//get compression method
|
||||
if lines[j].starts_with("mscompress7"){
|
||||
@@ -116,7 +117,7 @@ pub fn extract_mstar(file: &File, output_folder: &str) -> Result<(), Box<dyn std
|
||||
// check if its boot partition
|
||||
if lines[j].starts_with("mmc write.boot") {
|
||||
if partname == "unknown" {
|
||||
partname = "boot"
|
||||
partname = "_mmc_boot"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +132,7 @@ pub fn extract_mstar(file: &File, output_folder: &str) -> Result<(), Box<dyn std
|
||||
j += 1;
|
||||
}
|
||||
|
||||
println!("Part - Offset: {}, Size: {} --> {}.bin", offset, size, partname);
|
||||
println!("Part - Offset: {}, Size: {} --> {}", offset, size, partname);
|
||||
|
||||
if partname == "unknown"{
|
||||
println!("- Unknown destination, skipping!");
|
||||
@@ -151,8 +152,8 @@ pub fn extract_mstar(file: &File, output_folder: &str) -> Result<(), Box<dyn std
|
||||
println!("- Decompressing lz4, expected size: {}", lz4_expect_size);
|
||||
out_data = decompress_lz4(&data, lz4_expect_size.try_into().unwrap())?;
|
||||
} else if compression == "lzo" {
|
||||
//TODO: add lzo
|
||||
println!("- Decompressing lzo...");
|
||||
// nothing in rust to parse lzo file with header
|
||||
println!("- lzo compression is not supported yet!!...");
|
||||
out_data = data;
|
||||
}else {
|
||||
out_data = data;
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Write};
|
||||
use aes::Aes128;
|
||||
use cbc::{Decryptor, cipher::{block_padding::Pkcs7, BlockDecryptMut, KeyIvInit}};
|
||||
use sha1::{Digest, Sha1};
|
||||
|
||||
type Aes128CbcDec = Decryptor<Aes128>;
|
||||
|
||||
use crate::common;
|
||||
|
||||
use md5;
|
||||
|
||||
pub fn is_samsung_old_dir(path: &PathBuf) -> bool {
|
||||
if Path::new(&path).join("image").is_dir() & Path::new(&path).join("image/info.txt").exists(){
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn decrypt_aes(encrypted_data: &[u8], key: &[u8; 16], iv: &[u8; 16]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
|
||||
let mut data = encrypted_data.to_vec();
|
||||
let decryptor = Aes128CbcDec::new(key.into(), iv.into());
|
||||
let decrypted = decryptor.decrypt_padded_mut::<Pkcs7>(&mut data)
|
||||
.map_err(|e| format!("!!Decryption error!!: {:?}", e))?;
|
||||
|
||||
Ok(decrypted.to_vec())
|
||||
}
|
||||
|
||||
fn decrypt_xor(data: &[u8], key: &str) -> Vec<u8> {
|
||||
let key_bytes = key.as_bytes();
|
||||
data.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &byte)| byte ^ key_bytes[i % key_bytes.len()])
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn extract_samsung_old(path: &PathBuf, output_folder: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
let fw_info = fs::read_to_string(Path::new(&path).join("image/info.txt"))?;
|
||||
println!("Firmware info: {}", fw_info);
|
||||
|
||||
let image_path = Path::new(&path).join("image");
|
||||
let mut secret = "";
|
||||
let secret_t_ecp = [0x3E, 0xF6, 0x06, 0x72, 0x62, 0xCF, 0x0C, 0x67, 0x85, 0x98, 0xBF, 0xF2, 0x21, 0x69, 0xD1, 0xF1, 0xEA, 0x57, 0xC2, 0x84];
|
||||
|
||||
// from samygo tool
|
||||
if fw_info.starts_with("T-GA"){
|
||||
secret = "SHWJUH:85a045ae-2296-484c-b457-ede832fcfbe1-646390a3-105e-40aa-85f6-da3086c70111";
|
||||
} else if fw_info.starts_with("T-MST5"){
|
||||
secret = "SHWJUH:eceb2c14-db11-425e-9ebf-5f9607f0eb4b-3c38193e-751e-4719-8884-9e76322c0cec";
|
||||
} else if fw_info.starts_with("B-FIRHT7"){
|
||||
secret = "d6442d-7b46b2f4-0f11-4623-af63-8bb0a0d54c80-a22fbe2c-1bb5-49cc-b194-25c0f2b870f4";
|
||||
} else if fw_info.starts_with("B-FIRU") | fw_info.starts_with("B-FIRH") | fw_info.starts_with("B-FIRBSP") | fw_info.starts_with("B-FIR2"){
|
||||
secret = "SHWJUH:db48ad51-c784-4f06-af57-1070a910c536-6a028bb5-e83e-45da-b326-a3a39ccba26c";
|
||||
} else if fw_info.starts_with("B-FIRB"){
|
||||
secret = "d6442d-7b46b2f4-0f11-4623-af63-8bb0a0d54c80-a22fbe2c-1bb5-49cc-b194-25c0f2b870f4";
|
||||
} else if fw_info.starts_with("T-MST10P"){
|
||||
secret = "b4c136-fbc93576-b3e8-4035-bf4e-ba4cb4ada1ac-f0d81cc4-8301-4832-bd60-f331295743ba";
|
||||
} else if fw_info.starts_with("B-ECB"){
|
||||
secret = "SHWJUH:8fb684a9-84c1-46cf-aa81-977bce241542-6db4c136-8540-4ee4-8704-d9cd18590d11";
|
||||
} else if fw_info.starts_with("T-VAL"){
|
||||
secret = "A435HX:d3e90afc-0f09-4054-9bac-350cc8dfc901-7cee72ea-15ae-45ce-b0f5-00001abc2010";
|
||||
} else if fw_info.starts_with("T-TDT"){
|
||||
secret = "A435HX:d3e90afc-0f09-4054-9bac-350cc8dfc901-7cee72ea-15ae-45ce-b0f5-00002abc2010";
|
||||
} else if fw_info.starts_with("T-MSX"){
|
||||
secret = "A435HX:d3e90afc-0f09-4054-9bac-350cc8dfc901-7cee72ea-15ae-45ce-b0f5-00004abc2010";
|
||||
} else if fw_info.starts_with("T-CH"){
|
||||
secret = "A435HX:d3e90afc-0f09-4054-9bac-350cc8dfc901-7cee72ea-15ae-45ce-b0f5-611c4f8d4a71";
|
||||
} else if fw_info.starts_with("T-ECP") {
|
||||
} else {
|
||||
println!("Sorry, this firmware is not supported!");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for entry in fs::read_dir(image_path)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
|
||||
if path.is_file() {
|
||||
if let Some(ext) = path.extension() {
|
||||
if ext == "sec" {
|
||||
let file = File::open(&path)?;
|
||||
let filename = path.file_name().unwrap().to_str().unwrap();
|
||||
let file_size = file.metadata()?.len();
|
||||
println!("File: {}", filename);
|
||||
let data = common::read_file(&file, 0, file_size.try_into().unwrap())?;
|
||||
let salt = &data[8..16];
|
||||
|
||||
let key_md5;
|
||||
let iv_md5;
|
||||
|
||||
//Old -> key: md5 of (sha1 of secret as TEXT + salt)
|
||||
// iv: md5 of (md5 of key + key)
|
||||
|
||||
//2012 -> key: md5 of (secret + salt)
|
||||
// iv: md5 of (md5 of key + key)
|
||||
if fw_info.starts_with("T-ECP") {
|
||||
let key: Vec<u8> = [&secret_t_ecp, salt].concat();
|
||||
key_md5 = md5::compute(&key);
|
||||
|
||||
let mut iv = Vec::new();
|
||||
iv.extend_from_slice(&key_md5.0);
|
||||
iv.extend_from_slice(&key);
|
||||
iv_md5 = md5::compute(&iv);
|
||||
} else {
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.update(secret);
|
||||
let secret_digest = hasher.finalize();
|
||||
// yes it needs to be a string first then into bytes
|
||||
let secret_digest_string = format!("{:x}", secret_digest);
|
||||
let secret_digest_bytes = secret_digest_string.as_bytes();
|
||||
|
||||
let key: Vec<u8> = [&secret_digest_bytes, salt].concat();
|
||||
key_md5 = md5::compute(&key);
|
||||
|
||||
let mut iv = Vec::new();
|
||||
iv.extend_from_slice(&key_md5.0);
|
||||
iv.extend_from_slice(&key);
|
||||
iv_md5 = md5::compute(&iv);
|
||||
}
|
||||
|
||||
//println!("Key: {:02x?}", key_md5);
|
||||
//println!("IV: {:02x?}", iv_md5);
|
||||
|
||||
let end = file_size - 260;
|
||||
println!("- Decrypting file...");
|
||||
let decrypted_data = decrypt_aes(&data[16..end.try_into().unwrap()], &key_md5, &iv_md5)?;
|
||||
|
||||
println!("- DeXORing file...");
|
||||
let xor_key = fw_info.split_whitespace().next().unwrap();
|
||||
let out_data = decrypt_xor(&decrypted_data, xor_key);
|
||||
|
||||
let output_path = Path::new(&output_folder).join(filename.rsplit_once('.').map(|(left, _)| left).unwrap());
|
||||
|
||||
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)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
+9
-3
@@ -22,18 +22,24 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
let path = PathBuf::from(target_path);
|
||||
if path.is_dir() {
|
||||
println!("Directory");
|
||||
if formats::samsung_old::is_samsung_old_dir(&path) {
|
||||
println!("Samsung old firmware dir detected!");
|
||||
println!();
|
||||
formats::samsung_old::extract_samsung_old(&path, &output_path)?
|
||||
} else {
|
||||
println!("Input format not recognized!");
|
||||
}
|
||||
} else {
|
||||
//println!("file");
|
||||
let file = File::open(path)?;
|
||||
|
||||
println!();
|
||||
|
||||
if formats::mstar::is_mstar_file(&file) {
|
||||
println!("Mstar upgrade file detected!");
|
||||
println!();
|
||||
formats::mstar::extract_mstar(&file, &output_path)?;
|
||||
} else {
|
||||
println!("File format not recognized!");
|
||||
println!("Input format not recognized!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user