diff --git a/androscalpel/src/apk.rs b/androscalpel/src/apk.rs index 9dde770..a48c39e 100644 --- a/androscalpel/src/apk.rs +++ b/androscalpel/src/apk.rs @@ -90,6 +90,26 @@ impl Apk { 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 { + let values = dex + .get_struct_at_offset::(class_item.static_values_off)? + .values; + if values.len() > static_fields.len() { + return Err(Error::InconsistantStruct(format!( + "Inconsistant static_values array found in {}: \ + |static_values| = {}, |static_fields| = {}, \ + |static_values| should be <= |static_fields|", + <&DexString as Into>::into(&name), + values.len(), + static_fields.len() + ))); + } + //for (i, value) in values.iter().enumerate() {} + for field in static_fields.iter_mut().skip(values.len()) { + field.value = None; + } + }*/ Ok(Class { name, superclass, @@ -118,7 +138,7 @@ impl Apk { idx += field.field_idx_diff.0; let id_item = dex.get_field_id(idx as usize)?; - // Check class_idx == class? ¯\_(ツ)/¯ at list it usefull for debug + // Check class_idx == class? ¯\_(ツ)/¯ at least it usefull for debug let class_ty = dex.get_type_id(id_item.class_idx as usize)?; let class: DexString = dex.get_string(class_ty.descriptor_idx)?.into(); let class: String = class.into(); @@ -158,6 +178,7 @@ impl Apk { is_transient, is_synthetic, is_enum, + value: None, }) } Ok(fields) diff --git a/androscalpel/src/field.rs b/androscalpel/src/field.rs index 612e393..b8dd7d6 100644 --- a/androscalpel/src/field.rs +++ b/androscalpel/src/field.rs @@ -1,5 +1,6 @@ //! Representation of the fields of a class. +use pyo3::exceptions::PyTypeError; use pyo3::prelude::*; use crate::DexString; @@ -36,6 +37,8 @@ pub struct Field { /// If the field is an enumerated value #[pyo3(get, set)] pub is_enum: bool, + /// The default value of this field + pub value: Option, } /// Represent the visibility of a field @@ -62,6 +65,7 @@ impl Field { is_transient: false, is_synthetic: false, is_enum: false, + value: None, } } @@ -101,4 +105,526 @@ impl Field { let ty: String = (&self.type_).into(); format!("Field({name}, {ty})") } + + /// Return the value as a python object + #[getter] + pub fn get_value(&self) -> Option { + self.value.clone() + } + + /// Set the value from a python object + #[setter] + pub fn set_value(&mut self, ob: &PyAny) -> PyResult<()> { + self.value = Some(ob.extract()?); + // TODO: check type match + Ok(()) + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexByte(pub i8); +#[pymethods] +impl DexByte { + #[new] + pub fn new(val: i8) -> Self { + Self(val) + } + + pub fn get_value(&self) -> i8 { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexByte({})", self.0) + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexShort(pub i16); +#[pymethods] +impl DexShort { + #[new] + pub fn new(val: i16) -> Self { + Self(val) + } + + pub fn get_value(&self) -> i16 { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexShort({})", self.0) + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexChar(pub u16); +#[pymethods] +impl DexChar { + #[new] + pub fn new(val: u16) -> Self { + Self(val) + } + + pub fn get_value(&self) -> u16 { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexChar({})", self.0) + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexInt(pub i32); +#[pymethods] +impl DexInt { + #[new] + pub fn new(val: i32) -> Self { + Self(val) + } + + pub fn get_value(&self) -> i32 { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexInt({})", self.0) + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexLong(pub i64); +#[pymethods] +impl DexLong { + #[new] + pub fn new(val: i64) -> Self { + Self(val) + } + + pub fn get_value(&self) -> i64 { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexLong({})", self.0) + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy)] +pub struct DexFloat(pub f32); +#[pymethods] +impl DexFloat { + #[new] + pub fn new(val: f32) -> Self { + Self(val) + } + + pub fn get_value(&self) -> f32 { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexFloat({})", self.0) + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy)] +pub struct DexDouble(pub f64); +#[pymethods] +impl DexDouble { + #[new] + pub fn new(val: f64) -> Self { + Self(val) + } + + pub fn get_value(&self) -> f64 { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexDouble({})", self.0) + } +} + +/* +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexMethodType(pub u32); +#[pymethods] +impl DexMethodType { + #[new] + pub fn new(val: u32) -> Self { + Self(val) + } + + pub fn get_value(&self) -> u32 { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexMethodType({})", self.0) + } +} +*/ + +/* +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexMethodHandle(pub u32); +#[pymethods] +impl DexMethodHandle { + #[new] + pub fn new(val: u32) -> Self { + Self(val) + } + + pub fn get_value(&self) -> u32 { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexMethodHandle({})", self.0) + } +} +*/ + +/* +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexString(pub u32); +#[pymethods] +impl DexString { + #[new] + pub fn new(val: u32) -> Self { + Self(val) + } + + pub fn get_value(&self) -> u32 { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexString({})", self.0) + } +} +*/ + +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexType(pub u32); +#[pymethods] +impl DexType { + #[new] + pub fn new(val: u32) -> Self { + Self(val) + } + + pub fn get_value(&self) -> u32 { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexType({})", self.0) + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexField(pub u32); +#[pymethods] +impl DexField { + #[new] + pub fn new(val: u32) -> Self { + Self(val) + } + + pub fn get_value(&self) -> u32 { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexField({})", self.0) + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexMethod(pub u32); +#[pymethods] +impl DexMethod { + #[new] + pub fn new(val: u32) -> Self { + Self(val) + } + + pub fn get_value(&self) -> u32 { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexMethod({})", self.0) + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexEnum(pub u32); +#[pymethods] +impl DexEnum { + #[new] + pub fn new(val: u32) -> Self { + Self(val) + } + + pub fn get_value(&self) -> u32 { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexEnum({})", self.0) + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexArray; +#[pymethods] +impl DexArray { + #[new] + pub fn _new() -> Self { + Self + } + + pub fn get_value(&self) { + todo!() + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + "DexArray".into() + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexAnnotation; +#[pymethods] +impl DexAnnotation { + #[new] + pub fn _new() -> Self { + Self + } + + pub fn get_value(&self) { + todo!() + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + "DexAnnotation".into() + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexNull; +#[pymethods] +impl DexNull { + #[new] + pub fn _new() -> Self { + Self + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + "DexNull".into() + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DexBoolean(pub bool); +#[pymethods] +impl DexBoolean { + #[new] + pub fn new(val: bool) -> Self { + Self(val) + } + + pub fn get_value(&self) -> bool { + self.0 + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + format!("DexBoolean({})", self.0) + } +} + +#[derive(Debug, Clone)] +pub enum DexValue { + Byte(DexByte), + Short(DexShort), + Char(DexChar), + Int(DexInt), + Long(DexLong), + Float(DexFloat), + Double(DexDouble), + //MethodType(DexMethodType), + //MethodHandle(DexMethodHandle), + String(DexString), + Type(DexType), + Field(DexField), + Method(DexMethod), + Enum(DexEnum), + Array(DexArray), + Annotation(DexAnnotation), + Null(DexNull), + Boolean(DexBoolean), +} + +impl<'source> FromPyObject<'source> for DexValue { + fn extract(ob: &'source PyAny) -> PyResult { + if let Ok(val) = DexByte::extract(ob) { + Ok(Self::Byte(val)) + } else if let Ok(val) = DexShort::extract(ob) { + Ok(Self::Short(val)) + } else if let Ok(val) = DexChar::extract(ob) { + Ok(Self::Char(val)) + } else if let Ok(val) = DexInt::extract(ob) { + Ok(Self::Int(val)) + } else if let Ok(val) = DexLong::extract(ob) { + Ok(Self::Long(val)) + } else if let Ok(val) = DexFloat::extract(ob) { + Ok(Self::Float(val)) + } else if let Ok(val) = DexDouble::extract(ob) { + Ok(Self::Double(val)) + } else if let Ok(val) = DexString::extract(ob) { + Ok(Self::String(val)) + } else if let Ok(val) = DexType::extract(ob) { + Ok(Self::Type(val)) + } else if let Ok(val) = DexField::extract(ob) { + Ok(Self::Field(val)) + } else if let Ok(val) = DexMethod::extract(ob) { + Ok(Self::Method(val)) + } else if let Ok(val) = DexEnum::extract(ob) { + Ok(Self::Enum(val)) + } else if let Ok(val) = DexArray::extract(ob) { + Ok(Self::Array(val)) + } else if let Ok(val) = DexAnnotation::extract(ob) { + Ok(Self::Annotation(val)) + } else if let Ok(val) = DexNull::extract(ob) { + 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) = DexMethodHandle::extract(ob) { Ok(Self::MethodHandle(val)) + } else { + Err(PyErr::new::(format!( + "{} is not a castable as a DexValue", + ob.repr()? + ))) + } + } +} + +impl IntoPy for DexValue { + fn into_py(self, py: Python<'_>) -> PyObject { + match self { + DexValue::Byte(val) => val.into_py(py), + DexValue::Short(val) => val.into_py(py), + DexValue::Char(val) => val.into_py(py), + DexValue::Int(val) => val.into_py(py), + DexValue::Long(val) => val.into_py(py), + DexValue::Float(val) => val.into_py(py), + DexValue::Double(val) => val.into_py(py), + //DexValue::MethodType(val) => val.into_py(py), + //DexValue::MethodHandle(val) => val.into_py(py), + DexValue::String(val) => val.into_py(py), + DexValue::Type(val) => val.into_py(py), + DexValue::Field(val) => val.into_py(py), + DexValue::Method(val) => val.into_py(py), + DexValue::Enum(val) => val.into_py(py), + DexValue::Array(val) => val.into_py(py), + DexValue::Annotation(val) => val.into_py(py), + DexValue::Null(val) => val.into_py(py), + DexValue::Boolean(val) => val.into_py(py), + } + } } diff --git a/androscalpel/src/lib.rs b/androscalpel/src/lib.rs index 048e5e8..da9f716 100644 --- a/androscalpel/src/lib.rs +++ b/androscalpel/src/lib.rs @@ -148,6 +148,24 @@ impl DexString { #[pymodule] fn androscalpel(_py: Python, m: &PyModule) -> PyResult<()> { pyo3_log::init(); + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + // m.add_class::()?; + // m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; m.add_class::()?; m.add_class::()?; m.add_class::()?;