From 1d62277f42f144c43f7f7ecfd54e671c8e0eb0a8 Mon Sep 17 00:00:00 2001 From: Jean-Marie Mineau Date: Wed, 15 Jan 2025 17:25:26 +0100 Subject: [PATCH] WIP --- Cargo.lock | 23 +++++++++++++++++ androscalpel/Cargo.toml | 2 ++ androscalpel/src/apk.rs | 47 ++++++++++++++++++++++++----------- androscalpel/src/method.rs | 10 ++++++++ androscalpel/src/tests/mod.rs | 25 +++++++++++++++++++ 5 files changed, 92 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c2f98c..5cc9001 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,7 @@ dependencies = [ "anyhow", "apk_frauder", "log", + "pretty_assertions", "pyo3", "pyo3-log", "rayon", @@ -180,6 +181,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.10.7" @@ -347,6 +354,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "proc-macro2" version = "1.0.78" @@ -668,3 +685,9 @@ name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" diff --git a/androscalpel/Cargo.toml b/androscalpel/Cargo.toml index 8e1338e..795ce66 100644 --- a/androscalpel/Cargo.toml +++ b/androscalpel/Cargo.toml @@ -21,6 +21,8 @@ serde = { version = "1.0.195", features = ["derive"] } serde_json = "1.0.111" sha1 = "0.10.6" +[dev-dependencies] +pretty_assertions = "1.4.1" #[features] #extension-module = ["pyo3/extension-module"] diff --git a/androscalpel/src/apk.rs b/androscalpel/src/apk.rs index 0d2b9a5..c84ce14 100644 --- a/androscalpel/src/apk.rs +++ b/androscalpel/src/apk.rs @@ -830,32 +830,32 @@ impl Apk { let ins = match format.clone() { Format10X { op: 0x00 } => Instruction::Nop {}, Format12X { op: 0x01, va, vb } => Instruction::Move { - from: va as u16, - to: vb as u16, + to: va as u16, + from: vb as u16, }, Format22X { op: 0x02, va, vb } => Instruction::Move { - from: va as u16, - to: vb, + to: va as u16, + from: vb, }, - Format32X { op: 0x03, va, vb } => Instruction::Move { from: va, to: vb }, + Format32X { op: 0x03, va, vb } => Instruction::Move { to: va, from: vb }, Format12X { op: 0x04, va, vb } => Instruction::MoveWide { - from: va as u16, - to: vb as u16, + to: va as u16, + from: vb as u16, }, Format22X { op: 0x05, va, vb } => Instruction::MoveWide { - from: va as u16, - to: vb, + to: va as u16, + from: vb, }, - Format32X { op: 0x06, va, vb } => Instruction::MoveWide { from: va, to: vb }, + Format32X { op: 0x06, va, vb } => Instruction::MoveWide { to: va, from: vb }, Format12X { op: 0x07, va, vb } => Instruction::MoveObject { - from: va as u16, - to: vb as u16, + to: va as u16, + from: vb as u16, }, Format22X { op: 0x08, va, vb } => Instruction::MoveObject { - from: va as u16, - to: vb, + to: va as u16, + from: vb, }, - Format32X { op: 0x09, va, vb } => Instruction::MoveObject { from: va, to: vb }, + Format32X { op: 0x09, va, vb } => Instruction::MoveObject { to: va, from: vb }, Format11X { op: 0x0a, va } => Instruction::MoveResult { to: va }, Format11X { op: 0x0b, va } => Instruction::MoveResultWide { to: va }, Format11X { op: 0x0c, va } => Instruction::MoveResultObject { to: va }, @@ -2948,6 +2948,23 @@ impl Apk { }) } + // TODO: check for android platform classes? + /// Search for the given class. If several classes with the same name are found, + /// return the class used by android (classes.dex over classes2.dex over classes3.dex until + /// classesN.dex does not exists), + /// and if not found in files used by android, look in any other files (classes0.dex, + /// classses1.dex, classes02.dex, assets/stuff.dex, ...), and select the first one in + /// alphabetical order of dex file name. + pub fn get_class(&self, class_id: &IdType) -> Option<&Class> { + self.get_file_of_class(class_id, false).and_then(|file| { + self.dex_files + .get(&file) + .expect("`get_file_of_class()` return a string not in `dex_files`") + .classes + .get(class_id) + }) + } + /// Search for the dex file of a given class. If several classes with the same name exist, /// return the file used by android (classes.dex over classes2.dex over classes3.dex until /// classesN.dex does not exists), and if `valid_file_only` is set to false, look in any diff --git a/androscalpel/src/method.rs b/androscalpel/src/method.rs index 585b368..94c54bf 100644 --- a/androscalpel/src/method.rs +++ b/androscalpel/src/method.rs @@ -70,6 +70,16 @@ pub struct Method { #[pyo3(get)] pub code: Option, } +/* +impl PartialEq for Method { + fn eq(&self, other: &Self) -> bool { + let res = self.code.eq(other.code); + if !res { + panic!("{} code don't match", self.descriptor.__str__()); + } + return res; + } +}*/ /// Represent the visibility of a field #[pyclass] diff --git a/androscalpel/src/tests/mod.rs b/androscalpel/src/tests/mod.rs index d43485e..9ca6ac2 100644 --- a/androscalpel/src/tests/mod.rs +++ b/androscalpel/src/tests/mod.rs @@ -10,6 +10,8 @@ use std::ops::Deref; use std::sync::{Mutex, OnceLock}; use std::time::Instant; +//use pretty_assertions::assert_eq; + fn write_to_report(data: &str) { static REPORT_FILE: Mutex> = Mutex::new(None); let mut report_file = REPORT_FILE.lock().unwrap(); @@ -144,6 +146,29 @@ fn test_generated_apk_equivalence() { new_apk .add_dex_file("classes.dex", &new_dex, false, false) .unwrap(); + /* + let method = IdMethod::from_smali( + "Lkotlinx/coroutines/flow/internal/SafeCollector_commonKt$unsafeFlow$1$collect$1;->\ + invokeSuspend(\ + Ljava/lang/Object;\ + )\ + Ljava/lang/Object;", + ) + .unwrap(); + assert_eq!( + get_hello_world_apk() + .get_class(&method.class_) + .unwrap() + .virtual_methods + .get(&method) + .unwrap(), + new_apk + .get_class(&method.class_) + .unwrap() + .virtual_methods + .get(&method) + .unwrap() + );*/ assert_eq!(get_hello_world_apk(), &new_apk); }