From 8157325a028dbb562a0d4a8aeab2964fcc71405c Mon Sep 17 00:00:00 2001 From: Jean-Marie Mineau Date: Wed, 17 Jan 2024 16:41:24 +0100 Subject: [PATCH] transfer file from one zip to another, WIP --- apk_frauder/src/lib.rs | 1 + apk_frauder/src/main.rs | 16 ++++++- apk_frauder/src/zip_writer.rs | 83 ++++++++++++++++++++++++++++++----- 3 files changed, 86 insertions(+), 14 deletions(-) diff --git a/apk_frauder/src/lib.rs b/apk_frauder/src/lib.rs index e6206d0..ca51bf6 100644 --- a/apk_frauder/src/lib.rs +++ b/apk_frauder/src/lib.rs @@ -14,6 +14,7 @@ use extra_fields::{ExtraField, Zip64ExtraField}; use file_header::FileHeader; use local_file_header::LocalFileHeader; pub use zip_reader::ZipFileReader; +pub use zip_writer::ZipFileWriter; #[derive(Debug, Clone, PartialEq, Eq, Serializable, Default)] pub struct Signature(pub u32); diff --git a/apk_frauder/src/main.rs b/apk_frauder/src/main.rs index 7306c1e..f325200 100644 --- a/apk_frauder/src/main.rs +++ b/apk_frauder/src/main.rs @@ -1,12 +1,13 @@ use apk_frauder::ZipFileReader; +use apk_frauder::ZipFileWriter; use std::fs::File; fn main() { + /* let file = File::open("app-release.apk").expect("failed to open file"); //let file = File::open("tst_64.zip").expect("failed to open file"); let zip_file = ZipFileReader::new(file); //println!("{}", zip_file.get_file_names().join("\n")); - /* for file in &zip_file.files { println!("{}", file.get_name()); println!("local: {:?}", file.local_header.malformed_extra_field); @@ -33,6 +34,17 @@ fn main() { println!("Not signed whith scheme >= v2"); } zip_file.check_holes(); - */ println!("{:#?}", zip_file.get_file_info("classes.dex")); + */ + + let file = File::open("app-release.apk").expect("failed to open file"); + let out_file = File::create("app-release.out.zip").expect("failed to create file"); + let mut zip_file = ZipFileReader::new(file); + let mut out_file = + ZipFileWriter::new(out_file, zip_file.zip64_end_of_central_directory.clone()); + for f in zip_file.files.clone() { + out_file.insert_file_from_zip(f, &mut zip_file); + } + out_file.write_central_directory(); + //println!("{:#?}", zip_file.zip64_end_of_central_directory); } diff --git a/apk_frauder/src/zip_writer.rs b/apk_frauder/src/zip_writer.rs index 28b3db1..7d045c7 100644 --- a/apk_frauder/src/zip_writer.rs +++ b/apk_frauder/src/zip_writer.rs @@ -1,9 +1,9 @@ use std::io::{Read, Seek, SeekFrom, Write}; -use crate::{ - end_of_central_directory::EndCentralDirectory, - end_of_central_directory::Zip64EndCentralDirectory, FileInfo, ZipFileReader, +use crate::end_of_central_directory::{ + EndCentralDirectory, Zip64EndCentralDirectory, Zip64EndCentralDirectoryLocator, }; +use crate::{FileInfo, ZipFileReader}; use androscalpel_serializer::Serializable; pub struct ZipFileWriter { @@ -14,6 +14,8 @@ pub struct ZipFileWriter { } impl ZipFileWriter { + /// If provided, `zip64_info` is used to get the value that are not computable from + /// the state, like version needed to extract. pub fn new(writer: T, zip64_info: Option) -> Self { Self { current_offset: 0, @@ -53,18 +55,75 @@ impl ZipFileWriter { for file_info in &self.files { file_info.header.serialize(&mut self.data).unwrap(); } - // TODO: zip64 + let number_of_entries_in_central_directory_on_disk = self.files.len(); + let number_of_entries_in_central_directory = self.files.len(); + let size_central_directory: u64 = self + .files + .iter() + .map(|file| file.header.size() as u64) + .sum(); + let offset_central_directory = self.current_offset; + let use_zip64 = (number_of_entries_in_central_directory_on_disk > u16::MAX as usize) + || (number_of_entries_in_central_directory > u16::MAX as usize) + || (size_central_directory > u32::MAX as u64) + || (offset_central_directory > u32::MAX as u64) + || self.zip64_end_of_central_directory.is_some(); + + if use_zip64 { + if self.zip64_end_of_central_directory.is_none() { + self.zip64_end_of_central_directory = Some(Zip64EndCentralDirectory { + version_made_by: 45, + version_needed_to_extract: 45, + number_of_this_disk: 0, + disk_number_of_central_directory_start: 0, + number_entry_in_central_directory_on_this_disk: 0, + number_entry_in_central_directory: 0, + size_of_central_directory: 0, + offset_central_directory: 0, + extensible_data: vec![], + }) + } + let zip64_edc = self.zip64_end_of_central_directory.as_mut().unwrap(); + zip64_edc.number_entry_in_central_directory_on_this_disk = + number_of_entries_in_central_directory_on_disk as u64; + zip64_edc.number_entry_in_central_directory = + number_of_entries_in_central_directory as u64; + zip64_edc.size_of_central_directory = size_central_directory; + zip64_edc.offset_central_directory = offset_central_directory; + zip64_edc.serialize(&mut self.data).unwrap(); + + Zip64EndCentralDirectoryLocator { + disk_number_of_zip64_end_central_directory_start: 0, + offset_zip64_end_of_central_directory_record: offset_central_directory + + size_central_directory, + total_number_of_disks: 0, + } + .serialize(&mut self.data) + .unwrap(); + } EndCentralDirectory { disk_number: 0, disk_number_of_central_directory_start: 0, - number_of_entries_in_central_directory_on_disk: self.files.len() as u16, - number_of_entries_in_central_directory: self.files.len() as u16, - size_central_directory: self - .files - .iter() - .map(|file| file.local_header.size() as u32 + file.get_compressed_size() as u32) - .sum(), - offset_central_directory: self.current_offset as u32, + number_of_entries_in_central_directory_on_disk: if use_zip64 { + u16::MAX + } else { + number_of_entries_in_central_directory_on_disk as u16 + }, + number_of_entries_in_central_directory: if use_zip64 { + u16::MAX + } else { + number_of_entries_in_central_directory as u16 + }, + size_central_directory: if use_zip64 { + u32::MAX + } else { + size_central_directory as u32 + }, + offset_central_directory: if use_zip64 { + u32::MAX + } else { + offset_central_directory as u32 + }, comment: vec![], } .serialize(&mut self.data)