refactor values repr

This commit is contained in:
Jean-Marie Mineau 2023-10-02 13:23:09 +02:00
parent 1bf328d44e
commit b2c4da413c
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
5 changed files with 740 additions and 720 deletions

371
androscalpel/src/dex_id.rs Normal file
View file

@ -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 <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
pub(crate) shorty: DexString,
pub(crate) return_type: IdType,
pub(crate) parameters: Vec<IdType>,
}
#[pymethods]
/// The type of a method. The shorty is formated as described in
/// <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
impl IdMethodType {
#[new]
pub fn new(return_type: IdType, parameters: Vec<IdType>) -> Self {
// TODO: check format
Self {
shorty: Self::get_shorty(&return_type, &parameters),
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
/// <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
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 <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
#[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<DexString> {
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<Self> {
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
/// <https://source.android.com/docs/core/runtime/dex-format#membername>
#[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()
}
}

View file

@ -1,10 +1,8 @@
//! Representation of the fields of a class. //! Representation of the fields of a class.
use pyo3::exceptions::PyTypeError;
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::DexString; use crate::{DexValue, IdField};
use androscalpel_serializer::{StringDataItem, Uleb128};
/// Represent a field. /// Represent a field.
#[pyclass] #[pyclass]
@ -12,7 +10,7 @@ use androscalpel_serializer::{StringDataItem, Uleb128};
pub struct Field { pub struct Field {
/// The structure used to reference this field. /// The structure used to reference this field.
#[pyo3(get, set)] #[pyo3(get, set)]
pub descriptor: DexField, pub descriptor: IdField,
/// The field visibility /// The field visibility
#[pyo3(get, set)] #[pyo3(get, set)]
pub visibility: FieldVisibility, pub visibility: FieldVisibility,
@ -51,7 +49,7 @@ pub enum FieldVisibility {
#[pymethods] #[pymethods]
impl Field { impl Field {
#[new] #[new]
pub fn new(descriptor: DexField) -> Self { pub fn new(descriptor: IdField) -> Self {
Self { Self {
descriptor, descriptor,
visibility: FieldVisibility::Public, visibility: FieldVisibility::Public,
@ -116,713 +114,3 @@ impl Field {
Ok(()) 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 <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
pub(crate) shorty: DexString,
pub(crate) return_type: DexType,
pub(crate) 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(return_type: DexType, parameters: Vec<DexType>) -> Self {
// TODO: check format
Self {
shorty: Self::get_shorty(&return_type, &parameters),
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
/// <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
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 <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
#[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<DexString> {
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<Self> {
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
/// <https://source.android.com/docs/core/runtime/dex-format#membername>
#[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<Self> {
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::<PyTypeError, _>(format!(
"{} is not a castable as a DexValue",
ob.repr()?
)))
}
}
}
impl IntoPy<PyObject> 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),
}
}
}

View file

@ -4,11 +4,17 @@ use pyo3::prelude::*;
pub mod apk; pub mod apk;
pub mod class; pub mod class;
pub mod dex_id;
pub mod field; pub mod field;
pub mod scalar;
pub mod value;
pub use apk::*; pub use apk::*;
pub use class::*; pub use class::*;
pub use dex_id::*;
pub use field::*; pub use field::*;
pub use scalar::*;
pub use value::*;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -158,12 +164,12 @@ fn androscalpel(_py: Python, m: &PyModule) -> PyResult<()> {
// m.add_class::<DexMethodType>()?; // m.add_class::<DexMethodType>()?;
// m.add_class::<DexMethodHandle>()?; // m.add_class::<DexMethodHandle>()?;
m.add_class::<DexString>()?; m.add_class::<DexString>()?;
m.add_class::<DexType>()?; m.add_class::<IdType>()?;
m.add_class::<DexField>()?; m.add_class::<IdField>()?;
m.add_class::<DexMethod>()?; m.add_class::<IdMethod>()?;
m.add_class::<DexEnum>()?; m.add_class::<IdEnum>()?;
m.add_class::<DexArray>()?; m.add_class::<DexArray>()?;
m.add_class::<DexAnnotation>()?; m.add_class::<IdAnnotation>()?;
m.add_class::<DexNull>()?; m.add_class::<DexNull>()?;
m.add_class::<DexBoolean>()?; m.add_class::<DexBoolean>()?;
m.add_class::<DexString>()?; m.add_class::<DexString>()?;

256
androscalpel/src/scalar.rs Normal file
View file

@ -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()
}
}

99
androscalpel/src/value.rs Normal file
View file

@ -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<Self> {
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::<PyTypeError, _>(format!(
"{} is not a castable as a DexValue",
ob.repr()?
)))
}
}
}
impl IntoPy<PyObject> 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),
}
}
}