From 68520d0c30d912c42e82cf1ae09b4234525c2e47 Mon Sep 17 00:00:00 2001 From: Jean-Marie 'Histausse' Mineau Date: Fri, 1 Sep 2023 18:56:41 +0200 Subject: [PATCH] add flags for fields --- androscalpel/src/apk.rs | 50 +++++++++++++++++++++++++++++++++------ androscalpel/src/class.rs | 2 +- androscalpel/src/field.rs | 43 ++++++++++++++++++++++++++++++++- androscalpel/src/lib.rs | 3 ++- 4 files changed, 88 insertions(+), 10 deletions(-) diff --git a/androscalpel/src/apk.rs b/androscalpel/src/apk.rs index 4f0cb6e..9dde770 100644 --- a/androscalpel/src/apk.rs +++ b/androscalpel/src/apk.rs @@ -2,7 +2,7 @@ use log::info; use pyo3::prelude::*; -use crate::{Class, DexString, Field, Result}; +use crate::{Class, DexString, Error, Field, FieldVisibility, Result}; use androscalpel_serializer::*; /// Represent an apk. @@ -34,11 +34,11 @@ impl Apk { .get_type_id(class_item.class_idx as usize)? .descriptor_idx; let name: DexString = dex.get_string(name_idx)?.into(); - let superclass = if class_item.class_idx == NO_INDEX.0 { + let superclass = if class_item.superclass_idx == NO_INDEX.0 { None } else { let superclass_idx = dex - .get_type_id(class_item.class_idx as usize)? + .get_type_id(class_item.superclass_idx as usize)? .descriptor_idx; Some(dex.get_string(superclass_idx)?.into()) }; @@ -116,13 +116,49 @@ impl Apk { let mut fields = vec![]; for field in encoded_fields { idx += field.field_idx_diff.0; - // TODO: flags + let id_item = dex.get_field_id(idx as usize)?; - // Check class_idx == class? ¯\_(ツ)/¯ + // Check class_idx == class? ¯\_(ツ)/¯ at list 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(); let ty = dex.get_type_id(id_item.type_idx as usize)?; let ty = dex.get_string(ty.descriptor_idx)?.into(); - let name = dex.get_string(id_item.name_idx)?.into(); - fields.push(Field { name, type_: ty }) + let name: DexString = dex.get_string(id_item.name_idx)?.into(); + + let is_public = (field.access_flags.0 & ACC_PUBLIC) != 0; + let is_private = (field.access_flags.0 & ACC_PRIVATE) != 0; + let is_protected = (field.access_flags.0 & ACC_PROTECTED) != 0; + let is_static = (field.access_flags.0 & ACC_STATIC) != 0; + let is_final = (field.access_flags.0 & ACC_FINAL) != 0; + let is_volatile = (field.access_flags.0 & ACC_VOLATILE) != 0; + let is_transient = (field.access_flags.0 & ACC_TRANSIENT) != 0; + let is_synthetic = (field.access_flags.0 & ACC_SYNTHETIC) != 0; + let is_enum = (field.access_flags.0 & ACC_ENUM) != 0; + let visibility = match (is_public, is_private, is_protected) { + (true, false, false) => FieldVisibility::Public, + (false, true, false) => FieldVisibility::Private, + (false, false, true) => FieldVisibility::Protected, + (false, false, false) => FieldVisibility::None_, + (pbl, prv, prt) => { + let name: String = name.into(); + return Err(Error::InconsistantStruct(format!( + "Inconsistant visiblity found in {class}.{name}: \ + (public: {pbl}, private: {prv}, protected: {prt})" + ))); + } + }; + fields.push(Field { + name, + type_: ty, + visibility, + is_static, + is_final, + is_volatile, + is_transient, + is_synthetic, + is_enum, + }) } Ok(fields) } diff --git a/androscalpel/src/class.rs b/androscalpel/src/class.rs index 177d21f..94c2029 100644 --- a/androscalpel/src/class.rs +++ b/androscalpel/src/class.rs @@ -69,7 +69,7 @@ impl Class { pub fn new(name: DexString) -> Self { Self { name, - superclass: None, + superclass: Some("Ljava/lang/Object;".into()), interfaces: vec![], source_file: None, is_public: true, diff --git a/androscalpel/src/field.rs b/androscalpel/src/field.rs index 5b67a69..612e393 100644 --- a/androscalpel/src/field.rs +++ b/androscalpel/src/field.rs @@ -15,13 +15,54 @@ pub struct Field { /// The type of the field, format described at <> #[pyo3(get, set)] pub type_: DexString, + /// The field visibility + #[pyo3(get, set)] + pub visibility: FieldVisibility, + /// If the field is defined for the class globally + #[pyo3(get, set)] + pub is_static: bool, + /// If the field is immutable after construction + #[pyo3(get, set)] + pub is_final: bool, + /// For thread safety + #[pyo3(get, set)] + pub is_volatile: bool, + /// If the field should **not** be saved by default serialization + #[pyo3(get, set)] + pub is_transient: bool, + /// If the field is not defined in the source code + #[pyo3(get, set)] + pub is_synthetic: bool, + /// If the field is an enumerated value + #[pyo3(get, set)] + pub is_enum: bool, +} + +/// Represent the visibility of a field +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum FieldVisibility { + Public, + Private, + Protected, + None_, // Actually quite common } #[pymethods] impl Field { #[new] pub fn new(name: DexString, type_: DexString) -> Self { - Self { name, type_ } + Self { + name, + type_, + visibility: FieldVisibility::Public, + is_static: false, + is_final: false, + is_volatile: false, + is_transient: false, + is_synthetic: false, + is_enum: false, + } } pub fn __str__(&self) -> String { diff --git a/androscalpel/src/lib.rs b/androscalpel/src/lib.rs index 4e5e975..048e5e8 100644 --- a/androscalpel/src/lib.rs +++ b/androscalpel/src/lib.rs @@ -148,8 +148,9 @@ 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::()?; Ok(()) }