From b2c4da413ce1bb3ab8017011db992880423f6aef Mon Sep 17 00:00:00 2001 From: Jean-Marie Mineau Date: Mon, 2 Oct 2023 13:23:09 +0200 Subject: [PATCH] refactor values repr --- androscalpel/src/dex_id.rs | 371 +++++++++++++++++++ androscalpel/src/field.rs | 718 +------------------------------------ androscalpel/src/lib.rs | 16 +- androscalpel/src/scalar.rs | 256 +++++++++++++ androscalpel/src/value.rs | 99 +++++ 5 files changed, 740 insertions(+), 720 deletions(-) create mode 100644 androscalpel/src/dex_id.rs create mode 100644 androscalpel/src/scalar.rs create mode 100644 androscalpel/src/value.rs diff --git a/androscalpel/src/dex_id.rs b/androscalpel/src/dex_id.rs new file mode 100644 index 0000000..a88db4d --- /dev/null +++ b/androscalpel/src/dex_id.rs @@ -0,0 +1,371 @@ +//! The class identifying dex structure. + +use pyo3::prelude::*; + +use crate::DexString; +use androscalpel_serializer::{StringDataItem, Uleb128}; + +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IdMethodType { + /// Type formated as described by + pub(crate) shorty: DexString, + pub(crate) return_type: IdType, + pub(crate) parameters: Vec, +} + +#[pymethods] +/// The type of a method. The shorty is formated as described in +/// +impl IdMethodType { + #[new] + pub fn new(return_type: IdType, parameters: Vec) -> Self { + // TODO: check format + Self { + shorty: Self::get_shorty(&return_type, ¶meters), + return_type, + parameters, + } + } + + pub fn __str__(&self) -> String { + self.__repr__() + } + + pub fn __repr__(&self) -> String { + let repr: String = (&self.shorty).into(); + format!("DexMethodType({repr})") + } +} + +impl IdMethodType { + /// Compute the format for the shorty as described in + /// + pub fn get_shorty(return_type: &IdType, parameters: &[IdType]) -> DexString { + todo!() + } +} + +/* +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct IdMethodHandle(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) + } +} +*/ + +/// A type. +/// Type represented by [`DexString`] that follow the TypeDescriptor format +/// as described here +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IdType(pub(crate) DexString); +#[pymethods] +impl IdType { + #[new] + pub fn _new(ty: DexString) -> Self { + // TODO: check format + Self(ty) + } + + /// Return the void type (for return type) + #[staticmethod] + pub fn void() -> Self { + Self("V".into()) + } + + /// Return the boolean type + #[staticmethod] + pub fn boolean() -> Self { + Self("Z".into()) + } + /// Return the byte type + #[staticmethod] + pub fn byte() -> Self { + Self("B".into()) + } + + /// Return the short type + #[staticmethod] + pub fn short() -> Self { + Self("S".into()) + } + + /// Return the char type + #[staticmethod] + pub fn char() -> Self { + Self("C".into()) + } + + /// Return the int type + #[staticmethod] + pub fn int() -> Self { + Self("I".into()) + } + + /// Return the long type + #[staticmethod] + pub fn long() -> Self { + Self("J".into()) + } + + /// Return the float type + #[staticmethod] + pub fn float() -> Self { + Self("F".into()) + } + + /// Return the double type + #[staticmethod] + pub fn double() -> Self { + Self("D".into()) + } + + /// Return the type for the class of fully qualified name `name` + #[staticmethod] + pub fn class(name: &str) -> Self { + Self(format!("L{name}").into()) + } + + /// Return the type for an array of the specify `type_` + #[staticmethod] + pub fn array(type_: &IdType) -> Self { + let mut ty = type_.clone(); + ty.0 .0.utf16_size.0 += 1; + ty.0 .0.data.insert(0, 0x5b); + ty + } + + pub fn get_name(&self) -> DexString { + self.0.clone() + } + + pub fn __str__(&self) -> String { + (&self.0).into() + } + + pub fn __repr__(&self) -> String { + let name: String = (&self.0).into(); + format!("DexType({name})") + } + + /// Check if the type is void (return type) + pub fn is_void(&self) -> bool { + self == &Self::void() + } + + /// Check if the type is boolean + pub fn is_boolean(&self) -> bool { + self == &Self::boolean() + } + + /// Check if the type is byte + pub fn is_byte(&self) -> bool { + self == &Self::byte() + } + + /// Check if the type is short + pub fn is_short(&self) -> bool { + self == &Self::short() + } + + /// Check if the type is char + pub fn is_char(&self) -> bool { + self == &Self::char() + } + + /// Check if the type is int + pub fn is_int(&self) -> bool { + self == &Self::int() + } + + /// Check if the type is long + pub fn is_long(&self) -> bool { + self == &Self::long() + } + + /// Check if the type is float + pub fn is_float(&self) -> bool { + self == &Self::float() + } + + /// Check if the type is double + pub fn is_double(&self) -> bool { + self == &Self::double() + } + + /// Check if the type is a class + pub fn is_class(&self) -> bool { + self.0.get_utf16_size() == 0 + && self.0.get_bytes().is_empty() + && self.0.get_bytes()[0] != 0x76 + // Check if first char is an L + } + + /// Check if the type is an array + pub fn is_array(&self) -> bool { + self.0.get_utf16_size() == 0 + && self.0.get_bytes().is_empty() + && self.0.get_bytes()[0] != 0x5b + // Check if first char is an [ + } + + /// If the type is a class, return the name of the class, + /// else None. + pub fn get_class_name(&self) -> Option { + if self.is_class() { + Some( + StringDataItem { + utf16_size: Uleb128(self.0.get_utf16_size() - 1), + data: self.0.get_bytes()[1..].to_vec(), + } + .into(), + ) + } else { + None + } + } + + /// If the type is a array, return the type of the elements, + /// else None. + pub fn get_element_type(&self) -> Option { + if self.is_array() { + Some(Self( + StringDataItem { + utf16_size: Uleb128(self.0.get_utf16_size() - 1), + data: self.0.get_bytes()[1..].to_vec(), + } + .into(), + )) + } else { + None + } + } + + // TODO: TESTS +} + +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IdField { + /// The name of the field, format described at + /// + #[pyo3(get, set)] + pub name: DexString, + /// The type of the field. + #[pyo3(get, set)] + pub type_: IdType, + /// The class that own the field. + #[pyo3(get, set)] + pub class_: IdType, +} + +#[pymethods] +impl IdField { + #[new] + pub fn new(name: DexString, type_: IdType, class_: IdType) -> Self { + Self { + name, + type_, + class_, + } + } + + pub fn __str__(&self) -> String { + let class: String = self.class_.get_name().into(); + let name: String = (&self.name).into(); + format!("{class}.{name}") + } + + pub fn __repr__(&self) -> String { + let class: String = self.class_.get_name().into(); + let name: String = (&self.name).into(); + format!("IdField({class}.{name})") + } +} + +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct IdMethod(pub u32); +#[pymethods] +impl IdMethod { + #[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 IdEnum(pub u32); +#[pymethods] +impl IdEnum { + #[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 IdAnnotation; +#[pymethods] +impl IdAnnotation { + #[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() + } +} diff --git a/androscalpel/src/field.rs b/androscalpel/src/field.rs index 29c8cc7..4f1ff52 100644 --- a/androscalpel/src/field.rs +++ b/androscalpel/src/field.rs @@ -1,10 +1,8 @@ //! Representation of the fields of a class. -use pyo3::exceptions::PyTypeError; use pyo3::prelude::*; -use crate::DexString; -use androscalpel_serializer::{StringDataItem, Uleb128}; +use crate::{DexValue, IdField}; /// Represent a field. #[pyclass] @@ -12,7 +10,7 @@ use androscalpel_serializer::{StringDataItem, Uleb128}; pub struct Field { /// The structure used to reference this field. #[pyo3(get, set)] - pub descriptor: DexField, + pub descriptor: IdField, /// The field visibility #[pyo3(get, set)] pub visibility: FieldVisibility, @@ -51,7 +49,7 @@ pub enum FieldVisibility { #[pymethods] impl Field { #[new] - pub fn new(descriptor: DexField) -> Self { + pub fn new(descriptor: IdField) -> Self { Self { descriptor, visibility: FieldVisibility::Public, @@ -116,713 +114,3 @@ impl Field { 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, PartialEq, Eq)] -pub struct DexMethodType { - /// Type formated as described by - pub(crate) shorty: DexString, - pub(crate) return_type: DexType, - pub(crate) parameters: Vec, -} - -#[pymethods] -/// The type of a method. The shorty is formated as described in -/// -impl DexMethodType { - #[new] - pub fn new(return_type: DexType, parameters: Vec) -> Self { - // TODO: check format - Self { - shorty: Self::get_shorty(&return_type, ¶meters), - return_type, - parameters, - } - } - - pub fn __str__(&self) -> String { - self.__repr__() - } - - pub fn __repr__(&self) -> String { - let repr: String = (&self.shorty).into(); - format!("DexMethodType({repr})") - } -} - -impl DexMethodType { - /// Compute the format for the shorty as described in - /// - pub fn get_shorty(return_type: &DexType, parameters: &[DexType]) -> DexString { - todo!() - } -} - -/* -#[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) - } -} -*/ - -/// A type. -/// Type a represented by [`DexString`] that follow the TypeDescriptor format -/// as described here -#[pyclass] -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct DexType(pub(crate) DexString); -#[pymethods] -impl DexType { - #[new] - pub fn _new(ty: DexString) -> Self { - // TODO: check format - Self(ty) - } - - /// Return the void type (for return type) - #[staticmethod] - pub fn void() -> Self { - Self("V".into()) - } - - /// Return the boolean type - #[staticmethod] - pub fn boolean() -> Self { - Self("Z".into()) - } - /// Return the byte type - #[staticmethod] - pub fn byte() -> Self { - Self("B".into()) - } - - /// Return the short type - #[staticmethod] - pub fn short() -> Self { - Self("S".into()) - } - - /// Return the char type - #[staticmethod] - pub fn char() -> Self { - Self("C".into()) - } - - /// Return the int type - #[staticmethod] - pub fn int() -> Self { - Self("I".into()) - } - - /// Return the long type - #[staticmethod] - pub fn long() -> Self { - Self("J".into()) - } - - /// Return the float type - #[staticmethod] - pub fn float() -> Self { - Self("F".into()) - } - - /// Return the double type - #[staticmethod] - pub fn double() -> Self { - Self("D".into()) - } - - /// Return the type for the class of fully qualified name `name` - #[staticmethod] - pub fn class(name: &str) -> Self { - Self(format!("L{name}").into()) - } - - /// Return the type for an array of the specify `type_` - #[staticmethod] - pub fn array(type_: &DexType) -> Self { - let mut ty = type_.clone(); - ty.0 .0.utf16_size.0 += 1; - ty.0 .0.data.insert(0, 0x5b); - ty - } - - pub fn get_name(&self) -> DexString { - self.0.clone() - } - - pub fn __str__(&self) -> String { - (&self.0).into() - } - - pub fn __repr__(&self) -> String { - let name: String = (&self.0).into(); - format!("DexType({name})") - } - - /// Check if the type is void (return type) - pub fn is_void(&self) -> bool { - self == &Self::void() - } - - /// Check if the type is boolean - pub fn is_boolean(&self) -> bool { - self == &Self::boolean() - } - - /// Check if the type is byte - pub fn is_byte(&self) -> bool { - self == &Self::byte() - } - - /// Check if the type is short - pub fn is_short(&self) -> bool { - self == &Self::short() - } - - /// Check if the type is char - pub fn is_char(&self) -> bool { - self == &Self::char() - } - - /// Check if the type is int - pub fn is_int(&self) -> bool { - self == &Self::int() - } - - /// Check if the type is long - pub fn is_long(&self) -> bool { - self == &Self::long() - } - - /// Check if the type is float - pub fn is_float(&self) -> bool { - self == &Self::float() - } - - /// Check if the type is double - pub fn is_double(&self) -> bool { - self == &Self::double() - } - - /// Check if the type is a class - pub fn is_class(&self) -> bool { - self.0.get_utf16_size() == 0 - && self.0.get_bytes().is_empty() - && self.0.get_bytes()[0] != 0x76 - // Check if first char is an L - } - - /// Check if the type is an array - pub fn is_array(&self) -> bool { - self.0.get_utf16_size() == 0 - && self.0.get_bytes().is_empty() - && self.0.get_bytes()[0] != 0x5b - // Check if first char is an [ - } - - /// If the type is a class, return the name of the class, - /// else None. - pub fn get_class_name(&self) -> Option { - if self.is_class() { - Some( - StringDataItem { - utf16_size: Uleb128(self.0.get_utf16_size() - 1), - data: self.0.get_bytes()[1..].to_vec(), - } - .into(), - ) - } else { - None - } - } - - /// If the type is a array, return the type of the elements, - /// else None. - pub fn get_element_type(&self) -> Option { - if self.is_array() { - Some(Self( - StringDataItem { - utf16_size: Uleb128(self.0.get_utf16_size() - 1), - data: self.0.get_bytes()[1..].to_vec(), - } - .into(), - )) - } else { - None - } - } - - // TODO: TESTS - // TODO: move to another mod -} - -#[pyclass] -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct DexField { - /// The name of the field, format described at - /// - #[pyo3(get, set)] - pub name: DexString, - /// The type of the field. - #[pyo3(get, set)] - pub type_: DexType, - /// The class that own the field. - #[pyo3(get, set)] - pub class_: DexType, -} - -#[pymethods] -impl DexField { - #[new] - pub fn new(name: DexString, type_: DexType, class_: DexType) -> Self { - Self { - name, - type_, - class_, - } - } - - pub fn __str__(&self) -> String { - let class: String = self.class_.get_name().into(); - let name: String = (&self.name).into(); - format!("{class}.{name}") - } - - pub fn __repr__(&self) -> String { - let class: String = self.class_.get_name().into(); - let name: String = (&self.name).into(); - format!("DexField({class}.{name})") - } -} - -#[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 da9f716..fdba144 100644 --- a/androscalpel/src/lib.rs +++ b/androscalpel/src/lib.rs @@ -4,11 +4,17 @@ use pyo3::prelude::*; pub mod apk; pub mod class; +pub mod dex_id; pub mod field; +pub mod scalar; +pub mod value; pub use apk::*; pub use class::*; +pub use dex_id::*; pub use field::*; +pub use scalar::*; +pub use value::*; #[derive(Debug)] pub enum Error { @@ -158,12 +164,12 @@ fn androscalpel(_py: Python, m: &PyModule) -> PyResult<()> { // 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::()?; diff --git a/androscalpel/src/scalar.rs b/androscalpel/src/scalar.rs new file mode 100644 index 0000000..35a7837 --- /dev/null +++ b/androscalpel/src/scalar.rs @@ -0,0 +1,256 @@ +//! The class identifying dex structure. + +use pyo3::prelude::*; + +// TODO: move DexString here + +#[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) + } +} + +/* DexString is already define in lib.rs, TODO: move the version in lib.rs here +#[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 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) + } +} + +#[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() + } +} diff --git a/androscalpel/src/value.rs b/androscalpel/src/value.rs new file mode 100644 index 0000000..adfeec9 --- /dev/null +++ b/androscalpel/src/value.rs @@ -0,0 +1,99 @@ +//! The class identifying dex structure. + +use pyo3::exceptions::PyTypeError; +use pyo3::prelude::*; + +use crate::{dex_id::*, scalar::*, DexString}; + +#[derive(Debug, Clone)] +pub enum DexValue { + Byte(DexByte), + Short(DexShort), + Char(DexChar), + Int(DexInt), + Long(DexLong), + Float(DexFloat), + Double(DexDouble), + MethodType(IdMethodType), + //MethodHandle(DexMethodHandle), + String(DexString), + Type(IdType), + Field(IdField), + Method(IdMethod), + Enum(IdEnum), + Array(DexArray), + Annotation(IdAnnotation), + 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) = IdType::extract(ob) { + Ok(Self::Type(val)) + } else if let Ok(val) = IdField::extract(ob) { + Ok(Self::Field(val)) + } else if let Ok(val) = IdMethod::extract(ob) { + Ok(Self::Method(val)) + } else if let Ok(val) = IdEnum::extract(ob) { + Ok(Self::Enum(val)) + } else if let Ok(val) = DexArray::extract(ob) { + Ok(Self::Array(val)) + } else if let Ok(val) = IdAnnotation::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) = IdMethodType::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), + } + } +}