From b670649ed0fc835a6c1cfeef669f950831a82a72 Mon Sep 17 00:00:00 2001 From: Jean-Marie Mineau Date: Tue, 29 Aug 2023 11:50:24 +0200 Subject: [PATCH] add annotation item --- .../encoded_annotation.rs} | 0 androscalpel_serializer/src/annotation/mod.rs | 235 ++++++++++++++++++ 2 files changed, 235 insertions(+) rename androscalpel_serializer/src/{annotation.rs => annotation/encoded_annotation.rs} (100%) create mode 100644 androscalpel_serializer/src/annotation/mod.rs diff --git a/androscalpel_serializer/src/annotation.rs b/androscalpel_serializer/src/annotation/encoded_annotation.rs similarity index 100% rename from androscalpel_serializer/src/annotation.rs rename to androscalpel_serializer/src/annotation/encoded_annotation.rs diff --git a/androscalpel_serializer/src/annotation/mod.rs b/androscalpel_serializer/src/annotation/mod.rs new file mode 100644 index 0000000..56afde3 --- /dev/null +++ b/androscalpel_serializer/src/annotation/mod.rs @@ -0,0 +1,235 @@ +//! Annotation items. + +pub mod encoded_annotation; +pub use encoded_annotation::*; + +use crate as androscalpel_serializer; +use crate::{ReadSeek, Result, Serializable}; +use std::io::Write; + +/// https://source.android.com/docs/core/runtime/dex-format#referenced-from-class_def_item_1 +/// alignment: 4 bytes +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AnnotationDirectoryItem { + /// 0 if they are no annotation, else offset of an [`AnnotationSetItem`]. + pub class_annotations_off: u32, + // pub fields_size: u32, + // pub annotated_methods_size: u32, + // pub annotated_parameters_size: u32, + /// List of field annotation. The field annotations must be sorted by + /// increasing order of [`FieldAnnotation.field_idx`]. + pub field_annotations: Vec, + /// List of method annotation. The method annotations must be sorted by + /// increasing order of [`MethodAnnotation.method_idx`]. + pub method_annotation: Vec, + /// List of associated method parameter annotation. The parameter annotations + /// must be sorted by increasing order of [`ParameterAnnotation.parameter_size`]. + pub parameter_annotations: Vec, +} + +impl AnnotationDirectoryItem { + pub fn fields_size_field(&self) -> u32 { + self.field_annotations.len() as u32 + } + pub fn annotated_methods_size_field(&self) -> u32 { + self.method_annotation.len() as u32 + } + pub fn parameter_annotations_field(&self) -> u32 { + self.parameter_annotations.len() as u32 + } +} + +impl Serializable for AnnotationDirectoryItem { + fn serialize(&self, output: &mut dyn Write) -> Result<()> { + self.class_annotations_off.serialize(output)?; + self.fields_size_field().serialize(output)?; + self.annotated_methods_size_field().serialize(output)?; + self.parameter_annotations_field().serialize(output)?; + + for item in &self.field_annotations { + item.serialize(output)?; + } + for item in &self.method_annotation { + item.serialize(output)?; + } + for item in &self.parameter_annotations { + item.serialize(output)?; + } + Ok(()) + } + fn deserialize(input: &mut dyn ReadSeek) -> Result { + let class_annotations_off = u32::deserialize(input)?; + let fields_size = u32::deserialize(input)?; + let annotated_methods_size = u32::deserialize(input)?; + let annotated_parameters_size = u32::deserialize(input)?; + let mut field_annotations = vec![]; + for _ in 0..fields_size { + field_annotations.push(FieldAnnotation::deserialize(input)?); + } + let mut method_annotation = vec![]; + for _ in 0..annotated_methods_size { + method_annotation.push(MethodAnnotation::deserialize(input)?); + } + let mut parameter_annotations = vec![]; + for _ in 0..annotated_parameters_size { + parameter_annotations.push(ParameterAnnotation::deserialize(input)?); + } + + Ok(Self { + class_annotations_off, + field_annotations, + method_annotation, + parameter_annotations, + }) + } + fn size(&self) -> usize { + self.class_annotations_off.size() + + self.fields_size_field().size() + + self.annotated_methods_size_field().size() + + self.parameter_annotations_field().size() + + self + .field_annotations + .iter() + .map(|val| val.size()) + .sum::() + + self + .method_annotation + .iter() + .map(|val| val.size()) + .sum::() + + self + .parameter_annotations + .iter() + .map(|val| val.size()) + .sum::() + } +} + +/// https://source.android.com/docs/core/runtime/dex-format#field-annotation +#[derive(Serializable, Debug, Clone, PartialEq, Eq)] +pub struct FieldAnnotation { + pub field_idx: u32, + /// Offset to a [`AnnotationSetItem`] + pub annotation_off: u32, +} + +/// https://source.android.com/docs/core/runtime/dex-format#method-annotation +#[derive(Serializable, Debug, Clone, PartialEq, Eq)] +pub struct MethodAnnotation { + pub method_idx: u32, + /// Offset to a [`AnnotationSetItem`] + pub annotation_off: u32, +} + +/// https://source.android.com/docs/core/runtime/dex-format#parameter-annotation +#[derive(Serializable, Debug, Clone, PartialEq, Eq)] +pub struct ParameterAnnotation { + pub field_idx: u32, + /// Offset of a [`AnnotationSetRefList`] + pub annotation_off: u32, +} + +/// https://source.android.com/docs/core/runtime/dex-format#set-ref-list +/// alignment: 4 bytes +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AnnotationSetRefList { + // pub size: u32, + pub list: Vec, +} + +impl AnnotationSetRefList { + pub fn size_field(&self) -> u32 { + self.list.len() as u32 + } +} + +impl Serializable for AnnotationSetRefList { + fn serialize(&self, output: &mut dyn Write) -> Result<()> { + self.size_field().serialize(output)?; + for item in &self.list { + item.serialize(output)?; + } + Ok(()) + } + fn deserialize(input: &mut dyn ReadSeek) -> Result { + let size = u32::deserialize(input)?; + let mut list = vec![]; + for _ in 0..size { + list.push(AnnotationSetRefItem::deserialize(input)?); + } + Ok(Self { list }) + } + fn size(&self) -> usize { + self.size_field().size() + self.list.iter().map(|val| val.size()).sum::() + } +} + +/// https://source.android.com/docs/core/runtime/dex-format#set-ref-item +#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)] +pub struct AnnotationSetRefItem { + /// 0 if there are no annotation, offset to a [`AnnotationSetItem`] else. + pub annotations_off: u32, +} + +/// https://source.android.com/docs/core/runtime/dex-format#annotation-set-item +/// alignment: 4 +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AnnotationSetItem { + // pub size: u32, + /// Must be sorted by increasing [`AnnotationOffItem.type_idx`]. + pub entries: Vec, +} + +impl AnnotationSetItem { + pub fn size_field(&self) -> u32 { + self.entries.len() as u32 + } +} + +impl Serializable for AnnotationSetItem { + fn serialize(&self, output: &mut dyn Write) -> Result<()> { + self.size_field().serialize(output)?; + for item in &self.entries { + item.serialize(output)?; + } + Ok(()) + } + fn deserialize(input: &mut dyn ReadSeek) -> Result { + let size = u32::deserialize(input)?; + let mut entries = vec![]; + for _ in 0..size { + entries.push(AnnotationOffItem::deserialize(input)?); + } + Ok(Self { entries }) + } + fn size(&self) -> usize { + self.size_field().size() + self.entries.iter().map(|val| val.size()).sum::() + } +} + +/// https://source.android.com/docs/core/runtime/dex-format#off-item +#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)] +pub struct AnnotationOffItem { + /// Offset to a [`AnnotationItem`] + pub annotation_off: u32, +} + +/// https://source.android.com/docs/core/runtime/dex-format#annotation-item +#[derive(Serializable, Debug, Clone, PartialEq, Eq)] +pub struct AnnotationItem { + pub visibility: AnnotationVisibility, + pub annotation: EncodedAnnotation, +} + +// TODO: Enum or flags ? +/// https://source.android.com/docs/core/runtime/dex-format#annotation-item +#[derive(Serializable, Debug, Clone, PartialEq, Eq)] +#[prefix_type(u8)] +pub enum AnnotationVisibility { + #[prefix(0x00)] + Build, + #[prefix(0x01)] + Runtime, + #[prefix(0x02)] + System, +}