finish implementing IdMethodType
This commit is contained in:
parent
b2c4da413c
commit
cdf68c506a
3 changed files with 105 additions and 31 deletions
|
|
@ -148,7 +148,7 @@ impl Apk {
|
||||||
EncodedValue::MethodType(val) => {
|
EncodedValue::MethodType(val) => {
|
||||||
let proto = dex.get_proto_id(*val as usize)?;
|
let proto = dex.get_proto_id(*val as usize)?;
|
||||||
let shorty: DexString = dex.get_string(proto.shorty_idx)?.into();
|
let shorty: DexString = dex.get_string(proto.shorty_idx)?.into();
|
||||||
let return_type: DexType = DexType(
|
let return_type: IdType = IdType(
|
||||||
dex.get_string(
|
dex.get_string(
|
||||||
dex.get_type_id(proto.return_type_idx as usize)?
|
dex.get_type_id(proto.return_type_idx as usize)?
|
||||||
.descriptor_idx,
|
.descriptor_idx,
|
||||||
|
|
@ -159,16 +159,16 @@ impl Apk {
|
||||||
vec![]
|
vec![]
|
||||||
} else {
|
} else {
|
||||||
let type_list = dex.get_struct_at_offset::<TypeList>(proto.parameters_off)?;
|
let type_list = dex.get_struct_at_offset::<TypeList>(proto.parameters_off)?;
|
||||||
let mut parameters: Vec<DexType> = vec![];
|
let mut parameters: Vec<IdType> = vec![];
|
||||||
for ty in type_list.list {
|
for ty in type_list.list {
|
||||||
parameters.push(DexType(
|
parameters.push(IdType(
|
||||||
dex.get_string(dex.get_type_id(ty.type_idx as usize)?.descriptor_idx)?
|
dex.get_string(dex.get_type_id(ty.type_idx as usize)?.descriptor_idx)?
|
||||||
.into(),
|
.into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
parameters
|
parameters
|
||||||
};
|
};
|
||||||
Ok(DexValue::MethodType(DexMethodType {
|
Ok(DexValue::MethodType(IdMethodType {
|
||||||
shorty,
|
shorty,
|
||||||
return_type,
|
return_type,
|
||||||
parameters,
|
parameters,
|
||||||
|
|
@ -177,29 +177,29 @@ impl Apk {
|
||||||
// TODO: need method to be implemented first
|
// TODO: need method to be implemented first
|
||||||
EncodedValue::MethodHandle(_val) => todo!(), //Ok(DexValue::MethodHandle(DexMethodHandle(*val))),
|
EncodedValue::MethodHandle(_val) => todo!(), //Ok(DexValue::MethodHandle(DexMethodHandle(*val))),
|
||||||
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(DexType(
|
EncodedValue::Type(val) => Ok(DexValue::Type(IdType(
|
||||||
dex.get_string(dex.get_type_id(*val as usize)?.descriptor_idx)?
|
dex.get_string(dex.get_type_id(*val as usize)?.descriptor_idx)?
|
||||||
.into(),
|
.into(),
|
||||||
))),
|
))),
|
||||||
EncodedValue::Field(val) => {
|
EncodedValue::Field(val) => {
|
||||||
let field = dex.get_field_id(*val as usize)?;
|
let field = dex.get_field_id(*val as usize)?;
|
||||||
let name = dex.get_string(field.name_idx)?.into();
|
let name = dex.get_string(field.name_idx)?.into();
|
||||||
let type_ = DexType(
|
let type_ = IdType(
|
||||||
dex.get_string(dex.get_type_id(field.type_idx as usize)?.descriptor_idx)?
|
dex.get_string(dex.get_type_id(field.type_idx as usize)?.descriptor_idx)?
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
let class_ = DexType(
|
let class_ = IdType(
|
||||||
dex.get_string(dex.get_type_id(field.class_idx as usize)?.descriptor_idx)?
|
dex.get_string(dex.get_type_id(field.class_idx as usize)?.descriptor_idx)?
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
Ok(DexValue::Field(DexField {
|
Ok(DexValue::Field(IdField {
|
||||||
name,
|
name,
|
||||||
type_,
|
type_,
|
||||||
class_,
|
class_,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
EncodedValue::Method(val) => Ok(DexValue::Method(DexMethod(*val))),
|
EncodedValue::Method(val) => Ok(DexValue::Method(IdMethod(*val))),
|
||||||
EncodedValue::Enum(val) => Ok(DexValue::Enum(DexEnum(*val))),
|
EncodedValue::Enum(val) => Ok(DexValue::Enum(IdEnum(*val))),
|
||||||
EncodedValue::Array(_val) => todo!(), //Ok(DexValue::Array(DexArray(*val))),
|
EncodedValue::Array(_val) => todo!(), //Ok(DexValue::Array(DexArray(*val))),
|
||||||
EncodedValue::Annotation(_val) => todo!(), //Ok(DexValue::Annotation(DexAnnotation(*val))),
|
EncodedValue::Annotation(_val) => todo!(), //Ok(DexValue::Annotation(DexAnnotation(*val))),
|
||||||
EncodedValue::Null => Ok(DexValue::Null(DexNull)),
|
EncodedValue::Null => Ok(DexValue::Null(DexNull)),
|
||||||
|
|
@ -246,10 +246,10 @@ impl Apk {
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let descriptor = DexField {
|
let descriptor = IdField {
|
||||||
name,
|
name,
|
||||||
type_: DexType(ty),
|
type_: IdType(ty),
|
||||||
class_: DexType(class),
|
class_: IdType(class),
|
||||||
};
|
};
|
||||||
fields.push(Field {
|
fields.push(Field {
|
||||||
descriptor,
|
descriptor,
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,15 @@
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
use crate::DexString;
|
use crate::{DexString, Error, Result};
|
||||||
use androscalpel_serializer::{StringDataItem, Uleb128};
|
use androscalpel_serializer::{StringDataItem, Uleb128};
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct IdMethodType {
|
pub struct IdMethodType {
|
||||||
/// Type formated as described by <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
|
/// Type formated as described by <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
|
||||||
pub(crate) shorty: DexString,
|
pub(crate) shorty: DexString, // Redondant, but same as in the encoding, keep it in cas we ever
|
||||||
|
// need it
|
||||||
pub(crate) return_type: IdType,
|
pub(crate) return_type: IdType,
|
||||||
pub(crate) parameters: Vec<IdType>,
|
pub(crate) parameters: Vec<IdType>,
|
||||||
}
|
}
|
||||||
|
|
@ -20,7 +21,6 @@ pub struct IdMethodType {
|
||||||
impl IdMethodType {
|
impl IdMethodType {
|
||||||
#[new]
|
#[new]
|
||||||
pub fn new(return_type: IdType, parameters: Vec<IdType>) -> Self {
|
pub fn new(return_type: IdType, parameters: Vec<IdType>) -> Self {
|
||||||
// TODO: check format
|
|
||||||
Self {
|
Self {
|
||||||
shorty: Self::get_shorty(&return_type, ¶meters),
|
shorty: Self::get_shorty(&return_type, ¶meters),
|
||||||
return_type,
|
return_type,
|
||||||
|
|
@ -29,12 +29,19 @@ impl IdMethodType {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn __str__(&self) -> String {
|
pub fn __str__(&self) -> String {
|
||||||
self.__repr__()
|
format!(
|
||||||
|
"({}){}",
|
||||||
|
self.parameters
|
||||||
|
.iter()
|
||||||
|
.map(|param| param.__str__())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(" "),
|
||||||
|
self.return_type.__str__()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn __repr__(&self) -> String {
|
pub fn __repr__(&self) -> String {
|
||||||
let repr: String = (&self.shorty).into();
|
format!("DexMethodType({})", self.__str__())
|
||||||
format!("DexMethodType({repr})")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,7 +49,12 @@ impl IdMethodType {
|
||||||
/// Compute the format for the shorty as described in
|
/// Compute the format for the shorty as described in
|
||||||
/// <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
|
/// <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
|
||||||
pub fn get_shorty(return_type: &IdType, parameters: &[IdType]) -> DexString {
|
pub fn get_shorty(return_type: &IdType, parameters: &[IdType]) -> DexString {
|
||||||
todo!()
|
let mut shorty: String = return_type.get_shorty().into();
|
||||||
|
for ty in parameters {
|
||||||
|
let ty: String = ty.get_shorty().into();
|
||||||
|
shorty.push_str(&ty);
|
||||||
|
}
|
||||||
|
shorty.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,14 +86,24 @@ impl DexMethodHandle {
|
||||||
/// 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>
|
||||||
|
// Not a clean rust enum because we want to be compatible with python, and maybe support strange
|
||||||
|
// malware edge case?
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct IdType(pub(crate) DexString);
|
pub struct IdType(pub(crate) DexString);
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl IdType {
|
impl IdType {
|
||||||
#[new]
|
#[new]
|
||||||
pub fn _new(ty: DexString) -> Self {
|
pub fn _new(ty: DexString) -> Result<Self> {
|
||||||
// TODO: check format
|
// TODO: check format
|
||||||
|
let ty = Self(ty);
|
||||||
|
ty.check_format()?;
|
||||||
|
Ok(ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a type from its string representation without checking its format
|
||||||
|
#[staticmethod]
|
||||||
|
pub fn unchecked_new(ty: DexString) -> Self {
|
||||||
Self(ty)
|
Self(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,28 +235,28 @@ impl IdType {
|
||||||
|
|
||||||
/// Check if the type is a class
|
/// Check if the type is a class
|
||||||
pub fn is_class(&self) -> bool {
|
pub fn is_class(&self) -> bool {
|
||||||
self.0.get_utf16_size() == 0
|
self.0.get_utf16_size() >= 2
|
||||||
&& self.0.get_bytes().is_empty()
|
&& !self.0.get_bytes().len() > 2
|
||||||
&& self.0.get_bytes()[0] != 0x76
|
&& self.0.get_bytes()[0] == b'L'
|
||||||
// Check if first char is an L
|
&& *self.0.get_bytes().last().unwrap() == b';'
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the type is an array
|
/// Check if the type is an array
|
||||||
pub fn is_array(&self) -> bool {
|
pub fn is_array(&self) -> bool {
|
||||||
self.0.get_utf16_size() == 0
|
self.0.get_utf16_size() != 0
|
||||||
&& self.0.get_bytes().is_empty()
|
&& !self.0.get_bytes().is_empty()
|
||||||
&& self.0.get_bytes()[0] != 0x5b
|
&& self.0.get_bytes()[0] == b'['
|
||||||
// Check if first char is an [
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the type is a class, return the name of the class,
|
/// If the type is a class, return the name of the class,
|
||||||
/// else None.
|
/// else None.
|
||||||
pub fn get_class_name(&self) -> Option<DexString> {
|
pub fn get_class_name(&self) -> Option<DexString> {
|
||||||
if self.is_class() {
|
if self.is_class() {
|
||||||
|
let bytes = self.0.get_bytes();
|
||||||
Some(
|
Some(
|
||||||
StringDataItem {
|
StringDataItem {
|
||||||
utf16_size: Uleb128(self.0.get_utf16_size() - 1),
|
utf16_size: Uleb128(self.0.get_utf16_size() - 2),
|
||||||
data: self.0.get_bytes()[1..].to_vec(),
|
data: bytes[1..bytes.len() - 1].to_vec(),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
|
|
@ -259,6 +281,51 @@ impl IdType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the type is a value representation.
|
||||||
|
/// They should not be any needs to use this method externaly?
|
||||||
|
pub fn check_format(&self) -> Result<()> {
|
||||||
|
if self.is_void()
|
||||||
|
|| self.is_boolean()
|
||||||
|
|| self.is_byte()
|
||||||
|
|| self.is_short()
|
||||||
|
|| self.is_char()
|
||||||
|
|| self.is_int()
|
||||||
|
|| self.is_long()
|
||||||
|
|| self.is_float()
|
||||||
|
|| self.is_double()
|
||||||
|
|| self.is_class()
|
||||||
|
|| self
|
||||||
|
.get_element_type()
|
||||||
|
.map(|elt| elt.check_format().is_ok())
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
let format: String = (&self.0).into();
|
||||||
|
Err(Error::InconsistantStruct(format!(
|
||||||
|
"{format} is not a valid type"
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the shorty repr of this type (ID: the type if it's a scalar, 'L' else)
|
||||||
|
pub fn get_shorty(&self) -> DexString {
|
||||||
|
if self.is_void()
|
||||||
|
|| self.is_boolean()
|
||||||
|
|| self.is_byte()
|
||||||
|
|| self.is_short()
|
||||||
|
|| self.is_char()
|
||||||
|
|| self.is_int()
|
||||||
|
|| self.is_long()
|
||||||
|
|| self.is_float()
|
||||||
|
|| self.is_double()
|
||||||
|
{
|
||||||
|
self.0.clone()
|
||||||
|
} else {
|
||||||
|
"L".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: TESTS
|
// TODO: TESTS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
7
test.sh
Executable file
7
test.sh
Executable file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
source venv_maturin/bin/activate
|
||||||
|
|
||||||
|
cd androscalpel
|
||||||
|
maturin develop
|
||||||
|
cd ..
|
||||||
|
python test.py
|
||||||
Loading…
Add table
Add a link
Reference in a new issue