diff --git a/androscalpel/src/dex_fragment.rs b/androscalpel/src/dex_fragment.rs index ed45a38..a506221 100644 --- a/androscalpel/src/dex_fragment.rs +++ b/androscalpel/src/dex_fragment.rs @@ -54,8 +54,8 @@ pub struct DexFragment { type_lists_with_offset: Vec<(TypeList, u32)>, /// The encoded_array_items section. encoded_array_items: Vec, - /// The annotations_directory_item section. - annotations_directory_items: Vec, + /// The annotations_directory_item. + annotations_directory_items: Option, /// The annotation_set_item section. annotation_set_items: Vec, /// The annotation item section. @@ -68,6 +68,8 @@ pub struct DexFragment { code_items: Vec, /// The debug info items section. debug_info_items: Vec, + /// The list of interfaces of the class. + interfaces: Vec, } impl DexFragment { @@ -101,11 +103,12 @@ impl DexFragment { encoded_array_items: vec![], method_handles: vec![], code_items: vec![], - annotations_directory_items: vec![], + annotations_directory_items: None, annotation_set_items: vec![], annotation_items: vec![], annotation_set_lists: vec![], debug_info_items: vec![], + interfaces: class.interfaces.clone(), }; frag.strings = class.get_all_strings().into_iter().collect(); frag.strings.sort(); @@ -150,6 +153,54 @@ impl DexFragment { frag.section_manager .add_elt(FragSection::ClassDefItem, None); + + frag.class_def.class_idx = *types_index.get(&class.descriptor).ok_or(anyhow!( + "Type {} (type of class {}) not found in type list", + class.descriptor.__repr__(), + class.__repr__() + ))? as u32; + frag.class_def.access_flags = class.get_raw_access_flags(); + frag.class_def.superclass_idx = if let Some(sup) = &class.superclass { + *types_index.get(sup).ok_or(anyhow!( + "Type {} (superclass of class {}) not found in dex builder", + sup.__repr__(), + class.__repr__() + ))? as u32 + } else { + NO_INDEX.0 + }; + frag.class_def.interfaces_off = 0; // set when linking + frag.class_def.source_file_idx = if let Some(file) = &class.source_file { + *strings_index.get(file).ok_or(anyhow!( + "String {} (source file of class {}) not found in dex builder", + file.__repr__(), + class.__repr__() + ))? as u32 + } else { + NO_INDEX.0 + }; + frag.class_def.annotations_off = if class.has_annotations() { + // TODO: frag.insert_annotations(class)?; + 1 + } else { + 0 + }; + frag.class_def.class_data_off = if class.has_data_item() { + //TODO: frag.insert_class_data_item(class_id)?; + 1 + } else { + 0 + }; + frag.class_def.static_values_off = if class.has_static_values_array() { + let static_values_off = frag + .section_manager + .get_aligned_size(FragSection::EncodedArrayItem); + // TODO: frag.insert_class_static_values(class)?; + static_values_off + 1 + } else { + 0 + }; + Ok(frag) } @@ -1947,97 +1998,6 @@ impl DexFragment { Ok(()) } - /// Insert a class_def_item in the class_defs section **and** the other struct that needs to be - /// generated on the fly. - /// - /// # Warning - /// - /// The class_defs section **MUST** be sorted by inheritance dependencies (parents classes and - /// interfaces must appear **before** child classes). Accordingly, this method must be invoked - /// in the right order. - /// - /// # Note - /// - /// annotations_directory_item, encoded_array_item and class_data_item objects are 4 bytes - /// aligns, so their offset cannot be odd. - /// - /// To distinguish prelinked value (offset inside the code_item section) to actual values (offset - /// in the whole file or 0), their value is set to the actual value prelink value + 1. This allow - /// to distinguish the offset of the first item (equal to zero before linking) and the value - /// 0 used to indicate an abscence of item. - fn insert_class_def_item(&mut self, class_id: &IdType) -> Result<()> { - let idx = self.class_defs_list.len(); - self.class_defs - .entry(class_id.clone()) - .and_modify(|(_, i)| *i = idx); - let (class, _) = self.class_defs.get(class_id).unwrap(); - let class_data_off = if class.has_data_item() { - let class_data_off = self - .section_manager - .get_aligned_size(Section::ClassDataItem); - self.insert_class_data_item(class_id)?; - class_data_off + 1 - } else { - 0 - }; - // & vs &mut cluster-f, this make rust drop the ref so self hold by `class` before - // mutating self with `insert_class_data_item`, and get a new ref afterward - let (class, _) = self.class_defs.get(class_id).unwrap(); - let static_values_off = if class.has_static_values_array() { - let static_values_off = self - .section_manager - .get_aligned_size(Section::EncodedArrayItem); - self.insert_class_static_values(class_id)?; - static_values_off + 1 - } else { - 0 - }; - let (class, _) = self.class_defs.get(class_id).unwrap(); - let annotations_off = if class.has_annotations() { - let annotations_off = self - .section_manager - .get_aligned_size(Section::AnnotationsDirectoryItem); - self.insert_annotations(class_id)?; - annotations_off + 1 - } else { - 0 - }; - let (class, _) = self.class_defs.get(class_id).unwrap(); - self.class_defs_list.push(ClassDefItem { - class_idx: *self.type_ids.get(class_id).ok_or(anyhow!( - "Type {} (type of class {}) not found in dex builder", - class_id.__repr__(), - class.__repr__() - ))? as u32, - access_flags: class.get_raw_access_flags(), - superclass_idx: if let Some(sup) = &class.superclass { - *self.type_ids.get(sup).ok_or(anyhow!( - "Type {} (superclass of class {}) not found in dex builder", - sup.__repr__(), - class.__repr__() - ))? as u32 - } else { - NO_INDEX.0 - }, - interfaces_off: 0, - source_file_idx: if let Some(file) = &class.source_file { - *self.strings.get(file).ok_or(anyhow!( - "String {} (source file of class {}) not found in dex builder", - file.__repr__(), - class.__repr__() - ))? as u32 - } else { - NO_INDEX.0 - }, - - annotations_off, // need relinking once offset of class_def_item section is known - class_data_off, // need relinking once offset of class_data section is known - static_values_off, // need relinking once offset of encoded_array section is known - }); - self.section_manager.add_elt(Section::ClassDefItem, None); - Ok(()) - } - fn gen_type_list_section(&mut self) -> Result<()> { debug!("Generate the type_list section"); // Collect all type lists @@ -2781,7 +2741,9 @@ impl FragSectionManager { if !self.editable { panic!("Try to modify a section when the sections are set to read only"); } - if (section == FragSection::ClassDefItem || section == FragSection::ClassDataItem) + if (section == FragSection::ClassDefItem + || section == FragSection::ClassDataItem + || section == FragSection::AnnotationsDirectoryItem) && (self.nb_elt[section.get_index()] >= 1) { panic!("{section:#?} cannot contain more than one element in a dex fragment");