diff --git a/apk_frauder/src/extra_fields.rs b/apk_frauder/src/extra_fields.rs new file mode 100644 index 0000000..6bc532d --- /dev/null +++ b/apk_frauder/src/extra_fields.rs @@ -0,0 +1,139 @@ +use std::io::{Cursor, Write}; + +use androscalpel_serializer::{ReadSeek, Result, Serializable}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ExtraField { + Zip64(Zip64ExtraField), + Generic(GenericExtraField), +} + +impl ExtraField { + fn to_generic(&self) -> Result { + match self { + Self::Zip64(field) => field.to_generic_field(), + Self::Generic(field) => Ok(field.clone()), + } + } +} + +impl Serializable for ExtraField { + fn serialize(&self, output: &mut dyn Write) -> Result<()> { + self.to_generic()?.serialize(output) + } + + fn deserialize(input: &mut dyn ReadSeek) -> Result { + Ok(Self::Generic(GenericExtraField::deserialize(input)?)) + + /* + match field.id { + Zip64ExtraField::ID => Ok(Self::Zip64(Zip64ExtraField::from_generic(&field)?)), + _ => Ok(Self::Generic(field)), + } + */ + } + + fn size(&self) -> usize { + self.to_generic().unwrap().size() + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Zip64ExtraField { + pub original_size: Option, + pub compressed_size: Option, + pub offset_header: Option, + pub disk_number: Option, +} + +impl Zip64ExtraField { + pub const ID: u16 = 0x0001; + fn to_generic_field(&self) -> Result { + let mut data = Cursor::new(Vec::::new()); + if let Some(original_size) = self.original_size { + original_size.serialize(&mut data)?; + } + if let Some(compressed_size) = self.compressed_size { + compressed_size.serialize(&mut data)?; + } + if let Some(offset_header) = self.offset_header { + offset_header.serialize(&mut data)?; + } + if let Some(disk_number) = self.disk_number { + disk_number.serialize(&mut data)?; + } + + Ok(GenericExtraField { + id: Self::ID, + data: data.into_inner(), + }) + } + + pub fn from_generic( + field: &GenericExtraField, + original_size: bool, + compressed_size: bool, + offset_header: bool, + disk_number: bool, + ) -> Result { + assert_eq!(field.id, Self::ID); + let mut data = Cursor::new(&field.data); + let original_size = if original_size { + Some(u64::deserialize(&mut data)?) + } else { + None + }; + let compressed_size = if compressed_size { + Some(u64::deserialize(&mut data)?) + } else { + None + }; + let offset_header = if offset_header { + Some(u64::deserialize(&mut data)?) + } else { + None + }; + let disk_number = if disk_number { + Some(u32::deserialize(&mut data)?) + } else { + None + }; + Ok(Self { + original_size, + compressed_size, + offset_header, + disk_number, + }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct GenericExtraField { + pub id: u16, + pub data: Vec, +} + +impl Serializable for GenericExtraField { + fn serialize(&self, output: &mut dyn Write) -> Result<()> { + self.id.serialize(output)?; + (self.data.len() as u16).serialize(output)?; + for c in &self.data { + c.serialize(output)?; + } + Ok(()) + } + + fn deserialize(input: &mut dyn ReadSeek) -> Result { + let id = u16::deserialize(input)?; + let data_size = u16::deserialize(input)?; + let mut data = vec![]; + for _ in 0..data_size { + data.push(u8::deserialize(input)?); + } + Ok(Self { id, data }) + } + + fn size(&self) -> usize { + 4 + self.data.len() + } +} diff --git a/apk_frauder/src/file_header.rs b/apk_frauder/src/file_header.rs index 9872594..144a524 100644 --- a/apk_frauder/src/file_header.rs +++ b/apk_frauder/src/file_header.rs @@ -1,5 +1,6 @@ -use std::io::{Cursor, SeekFrom, Write}; +use std::io::{SeekFrom, Write}; +use crate::extra_fields::{ExtraField, GenericExtraField, Zip64ExtraField}; use crate::{cp437, Signature}; use androscalpel_serializer::{ReadSeek, Result, Serializable}; @@ -8,142 +9,6 @@ pub enum Encoding { UTF8, } -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ExtraField { - Zip64(Zip64ExtraField), - Generic(GenericExtraField), -} - -impl ExtraField { - fn to_generic(&self) -> Result { - match self { - Self::Zip64(field) => field.to_generic_field(), - Self::Generic(field) => Ok(field.clone()), - } - } -} - -impl Serializable for ExtraField { - fn serialize(&self, output: &mut dyn Write) -> Result<()> { - self.to_generic()?.serialize(output) - } - - fn deserialize(input: &mut dyn ReadSeek) -> Result { - Ok(Self::Generic(GenericExtraField::deserialize(input)?)) - - /* - match field.id { - Zip64ExtraField::ID => Ok(Self::Zip64(Zip64ExtraField::from_generic(&field)?)), - _ => Ok(Self::Generic(field)), - } - */ - } - - fn size(&self) -> usize { - self.to_generic().unwrap().size() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Zip64ExtraField { - original_size: Option, - compressed_size: Option, - offset_header: Option, - disk_number: Option, -} - -impl Zip64ExtraField { - const ID: u16 = 0x0001; - fn to_generic_field(&self) -> Result { - let mut data = Cursor::new(Vec::::new()); - if let Some(original_size) = self.original_size { - original_size.serialize(&mut data)?; - } - if let Some(compressed_size) = self.compressed_size { - compressed_size.serialize(&mut data)?; - } - if let Some(offset_header) = self.offset_header { - offset_header.serialize(&mut data)?; - } - if let Some(disk_number) = self.disk_number { - disk_number.serialize(&mut data)?; - } - - Ok(GenericExtraField { - id: Self::ID, - data: data.into_inner(), - }) - } - - fn from_generic( - field: &GenericExtraField, - original_size: bool, - compressed_size: bool, - offset_header: bool, - disk_number: bool, - ) -> Result { - assert_eq!(field.id, Self::ID); - let mut data = Cursor::new(&field.data); - let original_size = if original_size { - Some(u64::deserialize(&mut data)?) - } else { - None - }; - let compressed_size = if compressed_size { - Some(u64::deserialize(&mut data)?) - } else { - None - }; - let offset_header = if offset_header { - Some(u64::deserialize(&mut data)?) - } else { - None - }; - let disk_number = if disk_number { - Some(u32::deserialize(&mut data)?) - } else { - None - }; - Ok(Self { - original_size, - compressed_size, - offset_header, - disk_number, - }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct GenericExtraField { - pub id: u16, - pub data: Vec, -} - -impl Serializable for GenericExtraField { - fn serialize(&self, output: &mut dyn Write) -> Result<()> { - self.id.serialize(output)?; - (self.data.len() as u16).serialize(output)?; - for c in &self.data { - c.serialize(output)?; - } - Ok(()) - } - - fn deserialize(input: &mut dyn ReadSeek) -> Result { - let id = u16::deserialize(input)?; - let data_size = u16::deserialize(input)?; - let mut data = vec![]; - for _ in 0..data_size { - data.push(u8::deserialize(input)?); - } - Ok(Self { id, data }) - } - - fn size(&self) -> usize { - 4 + self.data.len() - } -} - #[derive(Debug, Clone, PartialEq, Eq)] pub struct FileHeader { // signature: Signature(0x02014b50) diff --git a/apk_frauder/src/lib.rs b/apk_frauder/src/lib.rs index cf38037..0d11d58 100644 --- a/apk_frauder/src/lib.rs +++ b/apk_frauder/src/lib.rs @@ -5,6 +5,7 @@ use androscalpel_serializer::Serializable; pub mod apk_signing_block; mod cp437; pub mod end_of_central_directory; +pub mod extra_fields; pub mod file_header; use apk_signing_block::*;