some work on DexType and DexMethodType

This commit is contained in:
Jean-Marie Mineau 2023-09-04 16:36:15 +02:00
parent cc6ce1c625
commit 2ec3fe2c9d
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
4 changed files with 127 additions and 28 deletions

View file

@ -2,9 +2,13 @@
use log::info;
use pyo3::prelude::*;
use crate::{Class, DexString, Error, Field, FieldVisibility, Result};
use crate::*;
use androscalpel_serializer::*;
// Prioritize Results from this crate
use crate::Error;
use crate::Result;
/// Represent an apk.
#[pyclass]
#[derive(Debug, Clone)]
@ -87,8 +91,8 @@ impl Apk {
let data_off = class_item.class_data_off;
if data_off != 0 {
let data = dex.get_struct_at_offset::<ClassDataItem>(data_off)?;
static_fields = self.get_field_list_from_dex(&data.static_fields, dex)?;
instance_fields = self.get_field_list_from_dex(&data.instance_fields, dex)?;
static_fields = Self::get_field_list_from_dex(&data.static_fields, dex)?;
instance_fields = Self::get_field_list_from_dex(&data.instance_fields, dex)?;
}
if class_item.static_values_off != 0 {
@ -105,7 +109,9 @@ impl Apk {
static_fields.len()
)));
}
//for (i, value) in values.iter().enumerate() {}
for (i, value) in values.iter().enumerate() {
static_fields[i].value = Some(Self::encoded_value_to_dex_value(value, dex)?);
}
for field in static_fields.iter_mut().skip(values.len()) {
field.value = None;
}
@ -127,8 +133,64 @@ impl Apk {
})
}
fn get_field_list_from_dex(
&self,
pub fn encoded_value_to_dex_value(
encoded_value: &EncodedValue,
dex: &DexFileReader,
) -> Result<DexValue> {
match encoded_value {
EncodedValue::Byte(val) => Ok(DexValue::Byte(DexByte(*val))),
EncodedValue::Short(val) => Ok(DexValue::Short(DexShort(*val))),
EncodedValue::Char(val) => Ok(DexValue::Char(DexChar(*val))),
EncodedValue::Int(val) => Ok(DexValue::Int(DexInt(*val))),
EncodedValue::Long(val) => Ok(DexValue::Long(DexLong(*val))),
EncodedValue::Float(val) => Ok(DexValue::Float(DexFloat(*val))),
EncodedValue::Double(val) => Ok(DexValue::Double(DexDouble(*val))),
EncodedValue::MethodType(val) => {
let proto = dex.get_proto_id(*val as usize)?;
let shorty: DexString = dex.get_string(proto.shorty_idx)?.into();
let return_type: DexType = DexType(
dex.get_string(
dex.get_type_id(proto.return_type_idx as usize)?
.descriptor_idx,
)?
.into(),
);
let parameters = if proto.parameters_off == 0 {
vec![]
} else {
let type_list = dex.get_struct_at_offset::<TypeList>(proto.parameters_off)?;
let mut parameters: Vec<DexType> = vec![];
for ty in type_list.list {
parameters.push(DexType(
dex.get_string(dex.get_type_id(ty.type_idx as usize)?.descriptor_idx)?
.into(),
));
}
parameters
};
Ok(DexValue::MethodType(DexMethodType {
shorty,
return_type,
parameters,
}))
}
EncodedValue::MethodHandle(_val) => todo!(), //Ok(DexValue::MethodHandle(DexMethodHandle(*val))),
EncodedValue::String(val) => Ok(DexValue::String(dex.get_string(*val)?.into())),
EncodedValue::Type(val) => Ok(DexValue::Type(DexType(
dex.get_string(dex.get_type_id(*val as usize)?.descriptor_idx)?
.into(),
))),
EncodedValue::Field(val) => Ok(DexValue::Field(DexField(*val))),
EncodedValue::Method(val) => Ok(DexValue::Method(DexMethod(*val))),
EncodedValue::Enum(val) => Ok(DexValue::Enum(DexEnum(*val))),
EncodedValue::Array(_val) => todo!(), //Ok(DexValue::Array(DexArray(*val))),
EncodedValue::Annotation(_val) => todo!(), //Ok(DexValue::Annotation(DexAnnotation(*val))),
EncodedValue::Null => Ok(DexValue::Null(DexNull)),
EncodedValue::Boolean(val) => Ok(DexValue::Boolean(DexBoolean(*val))),
}
}
pub fn get_field_list_from_dex(
encoded_fields: &[EncodedField],
dex: &DexFileReader,
) -> Result<Vec<Field>> {

View file

@ -282,19 +282,27 @@ impl DexDouble {
}
}
/*
#[pyclass]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DexMethodType(pub u32);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DexMethodType {
/// Type formated as described by <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
shorty: DexString,
return_type: DexType,
parameters: Vec<DexType>,
}
#[pymethods]
/// The type of a method. The shorty is formated as described in
/// <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
impl DexMethodType {
#[new]
pub fn new(val: u32) -> Self {
Self(val)
pub fn new(return_type: DexType, parameters: Vec<DexType>) -> Self {
// TODO: check format
Self {
shorty: Self::get_shorty(&return_type, &parameters),
return_type,
parameters,
}
pub fn get_value(&self) -> u32 {
self.0
}
pub fn __str__(&self) -> String {
@ -302,10 +310,16 @@ impl DexMethodType {
}
pub fn __repr__(&self) -> String {
format!("DexMethodType({})", self.0)
let repr: String = (&self.shorty).into();
format!("DexMethodType({repr})")
}
}
impl DexMethodType {
pub fn get_shorty(return_type: &DexType, parameters: &[DexType]) -> DexString {
todo!()
}
}
*/
/*
#[pyclass]
@ -357,26 +371,31 @@ impl DexString {
}
*/
/// A type.
/// Type a represented by [`DexString`] that follow the TypeDescriptor format
/// as described here <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
#[pyclass]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DexType(pub u32);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DexType(pub(crate) DexString);
#[pymethods]
impl DexType {
#[new]
pub fn new(val: u32) -> Self {
Self(val)
pub fn _new(ty: DexString) -> Self {
// TODO: check format
Self(ty)
}
pub fn get_value(&self) -> u32 {
pub fn get_name(&self) -> DexString {
self.0
}
pub fn __str__(&self) -> String {
self.__repr__()
self.0.into()
}
pub fn __repr__(&self) -> String {
format!("DexType({})", self.0)
let name: String = self.0.into();
format!("DexType({name})")
}
}
@ -546,7 +565,7 @@ pub enum DexValue {
Long(DexLong),
Float(DexFloat),
Double(DexDouble),
//MethodType(DexMethodType),
MethodType(DexMethodType),
//MethodHandle(DexMethodHandle),
String(DexString),
Type(DexType),
@ -593,7 +612,8 @@ impl<'source> FromPyObject<'source> for DexValue {
Ok(Self::Null(val))
} else if let Ok(val) = DexBoolean::extract(ob) {
Ok(Self::Boolean(val))
// } else if let Ok(val) = DexMethodType::extract(ob) { Ok(Self::MethodType(val))
} else if let Ok(val) = DexMethodType::extract(ob) {
Ok(Self::MethodType(val))
// } else if let Ok(val) = DexMethodHandle::extract(ob) { Ok(Self::MethodHandle(val))
} else {
Err(PyErr::new::<PyTypeError, _>(format!(

View file

@ -143,7 +143,7 @@ impl<'a> DexFileReader<'a> {
})
}
/// Return a [`&TypeIdItem`] from its idx.
/// Return a [`TypeIdItem`] reference from its idx.
pub fn get_type_id(&self, idx: usize) -> Result<&TypeIdItem> {
self.type_ids
.get(idx)
@ -154,7 +154,7 @@ impl<'a> DexFileReader<'a> {
)))
}
/// Return a [`&FieldIdItem`] from its idx.
/// Return a [`FieldIdItem`] reference from its idx.
pub fn get_field_id(&self, idx: usize) -> Result<&FieldIdItem> {
self.field_ids
.get(idx)
@ -164,6 +164,16 @@ impl<'a> DexFileReader<'a> {
)))
}
/// Return a [`ProtoIdItem`] reference from its idx.
pub fn get_proto_id(&self, idx: usize) -> Result<&ProtoIdItem> {
self.proto_ids
.get(idx)
.ok_or(Error::InconsistantStruct(format!(
"prototype idx {idx} is out of bound (|proto_ids|={})",
self.proto_ids.len()
)))
}
fn sanity_check(&self) -> Result<()> {
if self.header.magic.version != [0x30, 0x33, 0x39] {
warn!(

View file

@ -14,12 +14,19 @@ pub enum EncodedValue {
Long(i64),
Float(f32),
Double(f64),
/// Index of a [`crate::ProtoIdItem`] in `proto_ids`
MethodType(u32),
/// Index of a [`crate::MethodHandleItem`] in `method_handles`
MethodHandle(u32),
/// Index of a [`crate::StringIdItem`] in `string_ids`
String(u32),
/// Index of a [`crate::TypeIdItem`] in `type_ids`
Type(u32),
/// Index of a [`crate::FieldIdItem`] in `field_ids`
Field(u32),
/// Index of a [`crate::MethodIdItem`] in `method_ids`
Method(u32),
/// Index of a [`crate::FieldIdItem`] in `field_ids` representing an enum.
Enum(u32),
Array(EncodedArray),
Annotation(EncodedAnnotation),