EOD 12.09.2025

Samsung old module
This commit is contained in:
theubusu
2025-09-12 22:18:53 +02:00
parent 2ccbcad559
commit ee534675d8
6 changed files with 311 additions and 11 deletions
Generated
+136
View File
@@ -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"
+4
View File
@@ -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
View File
@@ -1 +1,2 @@
pub mod mstar;
pub mod samsung_old;
+7 -6
View File
@@ -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;
+152
View File
@@ -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
View File
@@ -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!");
}
}