diff --git a/androscalpel_serializer/src/items/hiddenapi.rs b/androscalpel_serializer/src/items/hiddenapi.rs new file mode 100644 index 0000000..a918a5a --- /dev/null +++ b/androscalpel_serializer/src/items/hiddenapi.rs @@ -0,0 +1,141 @@ +//! Hidden api items. + +use crate as androscalpel_serializer; +use crate::{Error, ReadSeek, Result, Serializable, Uleb128}; +use std::io::{Cursor, Write}; + +/// https://source.android.com/docs/core/runtime/dex-format#hiddenapi-class-data-item +/// Hard to serialize/deserialize without additional data like the number of classes +/// or the method/field of the classes. +#[derive(Clone, PartialEq, Eq)] +pub struct HiddenapiClassDataItem { + //pub size: u32, + pub data: Vec, +} + +impl HiddenapiClassDataItem { + pub fn size_field(&self) -> u32 { + self.data.len() as u32 + } + + /// Return `hiddenapi_class_data_item.offsets[class_idx]`. + /// + /// If `0`: Either no data for this class or all API flags are zero. + /// Else: offset from the begining of the [`HiddenapiClassDataItem`] + /// (including the size /!\). + /// + /// # Warning + /// + /// They are no check weither the `class_idx` is valid one or not. + /// Giving an invalid idx (like an idx >= nb class) is UB. + pub fn get_offset(&self, class_idx: u32) -> Result { + let index = (class_idx as usize) * 4; + if self.data.len() < index - 4 { + Err(Error::InconsistantStruct(format!( + "class index 0x{class_idx:x} out of bound of HiddenapiClassDataItem data" + ))) + } else { + u32::deserialize_from_slice(&self.data[index..]) + } + } + + /// Return `hiddenapi_class_data_item.offsets`. + /// + /// # Warning + /// + /// They are no check weither the `nb_class` is valid one or not. + /// Giving an invalid `nb_class`. + pub fn get_offsets(&self, nb_class: u32) -> Result> { + let mut offsets = vec![]; + let mut buffer = Cursor::new(self.data.as_slice()); + for _ in 0..nb_class { + offsets.push(u32::deserialize(&mut buffer)?); + } + Ok(offsets) + } + + /// Get a list of `nb_flags` flags from the `offset`. + /// `nb_flags` should be the number of field + the number of method + /// of the class associated to `offset`. + /// + /// # Warning + /// + /// They are no check weither the `nb_flags` or `offset` + /// are valid. Providing invalid values is UB. + pub fn get_flags(&self, nb_flags: usize, offset: u32) -> Result> { + if offset == 0 { + Ok(vec![Uleb128(0); nb_flags]) + } else if offset < 4 { + // < 8 is almost certainly false + panic!() + } else { + let mut buffer = Cursor::new(self.data.as_slice()); + let mut flags = vec![]; + for _ in 0..nb_flags { + flags.push(Uleb128::deserialize(&mut buffer)?); + } + Ok(flags) + } + } +} + +impl Serializable for HiddenapiClassDataItem { + fn serialize(&self, output: &mut dyn Write) -> Result<()> { + self.size_field().serialize(output)?; + for byte in &self.data { + byte.serialize(output)?; + } + Ok(()) + } + + fn deserialize(input: &mut dyn ReadSeek) -> Result { + let size = u32::deserialize(input)?; + let mut data = vec![]; + for _ in 0..size { + data.push(u8::deserialize(input)?); + } + Ok(Self { data }) + } + + fn size(&self) -> usize { + self.size_field().size() + self.data.iter().map(|val| val.size()).sum::() + } +} + +/// Flags for hidden api +#[derive(Serializable, Debug, PartialEq, Eq, Copy, Clone)] +#[prefix_type(Uleb128)] +pub enum HiddenApiFlag { + /// Interfaces that can be freely used and are supported as + /// part of the officially documented Android framework Package Index + #[prefix(Uleb128(0x00))] + Whitelist, + /// Non-SDK interfaces that can be used regardless of the + /// application's target API level + #[prefix(Uleb128(0x01))] + Greylist, + /// Non-SDK interfaces that cannot be used regardless of the + /// application's target API level. Accessing one of these + /// interfaces causes a runtime error. + #[prefix(Uleb128(0x02))] + Blacklist, + /// Non-SDK interfaces that can be used for Android 8.x and + /// below unless they are restricted. + #[prefix(Uleb128(0x03))] + GreylistMaxO, + /// Non-SDK interfaces that can be used for Android 9.x unless + /// they are restricted. + #[prefix(Uleb128(0x04))] + GreylistMaxP, + /// Non-SDK interfaces that can be used for Android 10.x unless + /// they are restricted. + #[prefix(Uleb128(0x05))] + GreylistMaxQ, + /// Non-SDK interfaces that can be used for Android 11.x unless + /// they are restricted. + #[prefix(Uleb128(0x06))] + GreylistMaxR, + /// Unknown flag, either an error or this crate is out of date. + #[default_variant] + Unknwon(Uleb128), +} diff --git a/androscalpel_serializer/src/items/mod.rs b/androscalpel_serializer/src/items/mod.rs index c870b28..99abac7 100644 --- a/androscalpel_serializer/src/items/mod.rs +++ b/androscalpel_serializer/src/items/mod.rs @@ -6,11 +6,13 @@ use crate::{EncodedArray, Serializable}; pub mod class; pub mod code; pub mod header; +pub mod hiddenapi; pub mod map; pub use class::*; pub use code::*; pub use header::*; +pub use hiddenapi::*; pub use map::*; /// https://source.android.com/docs/core/runtime/dex-format#string-item