From 519d0748be4b766c6d5e52aaf1f116af36a75133 Mon Sep 17 00:00:00 2001 From: Jean-Marie Mineau Date: Sun, 14 Jan 2024 14:11:03 +0100 Subject: [PATCH] new tool to explore .apk --- Cargo.lock | 7 ++ Cargo.toml | 1 + apk_frauder/Cargo.toml | 9 ++ apk_frauder/README.md | 1 + apk_frauder/src/main.rs | 234 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 252 insertions(+) create mode 100644 apk_frauder/Cargo.toml create mode 100644 apk_frauder/README.md create mode 100644 apk_frauder/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 7e1599f..ec3dea2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,13 @@ dependencies = [ "backtrace", ] +[[package]] +name = "apk_frauder" +version = "0.1.0" +dependencies = [ + "androscalpel_serializer", +] + [[package]] name = "arc-swap" version = "1.6.0" diff --git a/Cargo.toml b/Cargo.toml index bab6f5c..2f453a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ + "apk_frauder", "androscalpel_serializer", "androscalpel_serializer_derive", "androscalpel", diff --git a/apk_frauder/Cargo.toml b/apk_frauder/Cargo.toml new file mode 100644 index 0000000..e58d9b2 --- /dev/null +++ b/apk_frauder/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "apk_frauder" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +androscalpel_serializer = { version = "0.1.0", path = "../androscalpel_serializer" } diff --git a/apk_frauder/README.md b/apk_frauder/README.md new file mode 100644 index 0000000..dbd9dda --- /dev/null +++ b/apk_frauder/README.md @@ -0,0 +1 @@ +flate2/rust_backend diff --git a/apk_frauder/src/main.rs b/apk_frauder/src/main.rs new file mode 100644 index 0000000..9798e72 --- /dev/null +++ b/apk_frauder/src/main.rs @@ -0,0 +1,234 @@ +use std::fs::File; +use std::io::{Read, Seek, SeekFrom, Write}; + +use androscalpel_serializer::{ReadSeek, Result, Serializable}; + +#[derive(Debug, Clone, PartialEq, Eq, Serializable, Default)] +//struct Signature(pub [u8; 4]); +struct Signature(pub u32); + +#[derive(Debug, Clone, PartialEq, Eq)] +struct Zip64EndCentralDirectory { + // signature: Signature + // size_zip64_edf_record: u64 + version_made_by: u16, + version_needed_to_extract: u16, + number_of_this_disk: u32, + disk_number_of_central_directory_start: u32, + number_entry_in_central_directory_on_this_disk: u64, + number_entry_in_central_directory: u64, + size_of_central_directory: u64, + offset_central_directory: u64, + extensible_data: Vec, +} + +impl Zip64EndCentralDirectory { + const SIGNATURE: Signature = Signature(0x06064b50); + const MIN_SIZE: usize = 4 + 8 + 2 + 2 + 4 + 4 + 8 + 8 + 8 + 8; // + 0; +} + +impl Serializable for Zip64EndCentralDirectory { + fn serialize(&self, output: &mut dyn Write) -> Result<()> { + Self::SIGNATURE.serialize(output)?; + ((self.size() - 12) as u64).serialize(output)?; + self.version_made_by.serialize(output)?; + self.version_needed_to_extract.serialize(output)?; + self.number_of_this_disk.serialize(output)?; + self.disk_number_of_central_directory_start + .serialize(output)?; + self.number_entry_in_central_directory_on_this_disk + .serialize(output)?; + self.number_entry_in_central_directory.serialize(output)?; + self.size_of_central_directory.serialize(output)?; + self.offset_central_directory.serialize(output)?; + for d in &self.extensible_data { + d.serialize(output)?; + } + Ok(()) + } + + fn deserialize(input: &mut dyn ReadSeek) -> Result { + let signature = Signature::deserialize(input)?; + assert_eq!(signature, Self::SIGNATURE); // TODO + let size_zip64_edf_record = u64::deserialize(input)?; + let version_made_by = u16::deserialize(input)?; + let version_needed_to_extract = u16::deserialize(input)?; + let number_of_this_disk = u32::deserialize(input)?; + let disk_number_of_central_directory_start = u32::deserialize(input)?; + let number_entry_in_central_directory_on_this_disk = u64::deserialize(input)?; + let number_entry_in_central_directory = u64::deserialize(input)?; + let size_of_central_directory = u64::deserialize(input)?; + let offset_central_directory = u64::deserialize(input)?; + let mut extensible_data = vec![]; + for _ in 0..(size_zip64_edf_record as usize + 12 - Self::MIN_SIZE) { + extensible_data.push(u8::deserialize(input)?); + } + Ok(Self { + version_made_by, + version_needed_to_extract, + number_of_this_disk, + disk_number_of_central_directory_start, + number_entry_in_central_directory_on_this_disk, + number_entry_in_central_directory, + size_of_central_directory, + offset_central_directory, + extensible_data, + }) + } + + fn size(&self) -> usize { + Self::MIN_SIZE + self.extensible_data.len() + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serializable)] +struct Zip64EndCentralDirectoryLocator { + #[prefix(Self::SIGNATURE.0.to_le_bytes())] + disk_number_of_zip64_end_central_directory_start: u32, + offset_zip64_end_of_central_directory_record: u64, + total_number_of_disks: u32, +} + +impl Zip64EndCentralDirectoryLocator { + const SIGNATURE: Signature = Signature(0x07064b50); + const SIZE: usize = 4 + 4 + 8 + 4; +} + +#[derive(Debug, Clone, PartialEq, Eq)] +struct EndCentralDirectory { + //signature: Self::SIGNATURE, + disk_number: u16, + disk_number_of_central_directory_start: u16, + number_of_entries_in_central_directory_on_disk: u16, + number_of_entries_in_central_directory: u16, + size_central_directory: u32, + offset_central_directory: u32, + //file_comment_length: u16, + comment: Vec, +} + +impl EndCentralDirectory { + const SIGNATURE: Signature = Signature(0x06054b50); //Signature([0x06, 0x05, 0x4b, 0x50]); + const MIN_SIZE: usize = 4 + 4 * 2 + 2 * 4 + 2; // + 0; +} + +impl Serializable for EndCentralDirectory { + fn serialize(&self, output: &mut dyn Write) -> Result<()> { + Self::SIGNATURE.serialize(output)?; + self.disk_number.serialize(output)?; + self.disk_number_of_central_directory_start + .serialize(output)?; + self.number_of_entries_in_central_directory_on_disk + .serialize(output)?; + self.number_of_entries_in_central_directory + .serialize(output)?; + self.size_central_directory.serialize(output)?; + self.offset_central_directory.serialize(output)?; + (self.comment.len() as u16).serialize(output)?; + for c in &self.comment { + c.serialize(output)?; + } + Ok(()) + } + + fn deserialize(input: &mut dyn ReadSeek) -> Result { + let signature = Signature::deserialize(input)?; + let disk_number = u16::deserialize(input)?; + let disk_number_of_central_directory_start = u16::deserialize(input)?; + let number_of_entries_in_central_directory_on_disk = u16::deserialize(input)?; + let number_of_entries_in_central_directory = u16::deserialize(input)?; + let size_central_directory = u32::deserialize(input)?; + let offset_central_directory = u32::deserialize(input)?; + let file_comment_length = u16::deserialize(input)?; + let mut comment = vec![]; + for _ in 0..file_comment_length { + comment.push(u8::deserialize(input)?); + } + + assert_eq!(signature, Self::SIGNATURE); // TODO + Ok(Self { + disk_number, + disk_number_of_central_directory_start, + number_of_entries_in_central_directory_on_disk, + number_of_entries_in_central_directory, + size_central_directory, + offset_central_directory, + comment, + }) + } + + fn size(&self) -> usize { + Self::MIN_SIZE + self.comment.len() + } +} + +struct ZipFile { + end_of_central_directory: EndCentralDirectory, + end_of_central_directory_off: u64, + data: T, +} + +impl ZipFile { + fn new(mut reader: T) -> Self { + let end_of_central_directory_off = + Self::get_end_of_central_directory_offset(&mut reader).unwrap(); + reader + .seek(SeekFrom::Start(end_of_central_directory_off)) + .unwrap(); + let end_of_central_directory = EndCentralDirectory::deserialize(&mut reader).unwrap(); + println!("{end_of_central_directory:#?}"); + reader + .seek(SeekFrom::Start( + end_of_central_directory_off - Zip64EndCentralDirectoryLocator::SIZE as u64, + )) + .unwrap(); + let zip64_ecd_locator = Zip64EndCentralDirectoryLocator::deserialize(&mut reader).ok(); + if let Some(zip64_ecd_locator) = zip64_ecd_locator { + assert_eq!( + zip64_ecd_locator.disk_number_of_zip64_end_central_directory_start, + 0 + ); + assert!(zip64_ecd_locator.total_number_of_disks <= 1); + println!("Zip64 ECD Locator {:#?}", zip64_ecd_locator); + let zip64_edc_record_off = + zip64_ecd_locator.offset_zip64_end_of_central_directory_record; + reader.seek(SeekFrom::Start(zip64_edc_record_off)).unwrap(); + let zip64_edc_reccord = Zip64EndCentralDirectory::deserialize(&mut reader).ok(); + println!("{zip64_edc_reccord:#?}"); + } + + Self { + end_of_central_directory, + end_of_central_directory_off, + data: reader, + } + } + + fn get_end_of_central_directory_offset(reader: &mut T) -> Option { + let file_size = reader.seek(SeekFrom::End(0)).unwrap(); + let mut sig = Signature::default(); + let mut comment_size = 0; + while sig != EndCentralDirectory::SIGNATURE { + reader + .seek(SeekFrom::End( + -(EndCentralDirectory::MIN_SIZE as i64) - comment_size, + )) + .unwrap(); + sig = Signature::deserialize(reader).unwrap(); + comment_size += 1; + if comment_size > 65536 + || comment_size as usize + EndCentralDirectory::MIN_SIZE > file_size as usize + { + return None; + } + } + comment_size -= 1; + Some(file_size - comment_size as u64 - EndCentralDirectory::MIN_SIZE as u64) + } +} + +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_fime = ZipFile::new(file); +}