mirror of
https://github.com/Ap0dexMe0/unixtract.git
synced 2026-07-15 21:00:03 +02:00
change epk1 to structs and more
This commit is contained in:
@@ -11,4 +11,4 @@
|
||||
- LG Epk2 (Crypted and plain header)- 100% complete (unless unencrypted versions exist >)
|
||||
- LG epk3 - Probably fine??? but needs more testing (and more stolen keys)
|
||||
|
||||
Todo: use STRUCTS on everything
|
||||
Todo: use STRUCTS on everything and move them to seperate files probably
|
||||
+48
-54
@@ -3,8 +3,38 @@ use std::path::{Path};
|
||||
use std::fs::{self, OpenOptions};
|
||||
use std::io::{Write, Seek, SeekFrom};
|
||||
|
||||
use binrw::{BinRead, BinReaderExt};
|
||||
|
||||
use crate::common;
|
||||
|
||||
#[derive(BinRead)]
|
||||
struct CommonHeader {
|
||||
#[br(count = 4)] _magic_bytes: Vec<u8>,
|
||||
file_size: u32,
|
||||
pak_count: u32,
|
||||
}
|
||||
|
||||
#[derive(BinRead)]
|
||||
struct Pak {
|
||||
offset : u32,
|
||||
size : u32,
|
||||
}
|
||||
|
||||
#[derive(BinRead)]
|
||||
struct PakHeader {
|
||||
#[br(count = 4)] pak_name_bytes: Vec<u8>,
|
||||
stored_size: u32,
|
||||
#[br(count = 15)] platform_id_bytes: Vec<u8>,
|
||||
}
|
||||
impl PakHeader {
|
||||
fn pak_name(&self) -> String {
|
||||
common::string_from_bytes(&self.pak_name_bytes)
|
||||
}
|
||||
fn platform_id(&self) -> String {
|
||||
common::string_from_bytes(&self.platform_id_bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_epk1_file(file: &File) -> bool {
|
||||
let header = common::read_file(&file, 0, 4).expect("Failed to read from file.");
|
||||
if header == b"epak" {
|
||||
@@ -14,11 +44,6 @@ pub fn is_epk1_file(file: &File) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
struct Pak {
|
||||
offset : u32,
|
||||
size : u32,
|
||||
}
|
||||
|
||||
pub fn extract_epk1(mut file: &File, output_folder: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||
//check type of epk1
|
||||
let epk1_type;
|
||||
@@ -43,59 +68,39 @@ pub fn extract_epk1(mut file: &File, output_folder: &str) -> Result<(), Box<dyn
|
||||
let mut paks: Vec<Pak> = Vec::new();
|
||||
|
||||
if epk1_type == "be" {
|
||||
let _epak = common::read_exact(&mut file, 4)?; //epak magic
|
||||
|
||||
let file_size_bytes = common::read_exact(&mut file, 4)?;
|
||||
let file_size = u32::from_be_bytes(file_size_bytes.try_into().unwrap());
|
||||
|
||||
let pak_count_bytes = common::read_exact(&mut file, 4)?;
|
||||
let pak_count = u32::from_be_bytes(pak_count_bytes.try_into().unwrap());
|
||||
let header: CommonHeader = file.read_be()?;
|
||||
|
||||
for _i in 0..10 { //header can fit max 10 pak entries
|
||||
let pak_offset_bytes = common::read_exact(&mut file, 4)?;
|
||||
let pak_offset = u32::from_be_bytes(pak_offset_bytes.try_into().unwrap());
|
||||
let pak: Pak = file.read_be()?;
|
||||
|
||||
let pak_size_bytes = common::read_exact(&mut file, 4)?;
|
||||
let pak_size = u32::from_be_bytes(pak_size_bytes.try_into().unwrap());
|
||||
|
||||
if pak_offset == 0 && pak_size == 0 {
|
||||
if pak.offset == 0 && pak.size == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
paks.push(Pak { offset: pak_offset, size: pak_size });
|
||||
paks.push(Pak { offset: pak.offset, size: pak.size });
|
||||
}
|
||||
|
||||
assert!(pak_count as usize == paks.len(), "Paks count in header does not match the amount of non empty pak entries!");
|
||||
assert!(header.pak_count as usize == paks.len(), "Paks count in header does not match the amount of non empty pak entries!");
|
||||
|
||||
let version = common::read_exact(&mut file, 4)?;
|
||||
|
||||
println!("EPK info:\nFile size: {}\nPak count: {}\nVersion: {:02x?}.{:02x?}.{:02x?}",
|
||||
file_size, pak_count, version[1], version[2], version[3]);
|
||||
header.file_size, header.pak_count, version[1], version[2], version[3]);
|
||||
|
||||
} else if epk1_type == "le" {
|
||||
let _epak = common::read_exact(&mut file, 4)?; //epak magic
|
||||
|
||||
let file_size_bytes = common::read_exact(&mut file, 4)?;
|
||||
let file_size = u32::from_le_bytes(file_size_bytes.try_into().unwrap());
|
||||
|
||||
let pak_count_bytes = common::read_exact(&mut file, 4)?;
|
||||
let pak_count = u32::from_le_bytes(pak_count_bytes.try_into().unwrap());
|
||||
let header: CommonHeader = file.read_le()?;
|
||||
|
||||
for _i in 0..20 { //header can fit max 20 pak entries
|
||||
let pak_offset_bytes = common::read_exact(&mut file, 4)?;
|
||||
let pak_offset = u32::from_le_bytes(pak_offset_bytes.try_into().unwrap());
|
||||
let pak: Pak = file.read_le()?;
|
||||
|
||||
let pak_size_bytes = common::read_exact(&mut file, 4)?;
|
||||
let pak_size = u32::from_le_bytes(pak_size_bytes.try_into().unwrap());
|
||||
|
||||
if pak_offset == 0 && pak_size == 0 {
|
||||
if pak.offset == 0 && pak.size == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
paks.push(Pak { offset: pak_offset, size: pak_size });
|
||||
paks.push(Pak { offset: pak.offset, size: pak.size });
|
||||
}
|
||||
|
||||
assert!(pak_count as usize == paks.len(), "Paks count in header does not match the amount of non empty pak entries!");
|
||||
assert!(header.pak_count as usize == paks.len(), "Paks count in header does not match the amount of non empty pak entries!");
|
||||
|
||||
let version = common::read_exact(&mut file, 4)?;
|
||||
|
||||
@@ -103,29 +108,18 @@ pub fn extract_epk1(mut file: &File, output_folder: &str) -> Result<(), Box<dyn
|
||||
let ota_id = common::string_from_bytes(&ota_id_bytes);
|
||||
|
||||
println!("EPK info:\nFile size: {}\nPak count: {}\nOTA ID: {}\nVersion: {:02x?}.{:02x?}.{:02x?}",
|
||||
file_size, pak_count, ota_id, version[2], version[1], version[0]);
|
||||
header.file_size, header.pak_count, ota_id, version[2], version[1], version[0]);
|
||||
}
|
||||
|
||||
for (i, pak) in paks.iter().enumerate() {
|
||||
let pak_name_bytes = common::read_file(&file, pak.offset as u64, 4)?;
|
||||
let pak_name = common::string_from_bytes(&pak_name_bytes);
|
||||
file.seek(SeekFrom::Start(pak.offset as u64))?;
|
||||
let pak_header: PakHeader = if epk1_type == "be" {file.read_be()?} else {file.read_le()?};
|
||||
|
||||
let pak_actual_size_bytes = common::read_file(&file, pak.offset as u64 + 4, 4)?;
|
||||
let pak_actual_size;
|
||||
if epk1_type == "be" {
|
||||
pak_actual_size = u32::from_be_bytes(pak_actual_size_bytes.try_into().unwrap());
|
||||
} else {
|
||||
pak_actual_size = u32::from_le_bytes(pak_actual_size_bytes.try_into().unwrap());
|
||||
}
|
||||
let data = common::read_file(&file, pak.offset as u64 + 128, pak.size as usize - 128)?;
|
||||
|
||||
let pak_platform_bytes = common::read_file(&file, pak.offset as u64 + 8, 15)?;
|
||||
let pak_platform = common::string_from_bytes(&pak_platform_bytes);
|
||||
println!("\nPak {}: {}, Offset: {}, Size: {}, Platform: {}", i + 1, pak_header.pak_name(), pak.offset, pak.size, pak_header.platform_id());
|
||||
|
||||
let data = common::read_file(&file, pak.offset as u64, pak.size as usize)?;
|
||||
|
||||
println!("\nPak {}: {}, Offset: {}, Size: {}, Platform: {}", i + 1, pak_name, pak.offset, pak.size, pak_platform);
|
||||
|
||||
let output_path = Path::new(&output_folder).join(pak_name + ".bin");
|
||||
let output_path = Path::new(&output_folder).join(pak_header.pak_name() + ".bin");
|
||||
|
||||
fs::create_dir_all(&output_folder)?;
|
||||
let mut out_file = OpenOptions::new()
|
||||
@@ -133,7 +127,7 @@ pub fn extract_epk1(mut file: &File, output_folder: &str) -> Result<(), Box<dyn
|
||||
.create(true)
|
||||
.open(output_path)?;
|
||||
|
||||
out_file.write_all(&data[128..pak_actual_size as usize + 128])?;
|
||||
out_file.write_all(&data[..pak_header.stored_size as usize])?;
|
||||
|
||||
println!("- Saved file!");
|
||||
}
|
||||
|
||||
+38
-33
@@ -2,10 +2,41 @@ use std::fs::{self, File, OpenOptions};
|
||||
use std::path::{Path};
|
||||
use std::io::{Write, Seek, SeekFrom, Cursor};
|
||||
|
||||
use binrw::{BinRead, BinReaderExt};
|
||||
|
||||
use crate::common;
|
||||
use crate::keys;
|
||||
use crate::formats::epk::{decrypt_aes_ecb_auto, find_key};
|
||||
|
||||
#[derive(BinRead)]
|
||||
struct Header {
|
||||
#[br(count = 4)] _magic_bytes: Vec<u8>,
|
||||
file_size: u32,
|
||||
pak_count: u32,
|
||||
#[br(count = 4)] _epk2_magic: Vec<u8>,
|
||||
#[br(count = 4)] version: Vec<u8>,
|
||||
#[br(count = 32)] ota_id_bytes: Vec<u8>,
|
||||
}
|
||||
impl Header {
|
||||
fn ota_id(&self) -> String {
|
||||
common::string_from_bytes(&self.ota_id_bytes)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(BinRead)]
|
||||
struct PakEntry {
|
||||
offset: u32,
|
||||
size: u32,
|
||||
#[br(count = 4)] name_bytes: Vec<u8>,
|
||||
#[br(count = 4)] _version: Vec<u8>,
|
||||
segment_size: u32,
|
||||
}
|
||||
impl PakEntry {
|
||||
fn name(&self) -> String {
|
||||
common::string_from_bytes(&self.name_bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_epk2_file(file: &File) -> bool {
|
||||
let header = common::read_file(&file, 128, 4).expect("Failed to read from file.");
|
||||
if header == b"epak" {
|
||||
@@ -48,46 +79,20 @@ pub fn extract_epk2(mut file: &File, output_folder: &str) -> Result<(), Box<dyn
|
||||
}
|
||||
}
|
||||
//parse header
|
||||
let mut hdr_reader = Cursor::new(header);
|
||||
|
||||
let _epk = common::read_exact(&mut hdr_reader, 4)?;
|
||||
|
||||
let file_size_bytes = common::read_exact(&mut hdr_reader, 4)?;
|
||||
let file_size = u32::from_le_bytes(file_size_bytes.try_into().unwrap());
|
||||
|
||||
let pak_count_bytes = common::read_exact(&mut hdr_reader, 4)?;
|
||||
let pak_count = u32::from_le_bytes(pak_count_bytes.try_into().unwrap());
|
||||
|
||||
let _epk2 = common::read_exact(&mut hdr_reader, 4)?; // EPK2 magic
|
||||
|
||||
let version = common::read_exact(&mut hdr_reader, 4)?;
|
||||
|
||||
let ota_id_bytes = common::read_exact(&mut hdr_reader, 32)?;
|
||||
let ota_id = common::string_from_bytes(&ota_id_bytes);
|
||||
let mut hdr_reader = Cursor::new(header);
|
||||
let hdr: Header = hdr_reader.read_le()?;
|
||||
|
||||
println!("\nEPK info:\nFile size: {}\nPak count: {}\nOTA ID: {}\nVersion: {:02x?}.{:02x?}.{:02x?}\n",
|
||||
file_size, pak_count, ota_id, version[3], version[2], version[1]);
|
||||
hdr.file_size, hdr.pak_count, hdr.ota_id(), hdr.version[3], hdr.version[2], hdr.version[1]);
|
||||
|
||||
let mut paks: Vec<Pak> = Vec::new();
|
||||
//parse paks in header
|
||||
for i in 0..pak_count {
|
||||
let offset_bytes = common::read_exact(&mut hdr_reader, 4)?;
|
||||
let offset = u32::from_le_bytes(offset_bytes.try_into().unwrap()) + 128; //add 128 bytes of initial signature
|
||||
for i in 0..hdr.pak_count {
|
||||
let pak: PakEntry = hdr_reader.read_le()?;
|
||||
|
||||
let size_bytes = common::read_exact(&mut hdr_reader, 4)?;
|
||||
let size = u32::from_le_bytes(size_bytes.try_into().unwrap());
|
||||
println!("Pak {}: {}, offset: {}, size: {}, segment size: {}", i + 1, pak.name(), pak.offset + 128, pak.size, pak.segment_size);
|
||||
|
||||
let name_bytes = common::read_exact(&mut hdr_reader, 4)?;
|
||||
let name = common::string_from_bytes(&name_bytes);
|
||||
|
||||
let _version = common::read_exact(&mut hdr_reader, 4)?;
|
||||
|
||||
let segment_size_bytes = common::read_exact(&mut hdr_reader, 4)?;
|
||||
let segment_size = u32::from_le_bytes(segment_size_bytes.try_into().unwrap());
|
||||
|
||||
println!("Pak {}: {}, offset: {}, size: {}, segment size: {}", i + 1, name, offset, size, segment_size);
|
||||
|
||||
paks.push(Pak { offset, size, name });
|
||||
paks.push(Pak { offset: pak.offset + 128, size: pak.size, name: pak.name() });
|
||||
}
|
||||
|
||||
let mut signature_count = 0;
|
||||
|
||||
@@ -7,8 +7,7 @@ use binrw::{BinRead, BinReaderExt};
|
||||
|
||||
use crate::common;
|
||||
|
||||
#[derive(Debug, BinRead)]
|
||||
#[br(little)]
|
||||
#[derive(BinRead)]
|
||||
struct Header {
|
||||
#[br(count = 4)] _magic_bytes: Vec<u8>,
|
||||
#[br(count = 4)] _flags: Vec<u8>,
|
||||
@@ -19,8 +18,7 @@ struct Header {
|
||||
#[br(count = 116)] _unknown2: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, BinRead)]
|
||||
#[br(little)]
|
||||
#[derive(BinRead)]
|
||||
struct PartEntry {
|
||||
#[br(count = 16)] _unknown: Vec<u8>,
|
||||
index: u32,
|
||||
|
||||
@@ -12,8 +12,7 @@ use binrw::{BinRead, BinReaderExt};
|
||||
use crate::common;
|
||||
use crate::keys;
|
||||
|
||||
#[derive(Debug, BinRead)]
|
||||
#[br(little)]
|
||||
#[derive(BinRead)]
|
||||
struct Header {
|
||||
#[br(count = 8)] _magic_bytes: Vec<u8>,
|
||||
header_size: u32,
|
||||
@@ -24,15 +23,13 @@ struct Header {
|
||||
_padding2: u32,
|
||||
#[br(count = 512)] description_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Header {
|
||||
fn description(&self) -> String {
|
||||
common::string_from_bytes(&self.description_bytes)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, BinRead)]
|
||||
#[br(little)]
|
||||
#[derive(BinRead)]
|
||||
struct FileHeader {
|
||||
#[br(count = 60)] file_name_bytes: Vec<u8>,
|
||||
real_size: u32,
|
||||
@@ -40,7 +37,6 @@ struct FileHeader {
|
||||
_header_size: u32,
|
||||
_attributes: u32,
|
||||
}
|
||||
|
||||
impl FileHeader {
|
||||
fn file_name(&self) -> String {
|
||||
common::string_from_bytes(&self.file_name_bytes)
|
||||
|
||||
@@ -9,7 +9,6 @@ use flate2::read::GzDecoder;
|
||||
use crate::common;
|
||||
|
||||
#[derive(Debug, BinRead)]
|
||||
#[br(little)]
|
||||
struct PIMG {
|
||||
#[br(count = 4)] _magic_bytes: Vec<u8>,
|
||||
_unknown1: u32,
|
||||
@@ -21,7 +20,6 @@ struct PIMG {
|
||||
#[br(count = 16)] comp_type_bytes: Vec<u8>,
|
||||
#[br(count = 1032)] _comment: Vec<u8>,
|
||||
}
|
||||
|
||||
impl PIMG {
|
||||
fn name(&self) -> String {
|
||||
common::string_from_bytes(&self.name_bytes)
|
||||
@@ -50,7 +48,6 @@ fn decompress_gzip(compressed_data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error
|
||||
Ok(decompressed)
|
||||
}
|
||||
|
||||
|
||||
pub fn extract_tpv_timg(mut file: &File, output_folder: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let _timg = common::read_exact(&mut file, 288)?; //TIMG magic + header
|
||||
|
||||
|
||||
Reference in New Issue
Block a user