This commit is contained in:
Jean-Marie 'Histausse' Mineau 2023-08-31 16:01:31 +02:00
parent 559ae665cf
commit 68b11dc036
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
5 changed files with 91 additions and 12 deletions

View file

@ -1,8 +1,8 @@
//! Representation of an apk. //! Representation of an apk.
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::{Class, Result}; use crate::{Class, Error, Result};
use androscalpel_serializer::{ClassDefItem, DexFileReader}; use androscalpel_serializer::{ClassDefItem, DexFileReader, TypeList, NO_INDEX};
/// Represent an apk. /// Represent an apk.
#[pyclass] #[pyclass]
@ -15,7 +15,10 @@ pub struct Apk {
impl Apk { impl Apk {
/// Add the content of a dex file to the apk. /// Add the content of a dex file to the apk.
pub fn add_dex_file(&mut self, data: &[u8]) -> Result<()> { pub fn add_dex_file(&mut self, data: &[u8]) -> Result<()> {
println!("Start parsing file");
let dex = DexFileReader::new(data)?; let dex = DexFileReader::new(data)?;
println!("Header and lists parsed");
println!("Start parsing classes");
for class in dex.get_class_defs() { for class in dex.get_class_defs() {
self.add_class_from_dex_file(class, &dex)?; self.add_class_from_dex_file(class, &dex)?;
} }
@ -23,8 +26,65 @@ impl Apk {
} }
/// Add a class from a dex file reader. /// Add a class from a dex file reader.
fn add_class_from_dex_file(&mut self, class: &ClassDefItem, dex: &DexFileReader) -> Result<()> { fn add_class_from_dex_file(
todo!() &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::<TypeList>(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 { impl Apk {
#[new] #[new]
fn new() -> Self { fn new() -> Self {
println!("Create APK");
Self { classes: vec![] } Self { classes: vec![] }
} }
fn py_add_dex_file(&mut self, data: &[u8]) -> Result<()> {
self.add_dex_file(data)
}
} }

View file

@ -10,8 +10,6 @@ use crate::DexString;
pub struct Class { pub struct Class {
#[pyo3(get, set)] #[pyo3(get, set)]
pub name: DexString, pub name: DexString,
#[pyo3(get, set)]
pub ty: DexString,
// pub access_flags: // TODO // pub access_flags: // TODO
#[pyo3(get, set)] #[pyo3(get, set)]
pub superclass: Option<DexString>, pub superclass: Option<DexString>,
@ -28,10 +26,9 @@ pub struct Class {
#[pymethods] #[pymethods]
impl Class { impl Class {
#[new] #[new]
pub fn new(name: DexString, ty: DexString) -> Self { pub fn new(name: DexString) -> Self {
Self { Self {
name, name,
ty,
superclass: None, superclass: None,
interfaces: vec![], interfaces: vec![],
source_file: None, source_file: None,

View file

@ -2,8 +2,8 @@
use crate::{ use crate::{
CallSiteIdItem, ClassDefItem, EndianConstant, Error, FieldIdItem, HeaderItem, MapItemType, CallSiteIdItem, ClassDefItem, EndianConstant, Error, FieldIdItem, HeaderItem, MapItemType,
MapList, MethodHandleItem, MethodIdItem, ProtoIdItem, Result, Serializable, StringIdItem, MapList, MethodHandleItem, MethodIdItem, ProtoIdItem, Result, Serializable, StringDataItem,
TypeIdItem, StringIdItem, TypeIdItem,
}; };
use std::io::{Cursor, Seek, SeekFrom}; use std::io::{Cursor, Seek, SeekFrom};
@ -127,6 +127,21 @@ impl<'a> DexFileReader<'a> {
&self.map_list &self.map_list
} }
/// Return the [`StringDataItem`] of from its idx.
pub fn get_string(&self, idx: u32) -> Result<StringDataItem> {
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<()> { fn sanity_check(&self) -> Result<()> {
if self.header.magic.version != [0x30, 0x33, 0x39] { if self.header.magic.version != [0x30, 0x33, 0x39] {
println!( println!(

View file

@ -12,7 +12,8 @@ pub struct ClassDefItem {
pub class_idx: u32, pub class_idx: u32,
/// See <https://source.android.com/docs/core/runtime/dex-format#access-flags> /// See <https://source.android.com/docs/core/runtime/dex-format#access-flags>
pub access_flags: u32, 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, pub superclass_idx: u32,
/// 0 if no interfaces, else offset to a [`crate::TypeList`]. /// 0 if no interfaces, else offset to a [`crate::TypeList`].
pub interfaces_off: u32, pub interfaces_off: u32,
@ -247,6 +248,6 @@ impl Serializable for TypeList {
/// <https://source.android.com/docs/core/runtime/dex-format#type-item-format> /// <https://source.android.com/docs/core/runtime/dex-format#type-item-format>
#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)] #[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)]
pub struct TypeItem { pub struct TypeItem {
/// Index into the `type_ids` list. /// Index of a [`crate::TypeIdItem`] in the `type_ids` list.
pub type_idx: u16, pub type_idx: u16,
} }

View file

@ -19,6 +19,7 @@ pub use map::*;
/// alignment: 4 bytes /// alignment: 4 bytes
#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)] #[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)]
pub struct StringIdItem { pub struct StringIdItem {
/// Offset of a [`crate::StringDataItem`].
pub string_data_off: u32, pub string_data_off: u32,
} }