diff --git a/androscalpel/src/code.rs b/androscalpel/src/code.rs index 94d1dae..72456f9 100644 --- a/androscalpel/src/code.rs +++ b/androscalpel/src/code.rs @@ -101,10 +101,8 @@ impl Code { strings.extend(ins.get_all_strings()); } if let Some(names) = &self.parameter_names { - for name in names { - if let Some(name) = name { - strings.insert(name.clone()); - } + for name in names.iter().flatten() { + strings.insert(name.clone()); } } strings diff --git a/androscalpel/src/instructions.rs b/androscalpel/src/instructions.rs index 70a2a3b..f7f044c 100644 --- a/androscalpel/src/instructions.rs +++ b/androscalpel/src/instructions.rs @@ -14907,7 +14907,7 @@ impl InvokeVirtual { vd, vf, vg, - b: meth_idx as u16, + b: meth_idx, } } else if consec && len <= 255 { let a = self.args.len() as u8; diff --git a/androscalpel/src/lib.rs b/androscalpel/src/lib.rs index 3ece94a..c8bdb61 100644 --- a/androscalpel/src/lib.rs +++ b/androscalpel/src/lib.rs @@ -1,3 +1,6 @@ +#![allow(clippy::unnecessary_fallible_conversions)] +// DexString has Into but it's only for +// python, TryInto should be prefered use anyhow::Result; use pyo3::prelude::*; diff --git a/androscalpel/src/py_utils.rs b/androscalpel/src/py_utils.rs index 2d7a61a..9a641a1 100644 --- a/androscalpel/src/py_utils.rs +++ b/androscalpel/src/py_utils.rs @@ -3,11 +3,15 @@ use pyo3::prelude::*; use pyo3::types::PyBytes; -use std::io::Cursor; +use std::collections::HashSet; +use std::io::{Cursor, Seek, SeekFrom}; use std::path::PathBuf; -use crate::Result; -use androscalpel_serializer::{Serializable, Sleb128, Uleb128, Uleb128p1}; +use crate::{Apk, IdType, Result}; +use androscalpel_serializer::{ + DexFileReader, HeaderItem, Serializable, Sleb128, Uleb128, Uleb128p1, +}; +use apk_frauder::{end_of_central_directory::EndCentralDirectory, ZipFileReader}; /// Convert an integer to the uleb128 byte encoding #[pyfunction] @@ -44,6 +48,46 @@ pub fn sleb128_to_int(b: &[u8]) -> Result { Ok(Sleb128::deserialize_from_slice(b)?.0) } +// TODO: list_defined_classes, is_dex, is_zip take &[u8], but should allow to also read from file + +/// List all classes defined in a dex file. +#[pyfunction] +pub fn list_defined_classes(dex: &[u8]) -> Result> { + let dex = DexFileReader::new(dex)?; + dex.get_class_defs() + .iter() + .map(|cdef| Apk::get_id_type_from_idx(cdef.class_idx as usize, &dex)) + .collect() +} + +/// Test if a file is as .dex file an return the dex version if it is, else return None. +#[pyfunction] +pub fn is_dex(file: &[u8]) -> Option { + HeaderItem::deserialize_from_slice(file) + .ok() + .and_then(|header| String::from_utf8(header.magic.version.to_vec()).ok()) + .and_then(|version| version.parse::().ok()) +} + +/// Test if a file is a zip file. +#[pyfunction] +pub fn is_zip(file: &[u8]) -> bool { + let mut file = Cursor::new(file); + let ecd_off = if let Some(off) = ZipFileReader::get_end_of_central_directory_offset(&mut file) { + off + } else { + return false; + }; + if file.seek(SeekFrom::Start(ecd_off)).is_err() { + return false; + } + if let Ok(sig) = apk_frauder::Signature::deserialize(&mut file) { + EndCentralDirectory::SIGNATURE == sig + } else { + false + } +} + /// Replace the dex files a an apk an resigned the apk. /// /// # Warning