add item related to class

This commit is contained in:
Jean-Marie Mineau 2023-08-25 19:05:05 +02:00
parent 42698cc8d7
commit 9ed99594cc
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
4 changed files with 293 additions and 6 deletions

View file

@ -0,0 +1,252 @@
//! Class definitions.
use crate as androscalpel_serializer;
use crate::{ReadSeek, Result, Serializable, Uleb128};
use std::io::Write;
/// https://source.android.com/docs/core/runtime/dex-format#class-def-item
/// alignment: 4 bytes
#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)]
pub struct ClassDefItem {
/// Index of a [`TypeIdItem`] in `type_ids`, must be a class.
pub class_idx: u32,
/// See [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
pub access_flags: u32,
/// Either index of a [`TypeIdItem`] in `type_ids`, must be a class or NO_INDEX
pub superclass_idx: u32,
/// 0 if no interfaces, else offset to a [`TypeList`].
pub interfaces_off: u32,
/// Index of a [`StringIdItem`] in `string_ids` or NO_INDEX.
pub source_file_idx: u32,
/// 0 if no annotation, else offset to a [`AnnotationDirectoryItem`].
pub annotations_off: u32,
/// 0 if no data for this class, else offset to a [`ClassDataItem`].
pub class_data_off: u32,
/// 0 if no static fields, else offset to an [`EncodedArrayItem`].
///
/// Notes:
///
/// > The size of the array must be no larger than the number of static
/// > fields declared by this class, and the elements correspond to the
/// > static fields in the same order as declared in the corresponding
/// > field_list. The type of each array element must match the declared
/// > type of its corresponding field. If there are fewer elements in the
/// > array than there are static fields, then the leftover fields are
/// > initialized with a type-appropriate 0 or null.
pub static_values_off: u32,
}
/// https://source.android.com/docs/core/runtime/dex-format#method-handle-item
/// alignment: 4 bytes
#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)]
pub struct MethodHandleItem {
pub method_handle_type: MethodHandleType,
pub unused1: u16,
pub field_or_method_id: u16,
pub unused2: u16,
}
/// https://source.android.com/docs/core/runtime/dex-format#method-handle-type-codes
#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)]
#[prefix_type(u16)]
pub enum MethodHandleType {
#[prefix(0x00)]
StaticPut,
#[prefix(0x01)]
StaticGet,
#[prefix(0x02)]
InstancePut,
#[prefix(0x03)]
InstanceGet,
#[prefix(0x04)]
InvokeStatic,
#[prefix(0x05)]
InvokeInstance,
#[prefix(0x06)]
InvokeConstructor,
#[prefix(0x07)]
InvokeDirect,
#[prefix(0x08)]
InvokeInterface,
}
/// https://source.android.com/docs/core/runtime/dex-format#class-data-item
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ClassDataItem {
// pub static_fields_size: Uleb128,
// pub instance_fields_size: Uleb128,
// pub direct_methods_size: Uleb128,
// pub virtual_methods_size: Uleb128,
pub static_fields: Vec<EncodedField>,
pub instance_fields: Vec<EncodedField>,
pub direct_methods: Vec<EncodedMethod>,
pub virtual_methods: Vec<EncodedMethod>,
}
impl ClassDataItem {
pub fn static_fields_size_field(&self) -> Uleb128 {
Uleb128(self.static_fields.len() as u32)
}
pub fn instance_fields_size_field(&self) -> Uleb128 {
Uleb128(self.instance_fields.len() as u32)
}
pub fn direct_methods_size_field(&self) -> Uleb128 {
Uleb128(self.direct_methods.len() as u32)
}
pub fn virtual_methods_size_field(&self) -> Uleb128 {
Uleb128(self.virtual_methods.len() as u32)
}
}
impl Serializable for ClassDataItem {
fn serialize(&self, output: &mut dyn Write) -> Result<()> {
self.static_fields_size_field().serialize(output)?;
self.instance_fields_size_field().serialize(output)?;
self.direct_methods_size_field().serialize(output)?;
self.virtual_methods_size_field().serialize(output)?;
for field in &self.static_fields {
field.serialize(output)?;
}
for field in &self.instance_fields {
field.serialize(output)?;
}
for method in &self.direct_methods {
method.serialize(output)?;
}
for method in &self.virtual_methods {
method.serialize(output)?;
}
Ok(())
}
fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
let Uleb128(static_fields_size) = Uleb128::deserialize(input)?;
let Uleb128(instance_fields_size) = Uleb128::deserialize(input)?;
let Uleb128(direct_methods_size) = Uleb128::deserialize(input)?;
let Uleb128(virtual_methods_size) = Uleb128::deserialize(input)?;
let mut static_fields = vec![];
let mut instance_fields = vec![];
let mut direct_methods = vec![];
let mut virtual_methods = vec![];
for _ in 0..static_fields_size {
static_fields.push(EncodedField::deserialize(input)?);
}
for _ in 0..instance_fields_size {
instance_fields.push(EncodedField::deserialize(input)?);
}
for _ in 0..direct_methods_size {
direct_methods.push(EncodedMethod::deserialize(input)?);
}
for _ in 0..virtual_methods_size {
virtual_methods.push(EncodedMethod::deserialize(input)?);
}
Ok(Self {
// static_fields_size: Uleb128(static_fields_size),
// instance_fields_size: Uleb128(instance_fields_size),
// direct_methods_size: Uleb128(direct_methods_size),
// virtual_methods_size: Uleb128(virtual_methods_size),
static_fields,
instance_fields,
direct_methods,
virtual_methods,
})
}
fn size(&self) -> usize {
self.static_fields_size_field().size()
+ self.instance_fields_size_field().size()
+ self.direct_methods_size_field().size()
+ self.virtual_methods_size_field().size()
+ self
.static_fields
.iter()
.map(|val| val.size())
.sum::<usize>()
+ self
.instance_fields
.iter()
.map(|val| val.size())
.sum::<usize>()
+ self
.direct_methods
.iter()
.map(|val| val.size())
.sum::<usize>()
+ self
.virtual_methods
.iter()
.map(|val| val.size())
.sum::<usize>()
}
}
/// https://source.android.com/docs/core/runtime/dex-format#encoded-field-format
#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)]
pub struct EncodedField {
/// Index into the `field_ids` list for the identity of this field
/// (includes the name and descriptor), represented as a difference
/// from the index of previous element in the list. The index of the
/// first element in a list is represented directly.
pub field_idx_diff: Uleb128,
pub access_flags: Uleb128,
}
/// https://source.android.com/docs/core/runtime/dex-format#encoded-method
#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)]
pub struct EncodedMethod {
/// Index into the `method_ids list` for the identity of this method
/// (includes the name and descriptor), represented as a difference
/// from the index of previous element in the list. The index of the
/// first element in a list is represented directly.
pub method_idx_diff: Uleb128,
pub access_flags: Uleb128,
/// 0 if abstract or native, else offset to a [`CodeItem`].
pub code_off: Uleb128,
}
/// https://source.android.com/docs/core/runtime/dex-format#type-list
/// alignment: 4 bytes
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeList {
// pub size: u32,
pub list: Vec<TypeItem>,
}
impl TypeList {
fn size_field(&self) -> u32 {
self.list.len() as u32
}
}
impl Serializable for TypeList {
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<Self> {
let size = i32::deserialize(input)?;
let mut list = vec![];
for _ in 0..size {
list.push(TypeItem::deserialize(input)?);
}
Ok(Self {
// size,
list,
})
}
fn size(&self) -> usize {
self.size_field().size() + self.list.iter().map(|val| val.size()).sum::<usize>()
}
}
/// https://source.android.com/docs/core/runtime/dex-format#type-item-format
#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)]
pub struct TypeItem {
/// Index into the `type_ids` list.
pub type_idx: u16,
}

View file

@ -1,6 +1,7 @@
//! The header item: https://source.android.com/docs/core/runtime/dex-format#header-item
use crate::{DexFileMagic, EndianConstant};
use crate as androscalpel_serializer;
use crate::{DexFileMagic, EndianConstant, Serializable};
/// The header item: https://source.android.com/docs/core/runtime/dex-format#header-item
///

View file

@ -79,7 +79,7 @@ impl MapList {
impl Serializable for MapList {
fn serialize(&self, output: &mut dyn Write) -> Result<()> {
self.size_field().serialize(output)?;
for map_item in self.list {
for map_item in &self.list {
map_item.serialize(output)?;
}
Ok(())

View file

@ -1,11 +1,13 @@
//! The items structures.
use crate as androscalpel_serializer;
use crate::Serializable;
use crate::{EncodedArray, Serializable};
pub mod class;
pub mod header;
pub mod map;
pub use class::*;
pub use header::*;
pub use map::*;
@ -34,7 +36,7 @@ pub struct ProtoIdItem {
pub shorty_idx: u32,
/// Index of a [`TypeIdItem`] in `type_ids`.
pub return_type_idx: u32,
/// 0 if no parameter, else offset to a [`TypeList`.
/// 0 if no parameter, else offset to a [`TypeList`].
pub parameters_off: u32,
}
@ -42,7 +44,7 @@ pub struct ProtoIdItem {
/// alignment: 4 bytes
#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)]
pub struct FieldIdItem {
/// Index of a [`TypeIdItem`] in `type_ids`], must be a class.
/// Index of a [`TypeIdItem`] in `type_ids`, must be a class.
pub class_idx: u16,
/// Index of a [`TypeIdItem`] in `type_ids`.
pub type_idx: u16,
@ -54,10 +56,42 @@ pub struct FieldIdItem {
/// alignment: 4 bytes
#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)]
pub struct MethodIdItem {
/// Index of a [`TypeIdItem`] in `type_ids`], must be a class.
/// Index of a [`TypeIdItem`] in `type_ids`, must be a class.
pub class_idx: u16,
/// Index of a [`ProtoIdItem`] in `proto_ids`.
pub proto_idx: u16,
/// Index of a [`StringIdItem`] in [`HeaderItem.string_ids`].
pub name_idx: u32,
}
/// https://source.android.com/docs/core/runtime/dex-format#call-site-id-item
/// alignment: 4 bytes
#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)]
pub struct CallSiteIdItem {
/// Offset to a [`CallSiteItem`].
pub call_site_off: u32,
}
/// https://source.android.com/docs/core/runtime/dex-format#encoded-array-item
/// alignment: none
#[derive(Serializable, Debug, Clone, PartialEq, Eq)]
pub struct EncodedArrayItem {
pub value: EncodedArray,
}
/// https://source.android.com/docs/core/runtime/dex-format#call-site-item
///
/// The call_site_item is an encoded_array_item whose elements correspond to
/// the arguments provided to a bootstrap linker method.
///
/// The first three arguments are:
/// - A method handle representing the bootstrap linker method ([`EncodedValue::MethodHandle`])
/// - A method name that the bootstrap linker should resolve ([`EncodedValue::String`])
/// - A method type corresponding to the type of the method name to be resolved
/// ([`EncodedValue::MethodType`])
///
/// Any additional arguments are constant values passed to the bootstrap linker method.
/// These arguments are passed in order and without any type conversions.
///
///
pub type CallSiteItem = EncodedArrayItem;