diff --git a/androscalpel/src/annotation.rs b/androscalpel/src/annotation.rs index fb5afea..42400cf 100644 --- a/androscalpel/src/annotation.rs +++ b/androscalpel/src/annotation.rs @@ -7,7 +7,7 @@ use pyo3::prelude::*; use crate::hashmap_vectorize; use crate::{ dex_id::IdType, value::DexValue, DexString, IdField, IdMethod, IdMethodType, MethodHandle, - Result, + Result, Visitable, VisitableMut, Visitor, VisitorMut, }; /// Annotation with a visibility @@ -217,3 +217,27 @@ impl DexAnnotation { Ok(serde_json::from_str(json)?) } } + +impl Visitable for DexAnnotation { + fn default_visit(&self, v: &mut V) -> Result<()> { + v.visit_type(&self.type_)?; + for (id, val) in &self.elements { + v.visit_string(id)?; + v.visit_value(val)?; + } + Ok(()) + } +} + +impl VisitableMut for DexAnnotation { + fn default_visit_mut(self, v: &mut V) -> Result { + let type_ = v.visit_type(self.type_)?; + let mut elements = HashMap::new(); + for (id, val) in self.elements { + let id = v.visit_string(id)?; + let val = v.visit_value(val)?; + elements.insert(id, val); + } + Ok(Self { type_, elements }) + } +} diff --git a/androscalpel/src/code.rs b/androscalpel/src/code.rs index 56741fb..ff5db0f 100644 --- a/androscalpel/src/code.rs +++ b/androscalpel/src/code.rs @@ -265,7 +265,7 @@ impl Code { let mut new_insns = vec![]; last_ins_was_a_label = false; - for ins in self.insns.into_iter() { + for ins in self.insns.iter().cloned() { match ins { Instruction::Goto { label } => { last_ins_was_a_label = false; diff --git a/androscalpel/src/dex_writer.rs b/androscalpel/src/dex_writer.rs index 0c3c2b7..fb04835 100644 --- a/androscalpel/src/dex_writer.rs +++ b/androscalpel/src/dex_writer.rs @@ -511,9 +511,7 @@ impl DexWriter { for ins in &code.insns { match ins { Instruction::FillArrayData { - data, - elt_width, - arr, + data, elt_width, .. } => { let payload = InsFormat::FormatFillArrayDataPayload { elt_width: *elt_width, diff --git a/androscalpel/src/instructions.rs b/androscalpel/src/instructions.rs index bfd40c7..6ed5653 100644 --- a/androscalpel/src/instructions.rs +++ b/androscalpel/src/instructions.rs @@ -3862,7 +3862,6 @@ impl Instruction { Self::FloatToDouble { dest, val } => { sanity_check_4_bit_reg!("float-to-double", dest, val) } - Self::LongToInt { dest, val } => sanity_check_4_bit_reg!("long-to-int", dest, val), Self::DoubleToInt { dest, val } => sanity_check_4_bit_reg!("double-to-int", dest, val), Self::DoubleToLong { dest, val } => { sanity_check_4_bit_reg!("double-to-long", dest, val) @@ -6609,3 +6608,30 @@ impl CallSite { handles } } + +impl Visitable for CallSite { + fn default_visit(&self, v: &mut V) -> Result<()> { + v.visit_method_handle(&self.method_handle)?; + v.visit_string(&self.name)?; + v.visit_method_type(&self.type_)?; + for arg in &self.args { + v.visit_value(&arg)?; + } + Ok(()) + } +} + +impl VisitableMut for CallSite { + fn default_visit_mut(self, v: &mut V) -> Result { + Ok(Self { + method_handle: v.visit_method_handle(self.method_handle)?, + name: v.visit_string(self.name)?, + type_: v.visit_method_type(self.type_)?, + args: self + .args + .into_iter() + .map(|arg| v.visit_value(arg)) + .collect::>()?, + }) + } +} diff --git a/androscalpel/src/lib.rs b/androscalpel/src/lib.rs index 0d8b614..a58d495 100644 --- a/androscalpel/src/lib.rs +++ b/androscalpel/src/lib.rs @@ -33,6 +33,7 @@ pub use dex_writer::*; pub use field::*; pub use hiddenapi::*; pub use instructions as ins; +pub use instructions::*; pub use method::*; pub use method_handle::*; pub use scalar::*; @@ -91,199 +92,6 @@ fn androscalpel(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { /// Dalvik opcode for Androscalpel. fn androscalpel_ins(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; + m.add_class::()?; Ok(()) } diff --git a/androscalpel/src/scalar.rs b/androscalpel/src/scalar.rs index f7d4055..f11a174 100644 --- a/androscalpel/src/scalar.rs +++ b/androscalpel/src/scalar.rs @@ -4,7 +4,10 @@ use crate::Result; use serde::{Deserialize, Serialize}; use std::collections::HashSet; -use crate::{DexString, DexValue, IdField, IdMethod, IdMethodType, IdType, MethodHandle}; +use crate::{ + DexString, DexValue, IdField, IdMethod, IdMethodType, IdType, MethodHandle, Visitable, + VisitableMut, Visitor, VisitorMut, +}; use pyo3::prelude::*; #[pyclass] @@ -417,3 +420,23 @@ impl DexArray { methods } } + +impl Visitable for DexArray { + fn default_visit(&self, v: &mut V) -> Result<()> { + for val in &self.0 { + v.visit_value(&val)?; + } + Ok(()) + } +} + +impl VisitableMut for DexArray { + fn default_visit_mut(self, v: &mut V) -> Result { + Ok(Self( + self.0 + .into_iter() + .map(|val| v.visit_value(val)) + .collect::>()?, + )) + } +} diff --git a/androscalpel/src/value.rs b/androscalpel/src/value.rs index b5af3ef..5ad4c4f 100644 --- a/androscalpel/src/value.rs +++ b/androscalpel/src/value.rs @@ -6,7 +6,10 @@ use std::collections::HashSet; use pyo3::exceptions::PyTypeError; use pyo3::prelude::*; -use crate::{dex_id::*, scalar::*, DexAnnotation, DexString, MethodHandle}; +use crate::{ + dex_id::*, scalar::*, DexAnnotation, DexString, MethodHandle, Result, Visitable, VisitableMut, + Visitor, VisitorMut, +}; #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub enum DexValue { @@ -30,6 +33,56 @@ pub enum DexValue { Boolean(DexBoolean), } +impl Visitable for DexValue { + fn default_visit(&self, v: &mut V) -> Result<()> { + match self { + Self::Byte(val) => v.visit_byte(val), + Self::Short(val) => v.visit_short(val), + Self::Char(val) => v.visit_char(val), + Self::Int(val) => v.visit_int(val), + Self::Long(val) => v.visit_long(val), + Self::Float(val) => v.visit_float(val), + Self::Double(val) => v.visit_double(val), + Self::MethodType(val) => v.visit_method_type(val), + Self::MethodHandle(val) => v.visit_method_handle(val), + Self::String(val) => v.visit_string(val), + Self::Type(val) => v.visit_type(val), + Self::Field(val) => v.visit_field_id(val), + Self::Method(val) => v.visit_method_id(val), + Self::Enum(val) => v.visit_enum_id(val), + Self::Array(val) => v.visit_array(val), + Self::Annotation(val) => v.visit_annotation(val), + Self::Null(val) => v.visit_null(val), + Self::Boolean(val) => v.visit_bool(val), + } + } +} + +impl VisitableMut for DexValue { + fn default_visit_mut(self, v: &mut V) -> Result { + match self { + Self::Byte(val) => Ok(Self::Byte(v.visit_byte(val)?)), + Self::Short(val) => Ok(Self::Short(v.visit_short(val)?)), + Self::Char(val) => Ok(Self::Char(v.visit_char(val)?)), + Self::Int(val) => Ok(Self::Int(v.visit_int(val)?)), + Self::Long(val) => Ok(Self::Long(v.visit_long(val)?)), + Self::Float(val) => Ok(Self::Float(v.visit_float(val)?)), + Self::Double(val) => Ok(Self::Double(v.visit_double(val)?)), + Self::MethodType(val) => Ok(Self::MethodType(v.visit_method_type(val)?)), + Self::MethodHandle(val) => Ok(Self::MethodHandle(v.visit_method_handle(val)?)), + Self::String(val) => Ok(Self::String(v.visit_string(val)?)), + Self::Type(val) => Ok(Self::Type(v.visit_type(val)?)), + Self::Field(val) => Ok(Self::Field(v.visit_field_id(val)?)), + Self::Method(val) => Ok(Self::Method(v.visit_method_id(val)?)), + Self::Enum(val) => Ok(Self::Enum(v.visit_enum_id(val)?)), + Self::Array(val) => Ok(Self::Array(v.visit_array(val)?)), + Self::Annotation(val) => Ok(Self::Annotation(v.visit_annotation(val)?)), + Self::Null(val) => Ok(Self::Null(v.visit_null(val)?)), + Self::Boolean(val) => Ok(Self::Boolean(v.visit_bool(val)?)), + } + } +} + impl<'source> FromPyObject<'source> for DexValue { fn extract(ob: &'source PyAny) -> PyResult { if let Ok(val) = DexByte::extract(ob) { diff --git a/androscalpel/src/visitor.rs b/androscalpel/src/visitor.rs index 27ef6b6..dbdbd40 100644 --- a/androscalpel/src/visitor.rs +++ b/androscalpel/src/visitor.rs @@ -1,8 +1,8 @@ //! The visitor trait and common implementations. use crate::{ - ins::Instruction, CallSite, DexString, IdEnum, IdField, IdMethod, IdMethodType, IdType, - MethodHandle, Result, + ins::Instruction, scalar::*, CallSite, DexAnnotation, DexString, DexValue, IdEnum, IdField, + IdMethod, IdMethodType, IdType, MethodHandle, Result, }; use std::collections::HashSet; @@ -34,6 +34,42 @@ pub trait Visitor: Sized { fn visit_call_site(&mut self, site: &CallSite) -> Result<()> { site.default_visit(self) } + fn visit_value(&mut self, val: &DexValue) -> Result<()> { + val.default_visit(self) + } + fn visit_byte(&mut self, _: &DexByte) -> Result<()> { + Ok(()) + } + fn visit_short(&mut self, _: &DexShort) -> Result<()> { + Ok(()) + } + fn visit_char(&mut self, _: &DexChar) -> Result<()> { + Ok(()) + } + fn visit_int(&mut self, _: &DexInt) -> Result<()> { + Ok(()) + } + fn visit_long(&mut self, _: &DexLong) -> Result<()> { + Ok(()) + } + fn visit_float(&mut self, _: &DexFloat) -> Result<()> { + Ok(()) + } + fn visit_double(&mut self, _: &DexDouble) -> Result<()> { + Ok(()) + } + fn visit_array(&mut self, val: &DexArray) -> Result<()> { + val.default_visit(self) + } + fn visit_annotation(&mut self, val: &DexAnnotation) -> Result<()> { + val.default_visit(self) + } + fn visit_null(&mut self, _: &DexNull) -> Result<()> { + Ok(()) + } + fn visit_bool(&mut self, _: &DexBoolean) -> Result<()> { + Ok(()) + } } pub trait VisitorMut: Sized { @@ -64,6 +100,42 @@ pub trait VisitorMut: Sized { fn visit_call_site(&mut self, site: CallSite) -> Result { site.default_visit_mut(self) } + fn visit_value(&mut self, val: DexValue) -> Result { + val.default_visit_mut(self) + } + fn visit_byte(&mut self, val: DexByte) -> Result { + Ok(val) + } + fn visit_short(&mut self, val: DexShort) -> Result { + Ok(val) + } + fn visit_char(&mut self, val: DexChar) -> Result { + Ok(val) + } + fn visit_int(&mut self, val: DexInt) -> Result { + Ok(val) + } + fn visit_long(&mut self, val: DexLong) -> Result { + Ok(val) + } + fn visit_float(&mut self, val: DexFloat) -> Result { + Ok(val) + } + fn visit_double(&mut self, val: DexDouble) -> Result { + Ok(val) + } + fn visit_array(&mut self, val: DexArray) -> Result { + val.default_visit_mut(self) + } + fn visit_annotation(&mut self, val: DexAnnotation) -> Result { + val.default_visit_mut(self) + } + fn visit_null(&mut self, val: DexNull) -> Result { + Ok(val) + } + fn visit_bool(&mut self, val: DexBoolean) -> Result { + Ok(val) + } } /// Trait for structures that can be visited.