add a rought implem of code

This commit is contained in:
Jean-Marie Mineau 2023-11-30 14:40:49 +01:00
parent 026b9ddd41
commit 80968c9bcf
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
7 changed files with 198 additions and 13 deletions

View file

@ -1,6 +1,6 @@
//! Representation of an apk.
use anyhow::{anyhow, Result};
use anyhow::{anyhow, Context, Result};
use std::collections::HashMap;
use log::info;
@ -280,7 +280,7 @@ impl Apk {
))
}
/// Return a [`Vec<DexAnnotationItem>`] for the offset of an [`AnnotationSet`].
/// Return a [`Vec<DexAnnotationItem>`] for the offset of an [`AnnotationSetItem`].
pub fn get_annotation_items_from_annotation_set_off(
annotations_set_off: u32,
dex: &DexFileReader,
@ -577,7 +577,7 @@ impl Apk {
pub fn get_method_from_idx(
idx: usize,
Uleb128(access_flags): Uleb128,
Uleb128(_code_off): Uleb128,
Uleb128(code_off): Uleb128,
dex: &DexFileReader,
) -> Result<Method> {
let descriptor = Self::get_id_method_from_idx(idx, dex)?;
@ -648,6 +648,13 @@ impl Apk {
| ACC_DECLARED_SYNCHRONIZED)
);
}
let code = if code_off == 0 {
None
} else {
Some(Self::get_code_from_off(code_off, dex).with_context(|| {
format!("Failed to parse code of method {}", descriptor.__str__())
})?)
};
Ok(Method {
descriptor,
@ -665,7 +672,56 @@ impl Apk {
is_declared_syncrhonized,
annotations: vec![],
parameters_annotations: vec![],
code: (),
code,
})
}
/// Return a [`Code`] from it's offset in the dex file.
pub fn get_code_from_off(offset: u32, dex: &DexFileReader) -> Result<Code> {
let code_item = dex.get_struct_at_offset::<CodeItem>(offset)?;
let debug_info = if code_item.debug_info_off == 0 {
vec![]
} else {
dex.get_struct_at_offset::<DebugInfoItem>(code_item.debug_info_off)?
.serialize_to_vec()? // no dealing with that right now
};
let mut tries = vec![];
for TryItem {
start_addr,
insn_count,
handler_off,
} in code_item.tries
{
tries.push((start_addr, insn_count, handler_off));
}
let mut handlers_aux = vec![];
if let Some(EncodedCatchHandlerList { list }) = code_item.handlers {
for EncodedCatchHandler {
handlers,
catch_all_addr,
} in list
{
let mut handlers_ = vec![];
let catch_all_addr = catch_all_addr.map(|Uleb128(val)| val);
for EncodedTypeAddrPair {
type_idx: Uleb128(type_idx),
addr: Uleb128(addr),
} in handlers
{
handlers_.push((Self::get_id_type_from_idx(type_idx as usize, dex)?, addr))
}
handlers_aux.push((handlers_, catch_all_addr));
}
}
let handlers = handlers_aux;
Ok(Code {
registers_size: code_item.registers_size,
ins_size: code_item.ins_size,
outs_size: code_item.outs_size,
debug_info,
insns: code_item.insns,
tries,
handlers,
})
}

63
androscalpel/src/code.rs Normal file
View file

@ -0,0 +1,63 @@
//! Representation of a method.
use pyo3::prelude::*;
use crate::IdType;
// TODO: make this easy to edit/manipulate, maybe move to Method
type TmpHandlerType = (Vec<(IdType, u32)>, Option<u32>);
/// The code run by a method.
#[pyclass]
#[derive(Debug, Clone)]
pub struct Code {
// TODO: remove and compute this value from code.
/// The number of registers used by the code
#[pyo3(get, set)]
pub registers_size: u16,
// TODO: what does it means? is it computable?
/// The number of words of incoming arguments to the method
#[pyo3(get, set)]
pub ins_size: u16,
// TODO: what does it means? is it computable?
/// The number of words of outgoing argument space
#[pyo3(get, set)]
pub outs_size: u16,
// TODO: implement
/// The debug info
#[pyo3(get, set)]
pub debug_info: Vec<u8>,
// TODO: implement OPcode
/// The instructions.
#[pyo3(get, set)]
pub insns: Vec<u16>,
// TODO: currently unusable, juste a mapping ty TryItem
// TODO: maybe implement as custom OPcode to make me easy to modify?
/// Try blocks
#[pyo3(get, set)]
pub tries: Vec<(u32, u16, u16)>,
// TODO: currently unusable, juste a mapping ty TryItem
// TODO: maybe implement as custom OPcode to make me easy to modify?
/// The handlers associated to the tries blocks.
#[pyo3(get, set)]
pub handlers: Vec<TmpHandlerType>,
}
#[pymethods]
impl Code {
/*
#[new]
pub fn new() -> Self {
todo!()
}
*/
pub fn __str__(&self) -> String {
self.__repr__()
}
pub fn __repr__(&self) -> String {
"Code()".into()
}
}

View file

@ -5,6 +5,7 @@ use pyo3::prelude::*;
pub mod annotation;
pub mod apk;
pub mod class;
pub mod code;
pub mod dex_id;
pub mod dex_string;
pub mod field;
@ -16,6 +17,7 @@ pub mod value;
pub use annotation::*;
pub use apk::*;
pub use class::*;
pub use code::*;
pub use dex_id::*;
pub use dex_string::*;
pub use field::*;
@ -63,6 +65,7 @@ fn androscalpel(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<Method>()?;
m.add_class::<Field>()?;
m.add_class::<Class>()?;
m.add_class::<Code>()?;
m.add_class::<Apk>()?;
Ok(())
}

View file

@ -2,7 +2,7 @@
use pyo3::prelude::*;
use crate::{DexAnnotationItem, IdMethod};
use crate::{Code, DexAnnotationItem, IdMethod};
/// Represent a method.
#[pyclass]
@ -57,7 +57,7 @@ pub struct Method {
pub parameters_annotations: Vec<Vec<DexAnnotationItem>>,
/// The code of the method
pub code: (),
pub code: Option<Code>,
}
/// Represent the visibility of a field
@ -74,6 +74,7 @@ pub enum MethodVisibility {
impl Method {
#[new]
pub fn new(descriptor: IdMethod) -> Self {
// TODO: take code option as arg and set the default flags accordingly
Self {
descriptor,
visibility: MethodVisibility::Public,
@ -90,7 +91,7 @@ impl Method {
is_declared_syncrhonized: false,
annotations: vec![],
parameters_annotations: vec![],
code: (),
code: None,
}
}