add method handle

This really needs more checks
This commit is contained in:
Jean-Marie Mineau 2023-10-02 17:55:17 +02:00
parent 77be653786
commit feff847310
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
6 changed files with 351 additions and 36 deletions

View file

@ -199,6 +199,44 @@ impl Apk {
}) })
} }
/// Return a [`MethodHandle`] from its idx.
pub fn get_method_handle_from_idx(idx: usize, dex: &DexFileReader) -> Result<MethodHandle> {
let handle = dex.get_method_handle(idx)?;
match handle.method_handle_type {
MethodHandleType::StaticPut => Ok(MethodHandle::StaticPut(StaticPut(
Self::get_id_field_from_idx(handle.field_or_method_id as usize, dex)?,
))),
MethodHandleType::StaticGet => Ok(MethodHandle::StaticGet(StaticGet(
Self::get_id_field_from_idx(handle.field_or_method_id as usize, dex)?,
))),
MethodHandleType::InstancePut => Ok(MethodHandle::InstancePut(InstancePut(
Self::get_id_field_from_idx(handle.field_or_method_id as usize, dex)?,
))),
MethodHandleType::InstanceGet => Ok(MethodHandle::InstanceGet(InstanceGet(
Self::get_id_field_from_idx(handle.field_or_method_id as usize, dex)?,
))),
MethodHandleType::InvokeStatic => Ok(MethodHandle::InvokeStatic(InvokeStatic(
Self::get_id_method_from_idx(handle.field_or_method_id as usize, dex)?,
))),
MethodHandleType::InvokeInstance => Ok(MethodHandle::InvokeInstance(InvokeInstance(
Self::get_id_method_from_idx(handle.field_or_method_id as usize, dex)?,
))),
MethodHandleType::InvokeConstructor => {
Ok(MethodHandle::InvokeConstructor(InvokeConstructor(
Self::get_id_method_from_idx(handle.field_or_method_id as usize, dex)?,
)))
}
MethodHandleType::InvokeDirect => Ok(MethodHandle::InvokeDirect(InvokeDirect(
Self::get_id_method_from_idx(handle.field_or_method_id as usize, dex)?,
))),
MethodHandleType::InvokeInterface => {
Ok(MethodHandle::InvokeInterface(InvokeInterface(
Self::get_id_method_from_idx(handle.field_or_method_id as usize, dex)?,
)))
}
}
}
pub fn encoded_value_to_dex_value( pub fn encoded_value_to_dex_value(
encoded_value: &EncodedValue, encoded_value: &EncodedValue,
dex: &DexFileReader, dex: &DexFileReader,
@ -214,8 +252,9 @@ impl Apk {
EncodedValue::MethodType(val) => Ok(DexValue::MethodType( EncodedValue::MethodType(val) => Ok(DexValue::MethodType(
Self::get_id_method_type_from_idx(*val as usize, dex)?, Self::get_id_method_type_from_idx(*val as usize, dex)?,
)), )),
// TODO: need method to be implemented first EncodedValue::MethodHandle(val) => Ok(DexValue::MethodHandle(
EncodedValue::MethodHandle(_val) => todo!(), //Ok(DexValue::MethodHandle(DexMethodHandle(*val))), Self::get_method_handle_from_idx(*val as usize, dex)?,
)),
EncodedValue::String(val) => Ok(DexValue::String(dex.get_string(*val)?.into())), EncodedValue::String(val) => Ok(DexValue::String(dex.get_string(*val)?.into())),
EncodedValue::Type(val) => Ok(DexValue::Type(Self::get_id_type_from_idx( EncodedValue::Type(val) => Ok(DexValue::Type(Self::get_id_type_from_idx(
*val as usize, *val as usize,

View file

@ -58,31 +58,6 @@ impl IdMethodType {
} }
} }
/*
#[pyclass]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IdMethodHandle(pub u32);
#[pymethods]
impl DexMethodHandle {
#[new]
pub fn new(val: u32) -> Self {
Self(val)
}
pub fn get_value(&self) -> u32 {
self.0
}
pub fn __str__(&self) -> String {
self.__repr__()
}
pub fn __repr__(&self) -> String {
format!("DexMethodHandle({})", self.0)
}
}
*/
/// A type. /// A type.
/// Type represented by [`DexString`] that follow the TypeDescriptor format /// Type represented by [`DexString`] that follow the TypeDescriptor format
/// as described here <https://source.android.com/docs/core/runtime/dex-format#typedescriptor> /// as described here <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>

View file

@ -6,6 +6,7 @@ pub mod apk;
pub mod class; pub mod class;
pub mod dex_id; pub mod dex_id;
pub mod field; pub mod field;
pub mod method_handle;
pub mod scalar; pub mod scalar;
pub mod value; pub mod value;
@ -13,6 +14,7 @@ pub use apk::*;
pub use class::*; pub use class::*;
pub use dex_id::*; pub use dex_id::*;
pub use field::*; pub use field::*;
pub use method_handle::*;
pub use scalar::*; pub use scalar::*;
pub use value::*; pub use value::*;
@ -154,6 +156,8 @@ impl DexString {
#[pymodule] #[pymodule]
fn androscalpel(_py: Python, m: &PyModule) -> PyResult<()> { fn androscalpel(_py: Python, m: &PyModule) -> PyResult<()> {
pyo3_log::init(); pyo3_log::init();
m.add_class::<DexNull>()?;
m.add_class::<DexBoolean>()?;
m.add_class::<DexByte>()?; m.add_class::<DexByte>()?;
m.add_class::<DexShort>()?; m.add_class::<DexShort>()?;
m.add_class::<DexChar>()?; m.add_class::<DexChar>()?;
@ -161,18 +165,26 @@ fn androscalpel(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<DexLong>()?; m.add_class::<DexLong>()?;
m.add_class::<DexFloat>()?; m.add_class::<DexFloat>()?;
m.add_class::<DexDouble>()?; m.add_class::<DexDouble>()?;
// m.add_class::<DexMethodType>()?;
// m.add_class::<DexMethodHandle>()?;
m.add_class::<DexString>()?; m.add_class::<DexString>()?;
m.add_class::<IdMethodType>()?;
m.add_class::<IdType>()?; m.add_class::<IdType>()?;
m.add_class::<IdField>()?; m.add_class::<IdField>()?;
m.add_class::<IdMethod>()?; m.add_class::<IdMethod>()?;
m.add_class::<IdEnum>()?; m.add_class::<IdEnum>()?;
m.add_class::<StaticPut>()?;
m.add_class::<StaticGet>()?;
m.add_class::<InstancePut>()?;
m.add_class::<InstanceGet>()?;
m.add_class::<InvokeStatic>()?;
m.add_class::<InvokeInstance>()?;
m.add_class::<InvokeConstructor>()?;
m.add_class::<InvokeDirect>()?;
m.add_class::<InvokeInterface>()?;
m.add_class::<DexArray>()?; m.add_class::<DexArray>()?;
m.add_class::<IdAnnotation>()?; m.add_class::<IdAnnotation>()?;
m.add_class::<DexNull>()?;
m.add_class::<DexBoolean>()?;
m.add_class::<DexString>()?;
m.add_class::<FieldVisibility>()?; m.add_class::<FieldVisibility>()?;
m.add_class::<Class>()?; m.add_class::<Class>()?;
m.add_class::<Apk>()?; m.add_class::<Apk>()?;

View file

@ -0,0 +1,278 @@
//! The structure use to reference a method invocation.
use pyo3::exceptions::PyTypeError;
use pyo3::prelude::*;
use crate::dex_id::*;
/// The structure use to reference a method invocation.
#[derive(Debug, Clone)]
pub enum MethodHandle {
StaticPut(StaticPut),
StaticGet(StaticGet),
InstancePut(InstancePut),
InstanceGet(InstanceGet),
InvokeStatic(InvokeStatic),
InvokeInstance(InvokeInstance),
InvokeConstructor(InvokeConstructor),
InvokeDirect(InvokeDirect),
InvokeInterface(InvokeInterface),
}
#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StaticPut(pub IdField);
#[pymethods]
impl StaticPut {
#[new]
pub fn new(val: IdField) -> Self {
Self(val)
}
pub fn get_field(&self) -> IdField {
self.0.clone()
}
pub fn __str__(&self) -> String {
self.__repr__()
}
pub fn __repr__(&self) -> String {
format!("StaticPut({})", self.0.__str__())
}
}
#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StaticGet(pub IdField);
#[pymethods]
impl StaticGet {
#[new]
pub fn new(val: IdField) -> Self {
Self(val)
}
pub fn get_field(&self) -> IdField {
self.0.clone()
}
pub fn __str__(&self) -> String {
self.__repr__()
}
pub fn __repr__(&self) -> String {
format!("StaticGet({})", self.0.__str__())
}
}
#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InstancePut(pub IdField);
#[pymethods]
impl InstancePut {
#[new]
pub fn new(val: IdField) -> Self {
Self(val)
}
pub fn get_field(&self) -> IdField {
self.0.clone()
}
pub fn __str__(&self) -> String {
self.__repr__()
}
pub fn __repr__(&self) -> String {
format!("InstancePut({})", self.0.__str__())
}
}
#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InstanceGet(pub IdField);
#[pymethods]
impl InstanceGet {
#[new]
pub fn new(val: IdField) -> Self {
Self(val)
}
pub fn get_field(&self) -> IdField {
self.0.clone()
}
pub fn __str__(&self) -> String {
self.__repr__()
}
pub fn __repr__(&self) -> String {
format!("InstanceGet({})", self.0.__str__())
}
}
#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvokeStatic(pub IdMethod);
#[pymethods]
impl InvokeStatic {
#[new]
pub fn new(val: IdMethod) -> Self {
Self(val)
}
pub fn get_method(&self) -> IdMethod {
self.0.clone()
}
pub fn __str__(&self) -> String {
self.__repr__()
}
pub fn __repr__(&self) -> String {
format!("InvokeStatic({})", self.0.__str__())
}
}
#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvokeInstance(pub IdMethod);
#[pymethods]
impl InvokeInstance {
#[new]
pub fn new(val: IdMethod) -> Self {
Self(val)
}
pub fn get_method(&self) -> IdMethod {
self.0.clone()
}
pub fn __str__(&self) -> String {
self.__repr__()
}
pub fn __repr__(&self) -> String {
format!("InvokeInstance({})", self.0.__str__())
}
}
#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvokeConstructor(pub IdMethod);
#[pymethods]
impl InvokeConstructor {
#[new]
pub fn new(val: IdMethod) -> Self {
Self(val)
}
pub fn get_method(&self) -> IdMethod {
self.0.clone()
}
pub fn __str__(&self) -> String {
self.__repr__()
}
pub fn __repr__(&self) -> String {
format!("InvokeConstructor({})", self.0.__str__())
}
}
#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvokeDirect(pub IdMethod);
#[pymethods]
impl InvokeDirect {
#[new]
pub fn new(val: IdMethod) -> Self {
Self(val)
}
pub fn get_method(&self) -> IdMethod {
self.0.clone()
}
pub fn __str__(&self) -> String {
self.__repr__()
}
pub fn __repr__(&self) -> String {
format!("InvokeDirect({})", self.0.__str__())
}
}
#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvokeInterface(pub IdMethod);
#[pymethods]
impl InvokeInterface {
#[new]
pub fn new(val: IdMethod) -> Self {
Self(val)
}
pub fn get_method(&self) -> IdMethod {
self.0.clone()
}
pub fn __str__(&self) -> String {
self.__repr__()
}
pub fn __repr__(&self) -> String {
format!("InvokeInterface({})", self.0.__str__())
}
}
impl<'source> FromPyObject<'source> for MethodHandle {
fn extract(ob: &'source PyAny) -> PyResult<Self> {
if let Ok(val) = StaticPut::extract(ob) {
Ok(Self::StaticPut(val))
} else if let Ok(val) = StaticGet::extract(ob) {
Ok(Self::StaticGet(val))
} else if let Ok(val) = InstancePut::extract(ob) {
Ok(Self::InstancePut(val))
} else if let Ok(val) = InstanceGet::extract(ob) {
Ok(Self::InstanceGet(val))
} else if let Ok(val) = InvokeStatic::extract(ob) {
Ok(Self::InvokeStatic(val))
} else if let Ok(val) = InvokeInstance::extract(ob) {
Ok(Self::InvokeInstance(val))
} else if let Ok(val) = InvokeConstructor::extract(ob) {
Ok(Self::InvokeConstructor(val))
} else if let Ok(val) = InvokeDirect::extract(ob) {
Ok(Self::InvokeDirect(val))
} else if let Ok(val) = InvokeInterface::extract(ob) {
Ok(Self::InvokeInterface(val))
} else {
Err(PyErr::new::<PyTypeError, _>(format!(
"{} is not a castable as a MethodHandle",
ob.repr()?
)))
}
}
}
impl IntoPy<PyObject> for MethodHandle {
fn into_py(self, py: Python<'_>) -> PyObject {
match self {
Self::StaticPut(val) => val.into_py(py),
Self::StaticGet(val) => val.into_py(py),
Self::InstancePut(val) => val.into_py(py),
Self::InstanceGet(val) => val.into_py(py),
Self::InvokeStatic(val) => val.into_py(py),
Self::InvokeInstance(val) => val.into_py(py),
Self::InvokeConstructor(val) => val.into_py(py),
Self::InvokeDirect(val) => val.into_py(py),
Self::InvokeInterface(val) => val.into_py(py),
}
}
}

View file

@ -3,7 +3,7 @@
use pyo3::exceptions::PyTypeError; use pyo3::exceptions::PyTypeError;
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::{dex_id::*, scalar::*, DexString}; use crate::{dex_id::*, scalar::*, DexString, MethodHandle};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum DexValue { pub enum DexValue {
@ -15,7 +15,7 @@ pub enum DexValue {
Float(DexFloat), Float(DexFloat),
Double(DexDouble), Double(DexDouble),
MethodType(IdMethodType), MethodType(IdMethodType),
//MethodHandle(DexMethodHandle), MethodHandle(MethodHandle),
String(DexString), String(DexString),
Type(IdType), Type(IdType),
Field(IdField), Field(IdField),
@ -63,7 +63,8 @@ impl<'source> FromPyObject<'source> for DexValue {
Ok(Self::Boolean(val)) Ok(Self::Boolean(val))
} else if let Ok(val) = IdMethodType::extract(ob) { } else if let Ok(val) = IdMethodType::extract(ob) {
Ok(Self::MethodType(val)) Ok(Self::MethodType(val))
// } else if let Ok(val) = DexMethodHandle::extract(ob) { Ok(Self::MethodHandle(val)) } else if let Ok(val) = MethodHandle::extract(ob) {
Ok(Self::MethodHandle(val))
} else { } else {
Err(PyErr::new::<PyTypeError, _>(format!( Err(PyErr::new::<PyTypeError, _>(format!(
"{} is not a castable as a DexValue", "{} is not a castable as a DexValue",
@ -84,7 +85,7 @@ impl IntoPy<PyObject> for DexValue {
DexValue::Float(val) => val.into_py(py), DexValue::Float(val) => val.into_py(py),
DexValue::Double(val) => val.into_py(py), DexValue::Double(val) => val.into_py(py),
DexValue::MethodType(val) => val.into_py(py), DexValue::MethodType(val) => val.into_py(py),
//DexValue::MethodHandle(val) => val.into_py(py), DexValue::MethodHandle(val) => val.into_py(py),
DexValue::String(val) => val.into_py(py), DexValue::String(val) => val.into_py(py),
DexValue::Type(val) => val.into_py(py), DexValue::Type(val) => val.into_py(py),
DexValue::Field(val) => val.into_py(py), DexValue::Field(val) => val.into_py(py),

View file

@ -184,6 +184,16 @@ impl<'a> DexFileReader<'a> {
))) )))
} }
/// Return a [`MethodHandleItem`] reference from its idx.
pub fn get_method_handle(&self, idx: usize) -> Result<&MethodHandleItem> {
self.method_handles
.get(idx)
.ok_or(Error::InconsistantStruct(format!(
"method handle {idx} is out of bound (|method_handles|={})",
self.method_handles.len()
)))
}
fn sanity_check(&self) -> Result<()> { fn sanity_check(&self) -> Result<()> {
if self.header.magic.version != [0x30, 0x33, 0x39] { if self.header.magic.version != [0x30, 0x33, 0x39] {
warn!( warn!(