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 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)?;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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::*;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue