add method handle
This really needs more checks
This commit is contained in:
parent
77be653786
commit
feff847310
6 changed files with 351 additions and 36 deletions
|
|
@ -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(
|
||||
encoded_value: &EncodedValue,
|
||||
dex: &DexFileReader,
|
||||
|
|
@ -214,8 +252,9 @@ impl Apk {
|
|||
EncodedValue::MethodType(val) => Ok(DexValue::MethodType(
|
||||
Self::get_id_method_type_from_idx(*val as usize, dex)?,
|
||||
)),
|
||||
// TODO: need method to be implemented first
|
||||
EncodedValue::MethodHandle(_val) => todo!(), //Ok(DexValue::MethodHandle(DexMethodHandle(*val))),
|
||||
EncodedValue::MethodHandle(val) => Ok(DexValue::MethodHandle(
|
||||
Self::get_method_handle_from_idx(*val as usize, dex)?,
|
||||
)),
|
||||
EncodedValue::String(val) => Ok(DexValue::String(dex.get_string(*val)?.into())),
|
||||
EncodedValue::Type(val) => Ok(DexValue::Type(Self::get_id_type_from_idx(
|
||||
*val as usize,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
/// Type represented by [`DexString`] that follow the TypeDescriptor format
|
||||
/// as described here <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ pub mod apk;
|
|||
pub mod class;
|
||||
pub mod dex_id;
|
||||
pub mod field;
|
||||
pub mod method_handle;
|
||||
pub mod scalar;
|
||||
pub mod value;
|
||||
|
||||
|
|
@ -13,6 +14,7 @@ pub use apk::*;
|
|||
pub use class::*;
|
||||
pub use dex_id::*;
|
||||
pub use field::*;
|
||||
pub use method_handle::*;
|
||||
pub use scalar::*;
|
||||
pub use value::*;
|
||||
|
||||
|
|
@ -154,6 +156,8 @@ impl DexString {
|
|||
#[pymodule]
|
||||
fn androscalpel(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||
pyo3_log::init();
|
||||
m.add_class::<DexNull>()?;
|
||||
m.add_class::<DexBoolean>()?;
|
||||
m.add_class::<DexByte>()?;
|
||||
m.add_class::<DexShort>()?;
|
||||
m.add_class::<DexChar>()?;
|
||||
|
|
@ -161,18 +165,26 @@ fn androscalpel(_py: Python, m: &PyModule) -> PyResult<()> {
|
|||
m.add_class::<DexLong>()?;
|
||||
m.add_class::<DexFloat>()?;
|
||||
m.add_class::<DexDouble>()?;
|
||||
// m.add_class::<DexMethodType>()?;
|
||||
// m.add_class::<DexMethodHandle>()?;
|
||||
m.add_class::<DexString>()?;
|
||||
|
||||
m.add_class::<IdMethodType>()?;
|
||||
m.add_class::<IdType>()?;
|
||||
m.add_class::<IdField>()?;
|
||||
m.add_class::<IdMethod>()?;
|
||||
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::<IdAnnotation>()?;
|
||||
m.add_class::<DexNull>()?;
|
||||
m.add_class::<DexBoolean>()?;
|
||||
m.add_class::<DexString>()?;
|
||||
m.add_class::<FieldVisibility>()?;
|
||||
m.add_class::<Class>()?;
|
||||
m.add_class::<Apk>()?;
|
||||
|
|
|
|||
278
androscalpel/src/method_handle.rs
Normal file
278
androscalpel/src/method_handle.rs
Normal 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
use pyo3::exceptions::PyTypeError;
|
||||
use pyo3::prelude::*;
|
||||
|
||||
use crate::{dex_id::*, scalar::*, DexString};
|
||||
use crate::{dex_id::*, scalar::*, DexString, MethodHandle};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DexValue {
|
||||
|
|
@ -15,7 +15,7 @@ pub enum DexValue {
|
|||
Float(DexFloat),
|
||||
Double(DexDouble),
|
||||
MethodType(IdMethodType),
|
||||
//MethodHandle(DexMethodHandle),
|
||||
MethodHandle(MethodHandle),
|
||||
String(DexString),
|
||||
Type(IdType),
|
||||
Field(IdField),
|
||||
|
|
@ -63,7 +63,8 @@ impl<'source> FromPyObject<'source> for DexValue {
|
|||
Ok(Self::Boolean(val))
|
||||
} else if let Ok(val) = IdMethodType::extract(ob) {
|
||||
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 {
|
||||
Err(PyErr::new::<PyTypeError, _>(format!(
|
||||
"{} is not a castable as a DexValue",
|
||||
|
|
@ -84,7 +85,7 @@ impl IntoPy<PyObject> for DexValue {
|
|||
DexValue::Float(val) => val.into_py(py),
|
||||
DexValue::Double(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::Type(val) => val.into_py(py),
|
||||
DexValue::Field(val) => val.into_py(py),
|
||||
|
|
|
|||
|
|
@ -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<()> {
|
||||
if self.header.magic.version != [0x30, 0x33, 0x39] {
|
||||
warn!(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue