This commit is contained in:
Jean-Marie Mineau 2025-01-15 17:25:26 +01:00
parent dfcd6232a4
commit 1d62277f42
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
5 changed files with 92 additions and 15 deletions

23
Cargo.lock generated
View file

@ -26,6 +26,7 @@ dependencies = [
"anyhow", "anyhow",
"apk_frauder", "apk_frauder",
"log", "log",
"pretty_assertions",
"pyo3", "pyo3",
"pyo3-log", "pyo3-log",
"rayon", "rayon",
@ -180,6 +181,12 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.10.7" version = "0.10.7"
@ -347,6 +354,16 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 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]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.78" version = "1.0.78"
@ -668,3 +685,9 @@ name = "windows_x86_64_msvc"
version = "0.48.5" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "yansi"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"

View file

@ -21,6 +21,8 @@ serde = { version = "1.0.195", features = ["derive"] }
serde_json = "1.0.111" serde_json = "1.0.111"
sha1 = "0.10.6" sha1 = "0.10.6"
[dev-dependencies]
pretty_assertions = "1.4.1"
#[features] #[features]
#extension-module = ["pyo3/extension-module"] #extension-module = ["pyo3/extension-module"]

View file

@ -830,32 +830,32 @@ impl Apk {
let ins = match format.clone() { let ins = match format.clone() {
Format10X { op: 0x00 } => Instruction::Nop {}, Format10X { op: 0x00 } => Instruction::Nop {},
Format12X { op: 0x01, va, vb } => Instruction::Move { Format12X { op: 0x01, va, vb } => Instruction::Move {
from: va as u16, to: va as u16,
to: vb as u16, from: vb as u16,
}, },
Format22X { op: 0x02, va, vb } => Instruction::Move { Format22X { op: 0x02, va, vb } => Instruction::Move {
from: va as u16, to: va as u16,
to: vb, 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 { Format12X { op: 0x04, va, vb } => Instruction::MoveWide {
from: va as u16, to: va as u16,
to: vb as u16, from: vb as u16,
}, },
Format22X { op: 0x05, va, vb } => Instruction::MoveWide { Format22X { op: 0x05, va, vb } => Instruction::MoveWide {
from: va as u16, to: va as u16,
to: vb, 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 { Format12X { op: 0x07, va, vb } => Instruction::MoveObject {
from: va as u16, to: va as u16,
to: vb as u16, from: vb as u16,
}, },
Format22X { op: 0x08, va, vb } => Instruction::MoveObject { Format22X { op: 0x08, va, vb } => Instruction::MoveObject {
from: va as u16, to: va as u16,
to: vb, 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: 0x0a, va } => Instruction::MoveResult { to: va },
Format11X { op: 0x0b, va } => Instruction::MoveResultWide { to: va }, Format11X { op: 0x0b, va } => Instruction::MoveResultWide { to: va },
Format11X { op: 0x0c, va } => Instruction::MoveResultObject { 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, /// 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 /// 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 /// classesN.dex does not exists), and if `valid_file_only` is set to false, look in any

View file

@ -70,6 +70,16 @@ pub struct Method {
#[pyo3(get)] #[pyo3(get)]
pub code: Option<Code>, pub code: Option<Code>,
} }
/*
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 /// Represent the visibility of a field
#[pyclass] #[pyclass]

View file

@ -10,6 +10,8 @@ use std::ops::Deref;
use std::sync::{Mutex, OnceLock}; use std::sync::{Mutex, OnceLock};
use std::time::Instant; use std::time::Instant;
//use pretty_assertions::assert_eq;
fn write_to_report(data: &str) { fn write_to_report(data: &str) {
static REPORT_FILE: Mutex<Option<File>> = Mutex::new(None); static REPORT_FILE: Mutex<Option<File>> = Mutex::new(None);
let mut report_file = REPORT_FILE.lock().unwrap(); let mut report_file = REPORT_FILE.lock().unwrap();
@ -144,6 +146,29 @@ fn test_generated_apk_equivalence() {
new_apk new_apk
.add_dex_file("classes.dex", &new_dex, false, false) .add_dex_file("classes.dex", &new_dex, false, false)
.unwrap(); .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); assert_eq!(get_hello_world_apk(), &new_apk);
} }