factorize value parsing

This commit is contained in:
Jean-Marie Mineau 2023-10-02 16:58:33 +02:00
parent cdf68c506a
commit 77be653786
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
4 changed files with 123 additions and 67 deletions

View file

@ -133,6 +133,72 @@ impl Apk {
}) })
} }
/// Return a [`IdType`] from its idx.
pub fn get_id_type_from_idx(idx: usize, dex: &DexFileReader) -> Result<IdType> {
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<IdMethodType> {
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<IdType> = if proto.parameters_off == 0 {
vec![]
} else {
dex.get_struct_at_offset::<TypeList>(proto.parameters_off)?
.list
.iter()
.map(|ty| Self::get_id_type_from_idx(ty.type_idx as usize, dex).clone())
.collect::<Result<_>>()?
};
Ok(IdMethodType {
shorty,
return_type,
parameters,
})
}
/// Return a [`IdField`] from its idx.
pub fn get_id_field_from_idx(idx: usize, dex: &DexFileReader) -> Result<IdField> {
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<IdMethod> {
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( pub fn encoded_value_to_dex_value(
encoded_value: &EncodedValue, encoded_value: &EncodedValue,
dex: &DexFileReader, dex: &DexFileReader,
@ -145,60 +211,24 @@ impl Apk {
EncodedValue::Long(val) => Ok(DexValue::Long(DexLong(*val))), EncodedValue::Long(val) => Ok(DexValue::Long(DexLong(*val))),
EncodedValue::Float(val) => Ok(DexValue::Float(DexFloat(*val))), EncodedValue::Float(val) => Ok(DexValue::Float(DexFloat(*val))),
EncodedValue::Double(val) => Ok(DexValue::Double(DexDouble(*val))), EncodedValue::Double(val) => Ok(DexValue::Double(DexDouble(*val))),
EncodedValue::MethodType(val) => { EncodedValue::MethodType(val) => Ok(DexValue::MethodType(
let proto = dex.get_proto_id(*val as usize)?; Self::get_id_method_type_from_idx(*val as usize, dex)?,
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::<TypeList>(proto.parameters_off)?;
let mut parameters: Vec<IdType> = 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,
}))
}
// TODO: need method to be implemented first // TODO: need method to be implemented first
EncodedValue::MethodHandle(_val) => todo!(), //Ok(DexValue::MethodHandle(DexMethodHandle(*val))), EncodedValue::MethodHandle(_val) => todo!(), //Ok(DexValue::MethodHandle(DexMethodHandle(*val))),
EncodedValue::String(val) => Ok(DexValue::String(dex.get_string(*val)?.into())), EncodedValue::String(val) => Ok(DexValue::String(dex.get_string(*val)?.into())),
EncodedValue::Type(val) => Ok(DexValue::Type(IdType( EncodedValue::Type(val) => Ok(DexValue::Type(Self::get_id_type_from_idx(
dex.get_string(dex.get_type_id(*val as usize)?.descriptor_idx)? *val as usize,
.into(), dex,
))), )?)),
EncodedValue::Field(val) => { EncodedValue::Field(val) => Ok(DexValue::Field(Self::get_id_field_from_idx(
let field = dex.get_field_id(*val as usize)?; *val as usize,
let name = dex.get_string(field.name_idx)?.into(); dex,
let type_ = IdType( )?)),
dex.get_string(dex.get_type_id(field.type_idx as usize)?.descriptor_idx)? EncodedValue::Method(val) => Ok(DexValue::Method(Self::get_id_method_from_idx(
.into(), *val as usize,
); dex,
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::Enum(val) => Ok(DexValue::Enum(IdEnum(*val))), EncodedValue::Enum(val) => Ok(DexValue::Enum(IdEnum(*val))),
EncodedValue::Array(_val) => todo!(), //Ok(DexValue::Array(DexArray(*val))), EncodedValue::Array(_val) => todo!(), //Ok(DexValue::Array(DexArray(*val))),
EncodedValue::Annotation(_val) => todo!(), //Ok(DexValue::Annotation(DexAnnotation(*val))), EncodedValue::Annotation(_val) => todo!(), //Ok(DexValue::Annotation(DexAnnotation(*val))),

View file

@ -369,25 +369,41 @@ impl IdField {
} }
#[pyclass] #[pyclass]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct IdMethod(pub u32); pub struct IdMethod {
pub class_: IdType,
pub proto: IdMethodType,
pub name: DexString,
}
#[pymethods] #[pymethods]
impl IdMethod { impl IdMethod {
#[new] #[new]
pub fn new(val: u32) -> Self { pub fn new(class_: IdType, proto: IdMethodType, name: DexString) -> Self {
Self(val) Self {
} class_,
proto,
pub fn get_value(&self) -> u32 { name,
self.0 }
} }
pub fn __str__(&self) -> String { pub fn __str__(&self) -> String {
self.__repr__() format!(
"{}.{}({}){}",
self.class_.__str__(),
self.name.__str__(),
self.proto
.parameters
.iter()
.map(|param| param.__str__())
.collect::<Vec<String>>()
.join(", "),
self.proto.return_type.__str__()
)
} }
pub fn __repr__(&self) -> String { pub fn __repr__(&self) -> String {
format!("DexMethod({})", self.0) format!("DexMethod({})", self.__str__())
} }
} }

View file

@ -16,7 +16,7 @@ pub use field::*;
pub use scalar::*; pub use scalar::*;
pub use value::*; pub use value::*;
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum Error { pub enum Error {
InputTooSmall(String), InputTooSmall(String),
SerializationError(String), SerializationError(String),

View file

@ -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. /// Return a [`FieldIdItem`] reference from its idx.
pub fn get_field_id(&self, idx: usize) -> Result<&FieldIdItem> { pub fn get_field_id(&self, idx: usize) -> Result<&FieldIdItem> {
self.field_ids self.field_ids
@ -164,13 +174,13 @@ impl<'a> DexFileReader<'a> {
))) )))
} }
/// Return a [`ProtoIdItem`] reference from its idx. /// Return a [`MethodIdItem`] reference from its idx.
pub fn get_proto_id(&self, idx: usize) -> Result<&ProtoIdItem> { pub fn get_method_id(&self, idx: usize) -> Result<&MethodIdItem> {
self.proto_ids self.method_ids
.get(idx) .get(idx)
.ok_or(Error::InconsistantStruct(format!( .ok_or(Error::InconsistantStruct(format!(
"prototype idx {idx} is out of bound (|proto_ids|={})", "method idx {idx} is out of bound (|method_ids|={})",
self.proto_ids.len() self.method_ids.len()
))) )))
} }