From 68b11dc036ddbac16b939f80e56a0aebbce8ebba Mon Sep 17 00:00:00 2001 From: Jean-Marie 'Histausse' Mineau Date: Thu, 31 Aug 2023 16:01:31 +0200 Subject: [PATCH] WIP --- androscalpel/src/apk.rs | 73 ++++++++++++++++++++-- androscalpel/src/class.rs | 5 +- androscalpel_serializer/src/file_reader.rs | 19 +++++- androscalpel_serializer/src/items/class.rs | 5 +- androscalpel_serializer/src/items/mod.rs | 1 + 5 files changed, 91 insertions(+), 12 deletions(-) diff --git a/androscalpel/src/apk.rs b/androscalpel/src/apk.rs index dc30bf3..c41bf15 100644 --- a/androscalpel/src/apk.rs +++ b/androscalpel/src/apk.rs @@ -1,8 +1,8 @@ //! Representation of an apk. use pyo3::prelude::*; -use crate::{Class, Result}; -use androscalpel_serializer::{ClassDefItem, DexFileReader}; +use crate::{Class, Error, Result}; +use androscalpel_serializer::{ClassDefItem, DexFileReader, TypeList, NO_INDEX}; /// Represent an apk. #[pyclass] @@ -15,7 +15,10 @@ pub struct Apk { impl Apk { /// Add the content of a dex file to the apk. pub fn add_dex_file(&mut self, data: &[u8]) -> Result<()> { + println!("Start parsing file"); let dex = DexFileReader::new(data)?; + println!("Header and lists parsed"); + println!("Start parsing classes"); for class in dex.get_class_defs() { self.add_class_from_dex_file(class, &dex)?; } @@ -23,8 +26,65 @@ impl Apk { } /// Add a class from a dex file reader. - fn add_class_from_dex_file(&mut self, class: &ClassDefItem, dex: &DexFileReader) -> Result<()> { - todo!() + fn add_class_from_dex_file( + &mut self, + class_item: &ClassDefItem, + dex: &DexFileReader, + ) -> Result<()> { + let name_idx = dex + .get_type_ids() + .get(class_item.class_idx as usize) + .ok_or(Error::InconsistantStruct(format!( + "type idx {} out of bound of type_ids (|type_ids| = {})", + class_item.class_idx, + dex.get_type_ids().len() + )))? + .descriptor_idx; + let name = dex.get_string(name_idx)?.into(); + let superclass = if class_item.class_idx == NO_INDEX.0 { + None + } else { + let superclass_idx = dex + .get_type_ids() + .get(class_item.class_idx as usize) + .ok_or(Error::InconsistantStruct(format!( + "type idx {} out of bound of type_ids (|type_ids| = {})", + class_item.class_idx, + dex.get_type_ids().len() + )))? + .descriptor_idx; + Some(dex.get_string(superclass_idx)?.into()) + }; + let interfaces = if class_item.interfaces_off == 0 { + vec![] + } else { + let type_list = dex.get_struct_at_offset::(class_item.interfaces_off)?; + let mut list = vec![]; + for ty in type_list.list { + let ty = dex.get_type_ids().get(ty.type_idx as usize).ok_or( + Error::InconsistantStruct(format!( + "type idx {} out of bound of type_ids (|type_ids| = {})", + ty.type_idx, + dex.get_type_ids().len() + )), + )?; + let ty = dex.get_string(ty.descriptor_idx)?.into(); + list.push(ty); + } + list + }; + let source_file = if class_item.source_file_idx == NO_INDEX.0 { + None + } else { + Some(dex.get_string(class_item.source_file_idx)?.into()) + }; + self.classes.push(Class { + name, + superclass, + interfaces, + source_file, + }); + Ok(()) } } @@ -32,6 +92,11 @@ impl Apk { impl Apk { #[new] fn new() -> Self { + println!("Create APK"); Self { classes: vec![] } } + + fn py_add_dex_file(&mut self, data: &[u8]) -> Result<()> { + self.add_dex_file(data) + } } diff --git a/androscalpel/src/class.rs b/androscalpel/src/class.rs index 80d1600..b7d750c 100644 --- a/androscalpel/src/class.rs +++ b/androscalpel/src/class.rs @@ -10,8 +10,6 @@ use crate::DexString; pub struct Class { #[pyo3(get, set)] pub name: DexString, - #[pyo3(get, set)] - pub ty: DexString, // pub access_flags: // TODO #[pyo3(get, set)] pub superclass: Option, @@ -28,10 +26,9 @@ pub struct Class { #[pymethods] impl Class { #[new] - pub fn new(name: DexString, ty: DexString) -> Self { + pub fn new(name: DexString) -> Self { Self { name, - ty, superclass: None, interfaces: vec![], source_file: None, diff --git a/androscalpel_serializer/src/file_reader.rs b/androscalpel_serializer/src/file_reader.rs index 91d7357..5b116a5 100644 --- a/androscalpel_serializer/src/file_reader.rs +++ b/androscalpel_serializer/src/file_reader.rs @@ -2,8 +2,8 @@ use crate::{ CallSiteIdItem, ClassDefItem, EndianConstant, Error, FieldIdItem, HeaderItem, MapItemType, - MapList, MethodHandleItem, MethodIdItem, ProtoIdItem, Result, Serializable, StringIdItem, - TypeIdItem, + MapList, MethodHandleItem, MethodIdItem, ProtoIdItem, Result, Serializable, StringDataItem, + StringIdItem, TypeIdItem, }; use std::io::{Cursor, Seek, SeekFrom}; @@ -127,6 +127,21 @@ impl<'a> DexFileReader<'a> { &self.map_list } + /// Return the [`StringDataItem`] of from its idx. + pub fn get_string(&self, idx: u32) -> Result { + let id = self + .string_ids + .get(idx as usize) + .ok_or(Error::InconsistantStruct(format!( + "string idx {idx} is out of bound (|string_ids|={})", + self.string_ids.len() + )))?; + self.get_struct_at_offset(id.string_data_off) + .map_err(|err| { + Error::DeserializationError(format!("Failled to parse string {idx}: {err}")) + }) + } + fn sanity_check(&self) -> Result<()> { if self.header.magic.version != [0x30, 0x33, 0x39] { println!( diff --git a/androscalpel_serializer/src/items/class.rs b/androscalpel_serializer/src/items/class.rs index 2d85389..981a13d 100644 --- a/androscalpel_serializer/src/items/class.rs +++ b/androscalpel_serializer/src/items/class.rs @@ -12,7 +12,8 @@ pub struct ClassDefItem { pub class_idx: u32, /// See pub access_flags: u32, - /// Either index of a [`crate::TypeIdItem`] in `type_ids`, must be a class or NO_INDEX + /// Either index of a [`crate::TypeIdItem`] in `type_ids`, must be a class or + /// [`crate::NO_INDEX`] pub superclass_idx: u32, /// 0 if no interfaces, else offset to a [`crate::TypeList`]. pub interfaces_off: u32, @@ -247,6 +248,6 @@ impl Serializable for TypeList { /// #[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)] pub struct TypeItem { - /// Index into the `type_ids` list. + /// Index of a [`crate::TypeIdItem`] in the `type_ids` list. pub type_idx: u16, } diff --git a/androscalpel_serializer/src/items/mod.rs b/androscalpel_serializer/src/items/mod.rs index 15d60f1..551caac 100644 --- a/androscalpel_serializer/src/items/mod.rs +++ b/androscalpel_serializer/src/items/mod.rs @@ -19,6 +19,7 @@ pub use map::*; /// alignment: 4 bytes #[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)] pub struct StringIdItem { + /// Offset of a [`crate::StringDataItem`]. pub string_data_off: u32, }