add class data to generated dex

This commit is contained in:
Jean-Marie Mineau 2023-12-05 00:14:27 +01:00
parent 409663ca19
commit bb9f5a94aa
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
12 changed files with 474 additions and 41 deletions

View file

@ -3,7 +3,9 @@ use std::collections::{HashMap, HashSet};
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::{dex_id::IdType, value::DexValue, DexString, IdField, IdMethod, IdMethodType}; use crate::{
dex_id::IdType, value::DexValue, DexString, IdField, IdMethod, IdMethodType, MethodHandle,
};
/// Annotation with a visibility /// Annotation with a visibility
#[pyclass] #[pyclass]
@ -86,6 +88,11 @@ impl DexAnnotationItem {
pub fn get_all_method_ids(&self) -> HashSet<IdMethod> { pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
self.annotation.get_all_method_ids() self.annotation.get_all_method_ids()
} }
/// Return all method handles referenced in the annotation.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
self.annotation.get_all_method_handles()
}
} }
/// An annotation. /// An annotation.
@ -170,4 +177,13 @@ impl DexAnnotation {
} }
methods methods
} }
/// Return all method handles referenced in the annotation.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
let mut methods = HashSet::new();
for value in self.elements.values() {
methods.extend(value.get_all_method_handles());
}
methods
}
} }

View file

@ -5,8 +5,10 @@ use std::collections::{HashMap, HashSet};
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::{ use crate::{
DexAnnotationItem, DexString, Field, IdField, IdMethod, IdMethodType, IdType, Method, Result, DexAnnotationItem, DexString, Field, IdField, IdMethod, IdMethodType, IdType, Method,
MethodHandle, Result,
}; };
use androscalpel_serializer::consts::*;
/// Represent an apk /// Represent an apk
#[pyclass] #[pyclass]
@ -242,7 +244,7 @@ impl Class {
fields fields
} }
/// Return all methods id referenced in the class. /// Return all method ids referenced in the class.
/// This **not** the concatenation of the direct and virtual method attributs: /// This **not** the concatenation of the direct and virtual method attributs:
/// this also contains reference to method in other classes used by methods/values /// this also contains reference to method in other classes used by methods/values
/// in this class. /// in this class.
@ -267,4 +269,60 @@ impl Class {
} }
methods methods
} }
/// Return all method handles referenced in the class.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
let mut methods = HashSet::new();
for field in self.static_fields.values() {
methods.extend(field.get_all_method_handles());
}
for field in self.instance_fields.values() {
methods.extend(field.get_all_method_handles());
}
for method in self.direct_methods.values() {
methods.extend(method.get_all_method_handles());
}
for method in self.virtual_methods.values() {
methods.extend(method.get_all_method_handles());
}
for annot in &self.annotations {
methods.extend(annot.get_all_method_handles());
}
methods
}
/// If a data section is needed for this class.
pub fn has_data_section(&self) -> bool {
!self.static_fields.is_empty()
|| !self.instance_fields.is_empty()
|| !self.direct_methods.is_empty()
|| !self.virtual_methods.is_empty()
}
/// Return the binary representation of access flags.
pub fn get_raw_access_flags(&self) -> u32 {
let mut flags = 0u32;
if self.is_public {
flags |= ACC_PUBLIC;
}
if self.is_final {
flags |= ACC_FINAL;
}
if self.is_interface {
flags |= ACC_INTERFACE;
}
if self.is_abstract {
flags |= ACC_ABSTRACT;
}
if self.is_synthetic {
flags |= ACC_SYNTHETIC;
}
if self.is_annotation {
flags |= ACC_ANNOTATION;
}
if self.is_enum {
flags |= ACC_ENUM;
}
flags
}
} }

View file

@ -4,7 +4,7 @@ use std::collections::HashSet;
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::{DexString, IdField, IdMethod, IdMethodType, IdType}; use crate::{DexString, IdField, IdMethod, IdMethodType, IdType, MethodHandle};
// TODO: make this easy to edit/manipulate, maybe move to Method // TODO: make this easy to edit/manipulate, maybe move to Method
@ -102,4 +102,10 @@ impl Code {
// TODO // TODO
HashSet::new() HashSet::new()
} }
/// Return all method handles referenced in the codes.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
// TODO
HashSet::new()
}
} }

View file

@ -39,7 +39,7 @@ pub struct DexWriter {
/// index in the `class_defs` section. /// index in the `class_defs` section.
class_defs: HashMap<IdType, (Class, usize)>, class_defs: HashMap<IdType, (Class, usize)>,
// call_site_ids: // TODO: parsing code insns // call_site_ids: // TODO: parsing code insns
// method_handles: // method_handles are not deduplicated nor ordered, so they must be serialized on the fly.
// TODO: other structs in data: // TODO: other structs in data:
// **map_list**, prbl generate on write // **map_list**, prbl generate on write
// values // values
@ -285,8 +285,9 @@ impl DexWriter {
method_ids_list_aux method_ids_list_aux
}; };
debug!("Sort classes and generate the class_defs section"); debug!("Sort classes and generate the class_defs and class_data section");
let mut class_defs_list = vec![]; let mut class_defs_list = vec![];
let mut class_data_list = vec![];
for (idx, class_id) in self.get_sorted_class_def()?.into_iter().enumerate() { for (idx, class_id) in self.get_sorted_class_def()?.into_iter().enumerate() {
self.class_defs self.class_defs
.entry(class_id.clone()) .entry(class_id.clone())
@ -298,17 +299,7 @@ impl DexWriter {
class.descriptor.__repr__(), class.descriptor.__repr__(),
class.__repr__() class.__repr__()
))? as u32, ))? as u32,
access_flags: if class.is_public { ACC_PUBLIC } else { 0 } access_flags: class.get_raw_access_flags(),
| if class.is_final { ACC_FINAL } else { 0 }
| if class.is_interface { ACC_INTERFACE } else { 0 }
| if class.is_abstract { ACC_ABSTRACT } else { 0 }
| if class.is_synthetic { ACC_SYNTHETIC } else { 0 }
| if class.is_annotation {
ACC_ANNOTATION
} else {
0
}
| if class.is_enum { ACC_ENUM } else { 0 },
superclass_idx: if let Some(sup) = &class.superclass { superclass_idx: if let Some(sup) = &class.superclass {
*self.type_ids.get(sup).ok_or(anyhow!( *self.type_ids.get(sup).ok_or(anyhow!(
"Type {} (superclass of class {}) not found in dex builder", "Type {} (superclass of class {}) not found in dex builder",
@ -318,7 +309,7 @@ impl DexWriter {
} else { } else {
NO_INDEX.0 NO_INDEX.0
}, },
interfaces_off: 0, // TODO interfaces_off: 0,
source_file_idx: if let Some(file) = &class.source_file { source_file_idx: if let Some(file) = &class.source_file {
*self.strings.get(file).ok_or(anyhow!( *self.strings.get(file).ok_or(anyhow!(
"String {} (source file of class {}) not found in dex builder", "String {} (source file of class {}) not found in dex builder",
@ -328,13 +319,122 @@ impl DexWriter {
} else { } else {
NO_INDEX.0 NO_INDEX.0
}, },
annotations_off: 0, // TODO annotations_off: 0, // TODO
class_data_off: 0, // TODO class_data_off: {
// need relinking once offset of class_data section is known
if class.has_data_section() {
let mut data = ClassDataItem::default();
let mut static_fields: Vec<IdField> =
class.static_fields.keys().cloned().collect();
static_fields.sort();
let mut last_field_id = 0;
for id in &static_fields {
let idx = self.field_ids.get(id).ok_or(anyhow!(
"Field {} (field of class {}) not found in dex builder",
id.__repr__(),
class.__repr__()
))?;
let field_idx_diff = Uleb128((idx - last_field_id) as u32);
last_field_id = *idx;
let access_flags = Uleb128(
class.static_fields.get(id).unwrap().get_raw_access_flags(),
);
data.static_fields.push(EncodedField {
field_idx_diff,
access_flags,
});
}
let mut instance_fields: Vec<IdField> =
class.instance_fields.keys().cloned().collect();
instance_fields.sort();
let mut last_field_id = 0;
for id in &instance_fields {
let idx = self.field_ids.get(id).ok_or(anyhow!(
"Field {} (field of class {}) not found in dex builder",
id.__repr__(),
class.__repr__()
))?;
let field_idx_diff = Uleb128((idx - last_field_id) as u32);
last_field_id = *idx;
let access_flags = Uleb128(
class
.instance_fields
.get(id)
.unwrap()
.get_raw_access_flags(),
);
data.instance_fields.push(EncodedField {
field_idx_diff,
access_flags,
});
}
let mut direct_methods: Vec<IdMethod> =
class.direct_methods.keys().cloned().collect();
direct_methods.sort();
let mut last_method_id = 0;
for id in &direct_methods {
let idx = self.method_ids.get(id).ok_or(anyhow!(
"Method {} (method of class {}) not found in dex builder",
id.__repr__(),
class.__repr__()
))?;
let method_idx_diff = Uleb128((idx - last_method_id) as u32);
last_method_id = *idx;
let access_flags = Uleb128(
class.direct_methods.get(id).unwrap().get_raw_access_flags(),
);
data.direct_methods.push(EncodedMethod {
method_idx_diff,
access_flags,
code_off: Uleb128(0), // TODO
});
}
let mut virtual_methods: Vec<IdMethod> =
class.virtual_methods.keys().cloned().collect();
virtual_methods.sort();
let mut last_method_id = 0;
for id in &virtual_methods {
let idx = self.method_ids.get(id).ok_or(anyhow!(
"Method {} (method of class {}) not found in dex builder",
id.__repr__(),
class.__repr__()
))?;
let method_idx_diff = Uleb128((idx - last_method_id) as u32);
last_method_id = *idx;
let access_flags = Uleb128(
class
.virtual_methods
.get(id)
.unwrap()
.get_raw_access_flags(),
);
data.virtual_methods.push(EncodedMethod {
method_idx_diff,
access_flags,
code_off: Uleb128(0), // TODO
});
}
let class_data_off = section_manager.get_size(Section::ClassDataItem);
section_manager.add_elt(Section::ClassDataItem, Some(data.size()));
class_data_list.push(data);
class_data_off
} else {
0
}
},
static_values_off: 0, // TODO static_values_off: 0, // TODO
}); });
section_manager.add_elt(Section::ClassDefItem, None); section_manager.add_elt(Section::ClassDefItem, None);
} }
// Method handles are not ordered, nor deduplicated, so they are generated on the fly
let mut _method_handles: Vec<MethodHandleItem> = vec![];
debug!("Generate the type_list section"); debug!("Generate the type_list section");
let mut type_lists_index = HashMap::new(); let mut type_lists_index = HashMap::new();
for proto in self.proto_ids.keys() { for proto in self.proto_ids.keys() {
@ -443,6 +543,14 @@ impl DexWriter {
} }
} }
debug!("Link the class_data_item entries in class_def_items");
for (class, idx) in self.class_defs.values() {
if class.has_data_section() {
class_defs_list[*idx].class_data_off +=
section_manager.get_offset(Section::ClassDataItem);
}
}
debug!("Serialize the dex file"); debug!("Serialize the dex file");
// TODO: compute checksum, hash, ect // TODO: compute checksum, hash, ect
self.header.serialize(writer)?; self.header.serialize(writer)?;
@ -476,9 +584,11 @@ impl DexWriter {
class_def.serialize(writer)?; class_def.serialize(writer)?;
} }
// TODO: CallSiteIdItem, // TODO: CallSiteIdItem,
// TODO: MethodHandleItem, // MethodHandleItem section
// TODO: Data, for handle in _method_handles {
// MapList, handle.serialize(writer)?;
}
// MapList
map_list.serialize(writer)?; map_list.serialize(writer)?;
// TypeList, // TypeList,
let mut offset = 0; let mut offset = 0;
@ -492,7 +602,10 @@ impl DexWriter {
} }
// TODO: AnnotationSetRefList, // TODO: AnnotationSetRefList,
// TODO: AnnotationSetItem, // TODO: AnnotationSetItem,
// TODO: ClassDataItem, // ClassDataItem section
for data in class_data_list {
data.serialize(writer)?;
}
// TODO: CodeItem, // TODO: CodeItem,
for string in string_ids_list { for string in string_ids_list {
string.serialize(writer)?; string.serialize(writer)?;

View file

@ -4,7 +4,10 @@ use std::collections::HashSet;
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::{DexAnnotationItem, DexString, DexValue, IdField, IdMethod, IdMethodType, IdType}; use crate::{
DexAnnotationItem, DexString, DexValue, IdField, IdMethod, IdMethodType, IdType, MethodHandle,
};
use androscalpel_serializer::consts::*;
/// Represent a field. /// Represent a field.
#[pyclass] #[pyclass]
@ -171,7 +174,7 @@ impl Field {
fields fields
} }
/// Return all method ids referenced in the method. /// Return all method ids referenced in the field.
pub fn get_all_method_ids(&self) -> HashSet<IdMethod> { pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
let mut methods = HashSet::new(); let mut methods = HashSet::new();
if let Some(value) = &self.value { if let Some(value) = &self.value {
@ -182,4 +185,51 @@ impl Field {
} }
methods methods
} }
/// Return all method handles referenced in the field.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
let mut methods = HashSet::new();
if let Some(value) = &self.value {
methods.extend(value.get_all_method_handles());
}
for annot in &self.annotations {
methods.extend(annot.get_all_method_handles());
}
methods
}
/// Return the binary representation of access flags.
///
/// # Note
///
/// The return value is a u32, not the Uleb128
/// encoded value found in the dex file.
pub fn get_raw_access_flags(&self) -> u32 {
let mut flags = 0;
match self.visibility {
FieldVisibility::Public => flags |= ACC_PUBLIC,
FieldVisibility::Private => flags |= ACC_PRIVATE,
FieldVisibility::Protected => flags |= ACC_PROTECTED,
FieldVisibility::None_ => (),
}
if self.is_static {
flags |= ACC_STATIC
}
if self.is_final {
flags |= ACC_FINAL
}
if self.is_volatile {
flags |= ACC_VOLATILE
}
if self.is_transient {
flags |= ACC_TRANSIENT
}
if self.is_synthetic {
flags |= ACC_SYNTHETIC
}
if self.is_enum {
flags |= ACC_ENUM
}
flags
}
} }

View file

@ -4,7 +4,10 @@ use std::collections::HashSet;
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::{Code, DexAnnotationItem, DexString, IdField, IdMethod, IdMethodType, IdType}; use crate::{
Code, DexAnnotationItem, DexString, IdField, IdMethod, IdMethodType, IdType, MethodHandle,
};
use androscalpel_serializer::consts::*;
/// Represent a method. /// Represent a method.
#[pyclass] #[pyclass]
@ -196,4 +199,73 @@ impl Method {
} }
methods methods
} }
/// Return all method handles referenced in the method.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
let mut methods = HashSet::new();
for annot in &self.annotations {
methods.extend(annot.get_all_method_handles());
}
for param_annots in &self.parameters_annotations {
for annot in param_annots {
methods.extend(annot.get_all_method_handles());
}
}
if let Some(code) = &self.code {
methods.extend(code.get_all_method_handles());
}
methods
}
/// Return the binary representation of access flags.
///
/// # Note
///
/// The return value is a u32, not the Uleb128
/// encoded value found in the dex file.
pub fn get_raw_access_flags(&self) -> u32 {
let mut flags = 0;
match self.visibility {
MethodVisibility::Public => flags |= ACC_PUBLIC,
MethodVisibility::Private => flags |= ACC_PRIVATE,
MethodVisibility::Protected => flags |= ACC_PROTECTED,
MethodVisibility::None_ => (),
}
if self.is_static {
flags |= ACC_STATIC;
}
if self.is_final {
flags |= ACC_FINAL;
}
if self.is_synchronized {
flags |= ACC_SYNCHRONIZED;
}
if self.is_bridge {
flags |= ACC_BRIDGE;
}
if self.is_varargs {
flags |= ACC_VARARGS;
}
if self.is_native {
flags |= ACC_NATIVE;
}
if self.is_abstract {
flags |= ACC_ABSTRACT;
}
if self.is_strictfp {
flags |= ACC_STRICT;
}
if self.is_synthetic {
flags |= ACC_SYNTHETIC;
}
if self.is_constructor {
flags |= ACC_CONSTRUCTOR;
}
if self.is_declared_syncrhonized {
flags |= ACC_DECLARED_SYNCHRONIZED;
}
flags
}
} }

View file

@ -1,6 +1,7 @@
//! The structure use to reference a method invocation. //! The structure use to reference a method invocation.
use std::collections::HashSet; use std::collections::HashSet;
use std::hash::Hash;
use pyo3::exceptions::PyTypeError; use pyo3::exceptions::PyTypeError;
use pyo3::prelude::*; use pyo3::prelude::*;
@ -9,7 +10,7 @@ use crate::dex_id::*;
use crate::DexString; use crate::DexString;
/// The structure use to reference a method invocation. /// The structure use to reference a method invocation.
#[derive(Debug, Clone)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum MethodHandle { pub enum MethodHandle {
StaticPut(StaticPut), StaticPut(StaticPut),
StaticGet(StaticGet), StaticGet(StaticGet),
@ -23,7 +24,7 @@ pub enum MethodHandle {
} }
#[pyclass] #[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StaticPut(pub IdField); pub struct StaticPut(pub IdField);
#[pymethods] #[pymethods]
@ -71,9 +72,16 @@ impl StaticPut {
pub fn get_all_method_ids(&self) -> HashSet<IdMethod> { pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
HashSet::new() HashSet::new()
} }
/// Return all method handles referenced in the handle.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
let mut methods = HashSet::new();
methods.insert(MethodHandle::StaticPut(self.clone()));
methods
}
} }
#[pyclass] #[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StaticGet(pub IdField); pub struct StaticGet(pub IdField);
#[pymethods] #[pymethods]
@ -121,9 +129,16 @@ impl StaticGet {
pub fn get_all_method_ids(&self) -> HashSet<IdMethod> { pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
HashSet::new() HashSet::new()
} }
/// Return all method handles referenced in the handle.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
let mut methods = HashSet::new();
methods.insert(MethodHandle::StaticGet(self.clone()));
methods
}
} }
#[pyclass] #[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InstancePut(pub IdField); pub struct InstancePut(pub IdField);
#[pymethods] #[pymethods]
@ -171,9 +186,16 @@ impl InstancePut {
pub fn get_all_method_ids(&self) -> HashSet<IdMethod> { pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
HashSet::new() HashSet::new()
} }
/// Return all method handles referenced in the handle.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
let mut methods = HashSet::new();
methods.insert(MethodHandle::InstancePut(self.clone()));
methods
}
} }
#[pyclass] #[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InstanceGet(pub IdField); pub struct InstanceGet(pub IdField);
#[pymethods] #[pymethods]
@ -221,10 +243,17 @@ impl InstanceGet {
pub fn get_all_method_ids(&self) -> HashSet<IdMethod> { pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
HashSet::new() HashSet::new()
} }
/// Return all method handles referenced in the handle.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
let mut methods = HashSet::new();
methods.insert(MethodHandle::InstanceGet(self.clone()));
methods
}
} }
#[pyclass] #[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InvokeStatic(pub IdMethod); pub struct InvokeStatic(pub IdMethod);
#[pymethods] #[pymethods]
@ -272,10 +301,17 @@ impl InvokeStatic {
methods.insert(self.0.clone()); methods.insert(self.0.clone());
methods methods
} }
/// Return all method handles referenced in the handle.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
let mut methods = HashSet::new();
methods.insert(MethodHandle::InvokeStatic(self.clone()));
methods
}
} }
#[pyclass] #[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InvokeInstance(pub IdMethod); pub struct InvokeInstance(pub IdMethod);
#[pymethods] #[pymethods]
@ -323,10 +359,17 @@ impl InvokeInstance {
methods.insert(self.0.clone()); methods.insert(self.0.clone());
methods methods
} }
/// Return all method handles referenced in the handle.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
let mut methods = HashSet::new();
methods.insert(MethodHandle::InvokeInstance(self.clone()));
methods
}
} }
#[pyclass] #[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InvokeConstructor(pub IdMethod); pub struct InvokeConstructor(pub IdMethod);
#[pymethods] #[pymethods]
@ -374,10 +417,17 @@ impl InvokeConstructor {
methods.insert(self.0.clone()); methods.insert(self.0.clone());
methods methods
} }
/// Return all method handles referenced in the handle.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
let mut methods = HashSet::new();
methods.insert(MethodHandle::InvokeConstructor(self.clone()));
methods
}
} }
#[pyclass] #[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InvokeDirect(pub IdMethod); pub struct InvokeDirect(pub IdMethod);
#[pymethods] #[pymethods]
@ -425,10 +475,17 @@ impl InvokeDirect {
methods.insert(self.0.clone()); methods.insert(self.0.clone());
methods methods
} }
/// Return all method handles referenced in the handle.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
let mut methods = HashSet::new();
methods.insert(MethodHandle::InvokeDirect(self.clone()));
methods
}
} }
#[pyclass] #[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InvokeInterface(pub IdMethod); pub struct InvokeInterface(pub IdMethod);
#[pymethods] #[pymethods]
@ -476,6 +533,13 @@ impl InvokeInterface {
methods.insert(self.0.clone()); methods.insert(self.0.clone());
methods methods
} }
/// Return all method handles referenced in the handle.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
let mut methods = HashSet::new();
methods.insert(MethodHandle::InvokeInterface(self.clone()));
methods
}
} }
impl<'source> FromPyObject<'source> for MethodHandle { impl<'source> FromPyObject<'source> for MethodHandle {
@ -613,4 +677,19 @@ impl MethodHandle {
Self::InvokeInterface(val) => val.get_all_method_ids(), Self::InvokeInterface(val) => val.get_all_method_ids(),
} }
} }
/// Return all method handles referenced in the handle.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
match self {
Self::StaticPut(val) => val.get_all_method_handles(),
Self::StaticGet(val) => val.get_all_method_handles(),
Self::InstancePut(val) => val.get_all_method_handles(),
Self::InstanceGet(val) => val.get_all_method_handles(),
Self::InvokeStatic(val) => val.get_all_method_handles(),
Self::InvokeInstance(val) => val.get_all_method_handles(),
Self::InvokeConstructor(val) => val.get_all_method_handles(),
Self::InvokeDirect(val) => val.get_all_method_handles(),
Self::InvokeInterface(val) => val.get_all_method_handles(),
}
}
} }

View file

@ -2,7 +2,7 @@
use std::collections::HashSet; use std::collections::HashSet;
use crate::{DexString, DexValue, IdField, IdMethod, IdMethodType, IdType}; use crate::{DexString, DexValue, IdField, IdMethod, IdMethodType, IdType, MethodHandle};
use pyo3::prelude::*; use pyo3::prelude::*;
#[pyclass] #[pyclass]
@ -306,4 +306,13 @@ impl DexArray {
} }
methods methods
} }
/// Return all method handles referenced in the value.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
let mut methods = HashSet::new();
for val in &self.0 {
methods.extend(val.get_all_method_handles());
}
methods
}
} }

View file

@ -101,6 +101,7 @@ impl DexValue {
} }
} }
// TODO: implement for each variant struct for python binding
/// Return all strings referenced in the value. /// Return all strings referenced in the value.
pub fn get_all_strings(&self) -> HashSet<DexString> { pub fn get_all_strings(&self) -> HashSet<DexString> {
match self { match self {
@ -125,6 +126,7 @@ impl DexValue {
} }
} }
// TODO: implement for each variant struct for python binding
/// Return all types referenced in the value. /// Return all types referenced in the value.
pub fn get_all_types(&self) -> HashSet<IdType> { pub fn get_all_types(&self) -> HashSet<IdType> {
match self { match self {
@ -149,6 +151,7 @@ impl DexValue {
} }
} }
// TODO: implement for each variant struct for python binding
/// Return all prototypes referenced in the value. /// Return all prototypes referenced in the value.
pub fn get_all_protos(&self) -> HashSet<IdMethodType> { pub fn get_all_protos(&self) -> HashSet<IdMethodType> {
match self { match self {
@ -173,6 +176,7 @@ impl DexValue {
} }
} }
// TODO: implement for each variant struct for python binding
/// Return all field ids referenced in the value. /// Return all field ids referenced in the value.
pub fn get_all_field_ids(&self) -> HashSet<IdField> { pub fn get_all_field_ids(&self) -> HashSet<IdField> {
match self { match self {
@ -197,6 +201,7 @@ impl DexValue {
} }
} }
// TODO: implement for each variant struct for python binding
/// Return all method ids referenced in the value. /// Return all method ids referenced in the value.
pub fn get_all_method_ids(&self) -> HashSet<IdMethod> { pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
match self { match self {
@ -220,6 +225,31 @@ impl DexValue {
DexValue::Boolean(_) => HashSet::new(), DexValue::Boolean(_) => HashSet::new(),
} }
} }
// TODO: implement for each variant struct for python binding
/// Return all method handles referenced in the value.
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
match self {
DexValue::Byte(_) => HashSet::new(),
DexValue::Short(_) => HashSet::new(),
DexValue::Char(_) => HashSet::new(),
DexValue::Int(_) => HashSet::new(),
DexValue::Long(_) => HashSet::new(),
DexValue::Float(_) => HashSet::new(),
DexValue::Double(_) => HashSet::new(),
DexValue::MethodType(_) => HashSet::new(),
DexValue::MethodHandle(val) => val.get_all_method_handles(),
DexValue::String(_) => HashSet::new(),
DexValue::Type(_) => HashSet::new(),
DexValue::Field(_) => HashSet::new(),
DexValue::Method(_) => HashSet::new(),
DexValue::Enum(_) => HashSet::new(),
DexValue::Array(val) => val.get_all_method_handles(),
DexValue::Annotation(val) => val.get_all_method_handles(),
DexValue::Null(_) => HashSet::new(),
DexValue::Boolean(_) => HashSet::new(),
}
}
} }
impl IntoPy<PyObject> for DexValue { impl IntoPy<PyObject> for DexValue {

View file

@ -74,7 +74,7 @@ pub enum MethodHandleType {
} }
/// <https://source.android.com/docs/core/runtime/dex-format#class-data-item> /// <https://source.android.com/docs/core/runtime/dex-format#class-data-item>
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ClassDataItem { pub struct ClassDataItem {
// pub static_fields_size: Uleb128, // pub static_fields_size: Uleb128,
// pub instance_fields_size: Uleb128, // pub instance_fields_size: Uleb128,

View file

@ -1,6 +1,6 @@
pub mod annotation; pub mod annotation;
pub mod array; pub mod array;
pub mod constant; pub mod consts;
pub mod core; pub mod core;
pub mod debug; pub mod debug;
pub mod file_reader; pub mod file_reader;
@ -12,7 +12,7 @@ pub use androscalpel_serializer_derive::*;
pub use crate::core::*; pub use crate::core::*;
pub use annotation::*; pub use annotation::*;
pub use array::*; pub use array::*;
pub use constant::*; pub use consts::*;
pub use debug::*; pub use debug::*;
pub use items::*; pub use items::*;
pub use value::*; pub use value::*;