From 0f5764c3400415f15a2b58c3e039fa25a15ce37c Mon Sep 17 00:00:00 2001 From: Jean-Marie Mineau Date: Mon, 22 Jan 2024 14:22:28 +0100 Subject: [PATCH] implement file insertion --- apk_frauder/src/file_header.rs | 53 +++++++++++++++++++--------- apk_frauder/src/lib.rs | 36 +++++++++++++++++++ apk_frauder/src/local_file_header.rs | 15 ++++++++ apk_frauder/src/main.rs | 11 +++++- 4 files changed, 98 insertions(+), 17 deletions(-) diff --git a/apk_frauder/src/file_header.rs b/apk_frauder/src/file_header.rs index 9f1bd01..1968703 100644 --- a/apk_frauder/src/file_header.rs +++ b/apk_frauder/src/file_header.rs @@ -1,10 +1,9 @@ use std::io::{SeekFrom, Write}; use crate::compression::CompressionMethod; -use crate::cp437::string_to_cp437; use crate::error::Error; use crate::extra_fields::{ExtraField, GenericExtraField, Zip64ExtraField}; -use crate::{cp437, general_purpose_flags, Encoding, Signature}; +use crate::{cp437, external_file_attributes, general_purpose_flags, Encoding, Signature}; use androscalpel_serializer::{ReadSeek, Result, Serializable}; #[derive(Debug, Clone, PartialEq, Eq)] @@ -191,18 +190,10 @@ impl FileHeader { const MIN_SIZE: usize = 4 + 6 * 2 + 4 * 3 + 5 * 2 + 4 * 2; pub fn new_default(name: &str) -> Self { - let mut general_purpose_flags = 0; - let file_name = match string_to_cp437(name) { - Ok(name) => name, - Err(Error::NotCp437) => { - general_purpose_flags |= general_purpose_flags::MASK_UTF8_FILENAME; - name.as_bytes().into() - } - }; - FileHeader { + let mut header = FileHeader { version_made_by: 768, version_needed_to_extract: 0, - general_purpose_flags, + general_purpose_flags: 0, compression_method: CompressionMethod::Deflated, last_mod_file_time: 0, last_mod_file_data: 0, @@ -211,13 +202,20 @@ impl FileHeader { uncompressed_size: 0, disk_number_start: 0, internal_file_attributes: 0, - external_file_attributes: 0b1000000110100100 << 16, // TODO + // TODO: why 0b10000000 ? + external_file_attributes: external_file_attributes::REGULAR_FILE + | external_file_attributes::PERM_UR + | external_file_attributes::PERM_UW + | external_file_attributes::PERM_GR + | external_file_attributes::PERM_OR, // TODO offset_local_header: 0, - file_name, + file_name: vec![], extra_field: vec![], malformed_extra_field: vec![], file_comment: vec![], - } + }; + header.set_name(name); + header } pub fn get_name_encoding(&self) -> Encoding { @@ -227,13 +225,36 @@ impl FileHeader { Encoding::CP437 } } - pub fn get_name(&self) -> String { match self.get_name_encoding() { Encoding::UTF8 => std::str::from_utf8(&self.file_name).unwrap().into(), Encoding::CP437 => cp437::cp437_to_string(&self.file_name), } } + pub fn external_file_attributes_set_flag(&mut self, flag: u32) { + self.external_file_attributes |= flag; + } + pub fn external_file_attributes_unset_flag(&mut self, flag: u32) { + self.external_file_attributes &= !flag; + } + pub fn set_file_type(&mut self, file_type: u32) { + self.external_file_attributes &= !external_file_attributes::MASK_FILE_TYPE; + self.external_file_attributes |= file_type; + } + + pub fn set_name(&mut self, name: &str) { + let file_name = match cp437::string_to_cp437(name) { + Ok(name) => { + self.general_purpose_flags &= !general_purpose_flags::MASK_UTF8_FILENAME; + name + } + Err(Error::NotCp437) => { + self.general_purpose_flags |= general_purpose_flags::MASK_UTF8_FILENAME; + name.as_bytes().into() + } + }; + self.file_name = file_name; + } pub fn get_uncompressed_size(&self) -> u64 { if self.uncompressed_size != u32::MAX { diff --git a/apk_frauder/src/lib.rs b/apk_frauder/src/lib.rs index 5a865e5..31627ec 100644 --- a/apk_frauder/src/lib.rs +++ b/apk_frauder/src/lib.rs @@ -35,6 +35,29 @@ pub mod general_purpose_flags { pub const MASK_ENCRYPTED_CENTRAL_DIR: u16 = 1 << 13; } +pub mod external_file_attributes { + pub const FIFO_FILE: u32 = 0b00010000 << 24; + // #define S_IFCHR 0020000 /* character special */ ? + pub const DIR_FILE: u32 = 0b01000000 << 24; + // #define S_IFBLK 0060000 /* block special */ ? + pub const SYMBOLIC_LINK_FILE: u32 = 0b10100000 << 24; + pub const SOCKET_FILE: u32 = 0b11000000 << 24; + pub const REGULAR_FILE: u32 = 0b10000000 << 24; + pub const MASK_FILE_TYPE: u32 = 0b11110000 << 24; + pub const SETUID: u32 = 0b0000100000000000 << 16; + pub const SETGID: u32 = 0b0000010000000000 << 16; + pub const STICKY: u32 = 0b0000001000000000 << 16; + pub const PERM_UR: u32 = 0b0000000100000000 << 16; + pub const PERM_UW: u32 = 0b0000000010000000 << 16; + pub const PERM_UX: u32 = 0b0000000001000000 << 16; + pub const PERM_GR: u32 = 0b0000000000100000 << 16; + pub const PERM_GW: u32 = 0b0000000000010000 << 16; + pub const PERM_GX: u32 = 0b0000000000001000 << 16; + pub const PERM_OR: u32 = 0b0000000000000100 << 16; + pub const PERM_OW: u32 = 0b0000000000000010 << 16; + pub const PERM_OX: u32 = 0b0000000000000001 << 16; +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct FileInfo { pub local_header: LocalFileHeader, @@ -46,6 +69,19 @@ impl FileInfo { pub fn get_name(&self) -> String { self.header.get_name() } + pub fn set_name(&mut self, name: &str) { + self.header.set_name(name); + self.local_header.set_name(name); + } + pub fn external_file_attributes_set_flag(&mut self, flag: u32) { + self.header.external_file_attributes_set_flag(flag); + } + pub fn external_file_attributes_unset_flag(&mut self, flag: u32) { + self.header.external_file_attributes_unset_flag(flag); + } + pub fn set_file_type(&mut self, file_type: u32) { + self.header.set_file_type(file_type); + } pub fn get_offset_local_header(&self) -> u64 { self.header.get_offset_local_header() } diff --git a/apk_frauder/src/local_file_header.rs b/apk_frauder/src/local_file_header.rs index 635b271..17fd0d0 100644 --- a/apk_frauder/src/local_file_header.rs +++ b/apk_frauder/src/local_file_header.rs @@ -1,6 +1,7 @@ use std::io::{SeekFrom, Write}; use crate::compression::CompressionMethod; +use crate::error::Error; use crate::extra_fields::{ExtraField, GenericExtraField, Zip64ExtraField}; use crate::{cp437, general_purpose_flags, Encoding, Signature}; use androscalpel_serializer::{ReadSeek, Result, Serializable}; @@ -198,6 +199,20 @@ impl LocalFileHeader { } } + pub fn set_name(&mut self, name: &str) { + let file_name = match cp437::string_to_cp437(name) { + Ok(name) => { + self.general_purpose_flags &= !general_purpose_flags::MASK_UTF8_FILENAME; + name + } + Err(Error::NotCp437) => { + self.general_purpose_flags |= general_purpose_flags::MASK_UTF8_FILENAME; + name.as_bytes().into() + } + }; + self.file_name = file_name; + } + pub fn get_uncompressed_size(&self) -> u64 { if self.uncompressed_size != u32::MAX { self.uncompressed_size as u64 diff --git a/apk_frauder/src/main.rs b/apk_frauder/src/main.rs index 2f0810e..d3dc0a9 100644 --- a/apk_frauder/src/main.rs +++ b/apk_frauder/src/main.rs @@ -1,3 +1,4 @@ +use apk_frauder::external_file_attributes; use apk_frauder::file_header::FileHeader; use apk_frauder::ZipFileReader; use apk_frauder::ZipFileWriter; @@ -59,9 +60,17 @@ fn main() { None, ); out_file.insert_file( - &mut Cursor::new(b"Hello World\n"), + &mut Cursor::new(b"Hello World !!!\n"), FileHeader::new_default("plip.txt"), None, ); + + //let mut header_dir = FileHeader::new_default("dir"); + //header_dir.set_file_type(external_file_attributes::DIR_FILE); + //out_file.insert_file(&mut Cursor::new(b""), header_dir, None); + let mut header_link = FileHeader::new_default("dir/link"); + header_link.set_file_type(external_file_attributes::SYMBOLIC_LINK_FILE); + out_file.insert_file(&mut Cursor::new(b"../plop.txt"), header_link, None); + out_file.write_central_directory(); }