diff --git a/androscalpel/src/apk.rs b/androscalpel/src/apk.rs index 3cfe6ae..01d8547 100644 --- a/androscalpel/src/apk.rs +++ b/androscalpel/src/apk.rs @@ -3307,4 +3307,64 @@ impl Apk { })) } } + + /// Merget two application into one. + pub fn merge(&mut self, Self { mut dex_files }: Self) -> Result<()> { + let mut i = 0; + let mut name: String = "classes.dex".into(); + while self.dex_files.contains_key(&name) { + i += 1; + name = format!("classes{}.dex", i + 1); + } + let mut j = 0; + let mut other_name: String = "classes.dex".into(); + while let Some(file) = dex_files.remove(&other_name) { + self.dex_files.insert(name.clone(), file); + j += 1; + other_name = format!("classes{}.dex", j + 1); + while self.dex_files.contains_key(&name) { + i += 1; + name = format!("classes{}.dex", i + 1); + } + } + + // Maybe not a good idea reinserting invalid .dex as valid ones, so explicitly skip one + // index to keep the files invalids. + i += 1; + name = format!("classes{}.dex", i + 1); + while self.dex_files.contains_key(&name) { + i += 1; + name = format!("classes{}.dex", i + 1); + } + + for (other_name, dex) in dex_files.into_iter() { + if get_dex_name_index(&other_name).is_some() { + self.dex_files.insert(name.clone(), dex); + while self.dex_files.contains_key(&name) { + i += 1; + name = format!("classes{}.dex", i + 1); + } + } else { + let mut new_name = other_name.clone(); + let mut k = 1; + while self.dex_files.contains_key(&new_name) { + k += 1; + new_name = format!("{other_name}-{k}") + } + self.dex_files.insert(new_name, dex); + } + } + Ok(()) + } +} + +/// Parse a .dex file name, and if it is a valid android file, return the index of the file. +fn get_dex_name_index(name: &str) -> Option { + if name == "classes.dex" { + return Some(0); + } + name.strip_prefix("classes") + .and_then(|name| name.strip_suffix(".dex")) + .and_then(|name| name.parse::().ok()) + .and_then(|idx| if idx <= 1 { None } else { Some(idx - 1) }) }