diff --git a/androscalpel/src/apk.rs b/androscalpel/src/apk.rs index 9c73c1a..fde40ba 100644 --- a/androscalpel/src/apk.rs +++ b/androscalpel/src/apk.rs @@ -133,6 +133,72 @@ impl Apk { }) } + /// Return a [`IdType`] from its idx. + pub fn get_id_type_from_idx(idx: usize, dex: &DexFileReader) -> Result { + Ok(IdType( + dex.get_string(dex.get_type_id(idx)?.descriptor_idx)?.into(), + )) + } + + /// Return a [`IdMethodType`] from its idx. + pub fn get_id_method_type_from_idx(idx: usize, dex: &DexFileReader) -> Result { + let proto = dex.get_proto_id(idx)?; + let shorty: DexString = dex.get_string(proto.shorty_idx)?.into(); + let return_type: IdType = Self::get_id_type_from_idx(proto.return_type_idx as usize, dex)?; + let parameters: Vec = if proto.parameters_off == 0 { + vec![] + } else { + dex.get_struct_at_offset::(proto.parameters_off)? + .list + .iter() + .map(|ty| Self::get_id_type_from_idx(ty.type_idx as usize, dex).clone()) + .collect::>()? + }; + Ok(IdMethodType { + shorty, + return_type, + parameters, + }) + } + + /// Return a [`IdField`] from its idx. + pub fn get_id_field_from_idx(idx: usize, dex: &DexFileReader) -> Result { + let field = dex.get_field_id(idx)?; + let name = dex.get_string(field.name_idx)?.into(); + let type_ = IdType( + dex.get_string(dex.get_type_id(field.type_idx as usize)?.descriptor_idx)? + .into(), + ); + let class_ = IdType( + dex.get_string(dex.get_type_id(field.class_idx as usize)?.descriptor_idx)? + .into(), + ); + Ok(IdField { + name, + type_, + class_, + }) + } + + /// Return a [`IdMethod`] from its idx. + pub fn get_id_method_from_idx(idx: usize, dex: &DexFileReader) -> Result { + let method_id = dex.get_method_id(idx)?; + let class_ = IdType( + dex.get_string( + dex.get_type_id(method_id.class_idx as usize)? + .descriptor_idx, + )? + .into(), + ); + let proto = Self::get_id_method_type_from_idx(method_id.proto_idx as usize, dex)?; + let name = dex.get_string(method_id.name_idx)?.into(); + Ok(IdMethod { + class_, + proto, + name, + }) + } + pub fn encoded_value_to_dex_value( encoded_value: &EncodedValue, dex: &DexFileReader, @@ -145,60 +211,24 @@ impl Apk { 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: IdType = IdType( - 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::(proto.parameters_off)?; - let mut parameters: Vec = vec![]; - for ty in type_list.list { - parameters.push(IdType( - dex.get_string(dex.get_type_id(ty.type_idx as usize)?.descriptor_idx)? - .into(), - )); - } - parameters - }; - Ok(DexValue::MethodType(IdMethodType { - shorty, - return_type, - parameters, - })) - } + EncodedValue::MethodType(val) => Ok(DexValue::MethodType( + Self::get_id_method_type_from_idx(*val as usize, dex)?, + )), // TODO: need method to be implemented first 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(IdType( - dex.get_string(dex.get_type_id(*val as usize)?.descriptor_idx)? - .into(), - ))), - EncodedValue::Field(val) => { - let field = dex.get_field_id(*val as usize)?; - let name = dex.get_string(field.name_idx)?.into(); - let type_ = IdType( - dex.get_string(dex.get_type_id(field.type_idx as usize)?.descriptor_idx)? - .into(), - ); - let class_ = IdType( - dex.get_string(dex.get_type_id(field.class_idx as usize)?.descriptor_idx)? - .into(), - ); - Ok(DexValue::Field(IdField { - name, - type_, - class_, - })) - } - EncodedValue::Method(val) => Ok(DexValue::Method(IdMethod(*val))), + EncodedValue::Type(val) => Ok(DexValue::Type(Self::get_id_type_from_idx( + *val as usize, + dex, + )?)), + EncodedValue::Field(val) => Ok(DexValue::Field(Self::get_id_field_from_idx( + *val as usize, + dex, + )?)), + EncodedValue::Method(val) => Ok(DexValue::Method(Self::get_id_method_from_idx( + *val as usize, + dex, + )?)), EncodedValue::Enum(val) => Ok(DexValue::Enum(IdEnum(*val))), EncodedValue::Array(_val) => todo!(), //Ok(DexValue::Array(DexArray(*val))), EncodedValue::Annotation(_val) => todo!(), //Ok(DexValue::Annotation(DexAnnotation(*val))), diff --git a/androscalpel/src/dex_id.rs b/androscalpel/src/dex_id.rs index 5d26aaf..7a964e6 100644 --- a/androscalpel/src/dex_id.rs +++ b/androscalpel/src/dex_id.rs @@ -369,25 +369,41 @@ impl IdField { } #[pyclass] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct IdMethod(pub u32); +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IdMethod { + pub class_: IdType, + pub proto: IdMethodType, + pub name: DexString, +} + #[pymethods] impl IdMethod { #[new] - pub fn new(val: u32) -> Self { - Self(val) - } - - pub fn get_value(&self) -> u32 { - self.0 + pub fn new(class_: IdType, proto: IdMethodType, name: DexString) -> Self { + Self { + class_, + proto, + name, + } } pub fn __str__(&self) -> String { - self.__repr__() + format!( + "{}.{}({}){}", + self.class_.__str__(), + self.name.__str__(), + self.proto + .parameters + .iter() + .map(|param| param.__str__()) + .collect::>() + .join(", "), + self.proto.return_type.__str__() + ) } pub fn __repr__(&self) -> String { - format!("DexMethod({})", self.0) + format!("DexMethod({})", self.__str__()) } } diff --git a/androscalpel/src/lib.rs b/androscalpel/src/lib.rs index fdba144..c7db25f 100644 --- a/androscalpel/src/lib.rs +++ b/androscalpel/src/lib.rs @@ -16,7 +16,7 @@ pub use field::*; pub use scalar::*; pub use value::*; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Error { InputTooSmall(String), SerializationError(String), diff --git a/androscalpel_serializer/src/file_reader.rs b/androscalpel_serializer/src/file_reader.rs index 548aac2..96c1c5c 100644 --- a/androscalpel_serializer/src/file_reader.rs +++ b/androscalpel_serializer/src/file_reader.rs @@ -154,6 +154,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() + ))) + } + /// Return a [`FieldIdItem`] reference from its idx. pub fn get_field_id(&self, idx: usize) -> Result<&FieldIdItem> { self.field_ids @@ -164,13 +174,13 @@ impl<'a> DexFileReader<'a> { ))) } - /// Return a [`ProtoIdItem`] reference from its idx. - pub fn get_proto_id(&self, idx: usize) -> Result<&ProtoIdItem> { - self.proto_ids + /// Return a [`MethodIdItem`] reference from its idx. + pub fn get_method_id(&self, idx: usize) -> Result<&MethodIdItem> { + self.method_ids .get(idx) .ok_or(Error::InconsistantStruct(format!( - "prototype idx {idx} is out of bound (|proto_ids|={})", - self.proto_ids.len() + "method idx {idx} is out of bound (|method_ids|={})", + self.method_ids.len() ))) }