add class data to generated dex
This commit is contained in:
parent
409663ca19
commit
bb9f5a94aa
12 changed files with 474 additions and 41 deletions
|
|
@ -3,7 +3,9 @@ use std::collections::{HashMap, HashSet};
|
|||
|
||||
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
|
||||
#[pyclass]
|
||||
|
|
@ -86,6 +88,11 @@ impl DexAnnotationItem {
|
|||
pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
|
||||
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.
|
||||
|
|
@ -170,4 +177,13 @@ impl DexAnnotation {
|
|||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ use std::collections::{HashMap, HashSet};
|
|||
use pyo3::prelude::*;
|
||||
|
||||
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
|
||||
#[pyclass]
|
||||
|
|
@ -242,7 +244,7 @@ impl Class {
|
|||
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 also contains reference to method in other classes used by methods/values
|
||||
/// in this class.
|
||||
|
|
@ -267,4 +269,60 @@ impl Class {
|
|||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::collections::HashSet;
|
|||
|
||||
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
|
||||
|
||||
|
|
@ -102,4 +102,10 @@ impl Code {
|
|||
// TODO
|
||||
HashSet::new()
|
||||
}
|
||||
|
||||
/// Return all method handles referenced in the codes.
|
||||
pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
|
||||
// TODO
|
||||
HashSet::new()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ pub struct DexWriter {
|
|||
/// index in the `class_defs` section.
|
||||
class_defs: HashMap<IdType, (Class, usize)>,
|
||||
// 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:
|
||||
// **map_list**, prbl generate on write
|
||||
// values
|
||||
|
|
@ -285,8 +285,9 @@ impl DexWriter {
|
|||
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_data_list = vec![];
|
||||
for (idx, class_id) in self.get_sorted_class_def()?.into_iter().enumerate() {
|
||||
self.class_defs
|
||||
.entry(class_id.clone())
|
||||
|
|
@ -298,17 +299,7 @@ impl DexWriter {
|
|||
class.descriptor.__repr__(),
|
||||
class.__repr__()
|
||||
))? as u32,
|
||||
access_flags: if class.is_public { ACC_PUBLIC } else { 0 }
|
||||
| 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 },
|
||||
access_flags: class.get_raw_access_flags(),
|
||||
superclass_idx: if let Some(sup) = &class.superclass {
|
||||
*self.type_ids.get(sup).ok_or(anyhow!(
|
||||
"Type {} (superclass of class {}) not found in dex builder",
|
||||
|
|
@ -318,7 +309,7 @@ impl DexWriter {
|
|||
} else {
|
||||
NO_INDEX.0
|
||||
},
|
||||
interfaces_off: 0, // TODO
|
||||
interfaces_off: 0,
|
||||
source_file_idx: if let Some(file) = &class.source_file {
|
||||
*self.strings.get(file).ok_or(anyhow!(
|
||||
"String {} (source file of class {}) not found in dex builder",
|
||||
|
|
@ -328,13 +319,122 @@ impl DexWriter {
|
|||
} else {
|
||||
NO_INDEX.0
|
||||
},
|
||||
annotations_off: 0, // TODO
|
||||
class_data_off: 0, // TODO
|
||||
annotations_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
|
||||
});
|
||||
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");
|
||||
let mut type_lists_index = HashMap::new();
|
||||
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");
|
||||
// TODO: compute checksum, hash, ect
|
||||
self.header.serialize(writer)?;
|
||||
|
|
@ -476,9 +584,11 @@ impl DexWriter {
|
|||
class_def.serialize(writer)?;
|
||||
}
|
||||
// TODO: CallSiteIdItem,
|
||||
// TODO: MethodHandleItem,
|
||||
// TODO: Data,
|
||||
// MapList,
|
||||
// MethodHandleItem section
|
||||
for handle in _method_handles {
|
||||
handle.serialize(writer)?;
|
||||
}
|
||||
// MapList
|
||||
map_list.serialize(writer)?;
|
||||
// TypeList,
|
||||
let mut offset = 0;
|
||||
|
|
@ -492,7 +602,10 @@ impl DexWriter {
|
|||
}
|
||||
// TODO: AnnotationSetRefList,
|
||||
// TODO: AnnotationSetItem,
|
||||
// TODO: ClassDataItem,
|
||||
// ClassDataItem section
|
||||
for data in class_data_list {
|
||||
data.serialize(writer)?;
|
||||
}
|
||||
// TODO: CodeItem,
|
||||
for string in string_ids_list {
|
||||
string.serialize(writer)?;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ use std::collections::HashSet;
|
|||
|
||||
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.
|
||||
#[pyclass]
|
||||
|
|
@ -171,7 +174,7 @@ impl Field {
|
|||
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> {
|
||||
let mut methods = HashSet::new();
|
||||
if let Some(value) = &self.value {
|
||||
|
|
@ -182,4 +185,51 @@ impl Field {
|
|||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ use std::collections::HashSet;
|
|||
|
||||
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.
|
||||
#[pyclass]
|
||||
|
|
@ -196,4 +199,73 @@ impl Method {
|
|||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//! The structure use to reference a method invocation.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::hash::Hash;
|
||||
|
||||
use pyo3::exceptions::PyTypeError;
|
||||
use pyo3::prelude::*;
|
||||
|
|
@ -9,7 +10,7 @@ use crate::dex_id::*;
|
|||
use crate::DexString;
|
||||
|
||||
/// The structure use to reference a method invocation.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum MethodHandle {
|
||||
StaticPut(StaticPut),
|
||||
StaticGet(StaticGet),
|
||||
|
|
@ -23,7 +24,7 @@ pub enum MethodHandle {
|
|||
}
|
||||
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct StaticPut(pub IdField);
|
||||
|
||||
#[pymethods]
|
||||
|
|
@ -71,9 +72,16 @@ impl StaticPut {
|
|||
pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
|
||||
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]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct StaticGet(pub IdField);
|
||||
|
||||
#[pymethods]
|
||||
|
|
@ -121,9 +129,16 @@ impl StaticGet {
|
|||
pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
|
||||
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]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct InstancePut(pub IdField);
|
||||
|
||||
#[pymethods]
|
||||
|
|
@ -171,9 +186,16 @@ impl InstancePut {
|
|||
pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
|
||||
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]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct InstanceGet(pub IdField);
|
||||
|
||||
#[pymethods]
|
||||
|
|
@ -221,10 +243,17 @@ impl InstanceGet {
|
|||
pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
|
||||
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]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct InvokeStatic(pub IdMethod);
|
||||
|
||||
#[pymethods]
|
||||
|
|
@ -272,10 +301,17 @@ impl InvokeStatic {
|
|||
methods.insert(self.0.clone());
|
||||
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]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct InvokeInstance(pub IdMethod);
|
||||
|
||||
#[pymethods]
|
||||
|
|
@ -323,10 +359,17 @@ impl InvokeInstance {
|
|||
methods.insert(self.0.clone());
|
||||
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]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct InvokeConstructor(pub IdMethod);
|
||||
|
||||
#[pymethods]
|
||||
|
|
@ -374,10 +417,17 @@ impl InvokeConstructor {
|
|||
methods.insert(self.0.clone());
|
||||
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]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct InvokeDirect(pub IdMethod);
|
||||
|
||||
#[pymethods]
|
||||
|
|
@ -425,10 +475,17 @@ impl InvokeDirect {
|
|||
methods.insert(self.0.clone());
|
||||
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]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct InvokeInterface(pub IdMethod);
|
||||
|
||||
#[pymethods]
|
||||
|
|
@ -476,6 +533,13 @@ impl InvokeInterface {
|
|||
methods.insert(self.0.clone());
|
||||
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 {
|
||||
|
|
@ -613,4 +677,19 @@ impl MethodHandle {
|
|||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::{DexString, DexValue, IdField, IdMethod, IdMethodType, IdType};
|
||||
use crate::{DexString, DexValue, IdField, IdMethod, IdMethodType, IdType, MethodHandle};
|
||||
use pyo3::prelude::*;
|
||||
|
||||
#[pyclass]
|
||||
|
|
@ -306,4 +306,13 @@ impl DexArray {
|
|||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ impl DexValue {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: implement for each variant struct for python binding
|
||||
/// Return all strings referenced in the value.
|
||||
pub fn get_all_strings(&self) -> HashSet<DexString> {
|
||||
match self {
|
||||
|
|
@ -125,6 +126,7 @@ impl DexValue {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: implement for each variant struct for python binding
|
||||
/// Return all types referenced in the value.
|
||||
pub fn get_all_types(&self) -> HashSet<IdType> {
|
||||
match self {
|
||||
|
|
@ -149,6 +151,7 @@ impl DexValue {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: implement for each variant struct for python binding
|
||||
/// Return all prototypes referenced in the value.
|
||||
pub fn get_all_protos(&self) -> HashSet<IdMethodType> {
|
||||
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.
|
||||
pub fn get_all_field_ids(&self) -> HashSet<IdField> {
|
||||
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.
|
||||
pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
|
||||
match self {
|
||||
|
|
@ -220,6 +225,31 @@ impl DexValue {
|
|||
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 {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ pub enum MethodHandleType {
|
|||
}
|
||||
|
||||
/// <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 static_fields_size: Uleb128,
|
||||
// pub instance_fields_size: Uleb128,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
pub mod annotation;
|
||||
pub mod array;
|
||||
pub mod constant;
|
||||
pub mod consts;
|
||||
pub mod core;
|
||||
pub mod debug;
|
||||
pub mod file_reader;
|
||||
|
|
@ -12,7 +12,7 @@ pub use androscalpel_serializer_derive::*;
|
|||
pub use crate::core::*;
|
||||
pub use annotation::*;
|
||||
pub use array::*;
|
||||
pub use constant::*;
|
||||
pub use consts::*;
|
||||
pub use debug::*;
|
||||
pub use items::*;
|
||||
pub use value::*;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue