diff --git a/TODO.md b/TODO.md index 392a652..5cb22cb 100644 --- a/TODO.md +++ b/TODO.md @@ -7,5 +7,14 @@ - name register / parameters # frag meth -- insert_class_data_item - insert_class_static_values + +# relink + +data.static_fields: field_idx_diff +data.direct_methods: method_idx_diff +data.code_off +code_item.try_item +instr + +EncodedValue diff --git a/androscalpel/src/dex_fragment.rs b/androscalpel/src/dex_fragment.rs index 6a0cabe..27bc792 100644 --- a/androscalpel/src/dex_fragment.rs +++ b/androscalpel/src/dex_fragment.rs @@ -1,8 +1,7 @@ //! The structure that generate a .dex from classes. -use std::collections::{HashMap, HashSet, VecDeque}; -use std::io; -use std::io::{Cursor, Seek, SeekFrom, Write}; +use std::collections::HashMap; +use std::io::Cursor; use anyhow::{anyhow, bail, Context}; use log::debug; @@ -24,8 +23,8 @@ use androscalpel_serializer::Instruction as InsFormat; /// level format. #[derive(Debug, Clone)] pub struct DexFragment { - /// The id of the class represented by this fragment. - class_id: IdType, + // /// The id of the class represented by this fragment. + // class_id: IdType, /// The strings in the dex file, sorted. strings: Vec, /// The types in the dex file, sorted. @@ -48,10 +47,10 @@ pub struct DexFragment { class_data: Option, // TODO: type list should be handle like other ids // TODO: type list inside of proto ids are not handled here - /// The type lists found in the classes associated to their index in the type_lists section. - type_lists_index: HashMap, - /// The type_lists section and the offset of the lists inside the section. - type_lists_with_offset: Vec<(TypeList, u32)>, + // /// The type lists found in the classes associated to their index in the type_lists section. + // type_lists_index: HashMap, + // /// The type_lists section and the offset of the lists inside the section. + // type_lists_with_offset: Vec<(TypeList, u32)>, /// The encoded_array_items section. encoded_array_items: Vec, /// The annotations_directory_item. @@ -79,7 +78,7 @@ impl DexFragment { class.descriptor.__str__() ); let mut frag = Self { - class_id: class.descriptor.clone(), + //class_id: class.descriptor.clone(), strings: vec![], type_ids: vec![], proto_ids: vec![], @@ -98,8 +97,8 @@ impl DexFragment { call_site_ids: vec![], section_manager: FragSectionManager::default(), class_data: None, - type_lists_index: HashMap::new(), - type_lists_with_offset: vec![], + // type_lists_index: HashMap::new(), + // type_lists_with_offset: vec![], encoded_array_items: vec![], method_handles: vec![], code_items: vec![], @@ -194,7 +193,7 @@ impl DexFragment { 0 }; frag.class_def.class_data_off = if class.has_data_item() { - //TODO: frag.insert_class_data_item(class_id)?; + frag.insert_class_data_item(class, &index)?; 1 } else { 0 @@ -203,7 +202,7 @@ impl DexFragment { let static_values_off = frag .section_manager .get_aligned_size(FragSection::EncodedArrayItem); - // TODO: frag.insert_class_static_values(class)?; + frag.insert_class_static_values(class, &index)?; static_values_off + 1 } else { 0 @@ -247,9 +246,9 @@ impl DexFragment { for field_id in field_ids { let static_field = class.static_fields.get(&field_id); let instance_field = class.instance_fields.get(&field_id); - let (is_static, field) = match (static_field, instance_field) { - (Some(field), None) => (true, field), - (None, Some(field)) => (false, field), + let field = match (static_field, instance_field) { + (Some(field), None) => field, + (None, Some(field)) => field, _ => bail!( "Unexpected configuration: field {} is both a static and a instance field in {}", field_id.__str__(), class.__str__()), @@ -279,9 +278,9 @@ impl DexFragment { for method_id in &method_ids { let direct_method = class.direct_methods.get(method_id); let virtual_method = class.virtual_methods.get(method_id); - let (is_direct, method) = match (direct_method, virtual_method) { - (Some(method), None) => (true, method), - (None, Some(method)) => (false, method), + let method = match (direct_method, virtual_method) { + (Some(method), None) => method, + (None, Some(method)) => method, _ => bail!( "Unexpected configuration: method {} is both a direct and a virtual method in {}", method_id.__str__(), class.__str__()), @@ -307,9 +306,9 @@ impl DexFragment { for method_id in method_ids { let direct_method = class.direct_methods.get(&method_id); let virtual_method = class.virtual_methods.get(&method_id); - let (is_direct, method) = match (direct_method, virtual_method) { - (Some(method), None) => (true, method), - (None, Some(method)) => (false, method), + let method = match (direct_method, virtual_method) { + (Some(method), None) => method, + (None, Some(method)) => method, _ => bail!( "Unexpected configuration: method {} is both a direct and a virtual method in {}", method_id.__str__(), class.__str__()), @@ -463,7 +462,7 @@ impl DexFragment { } /// Insert a [`MethodHandle`]. - pub fn insert_method_handle(&mut self, handle: &MethodHandle, index: &FragIndex) -> Result<()> { + fn insert_method_handle(&mut self, handle: &MethodHandle, index: &FragIndex) -> Result<()> { let (field_or_method_id, method_handle_type) = match handle { MethodHandle::StaticPut(StaticPut(field)) => ( *index @@ -552,32 +551,7 @@ impl DexFragment { /// # Warning /// /// This is currently a stub that probably serialize invalid references to data. - fn insert_code_item(&mut self, method_id: IdMethod, direct_methods: bool) -> Result<()> { - let code = if direct_methods { - self.class_defs - .get(&method_id.class_) - .unwrap() - .0 - .direct_methods - .get(&method_id) - .unwrap() - .code - .as_ref() - .unwrap() - .clone() - } else { - self.class_defs - .get(&method_id.class_) - .unwrap() - .0 - .virtual_methods - .get(&method_id) - .unwrap() - .code - .as_ref() - .unwrap() - .clone() - }; + fn insert_code_item(&mut self, code: &Code, index: &FragIndex) -> Result<()> { // Estimate instructions addresses let mut min_addr = 0; let mut max_addr = 0; @@ -591,10 +565,9 @@ impl DexFragment { max_addr += ins.max_ins_size() / 2; } Instruction::ConstString(ins) => { - let string_idx = self.strings.get(&ins.lit).ok_or(anyhow!( - "String {} (found in code of {}) not found in dex builder", + let string_idx = index.strings.get(&ins.lit).ok_or(anyhow!( + "String {} not found in dex builder", ins.lit.__str__(), - method_id.__str__() ))?; let size = ins.get_raw_ins(*string_idx).size() / 2; min_addr += size; @@ -617,10 +590,9 @@ impl DexFragment { addr += ins.max_ins_size() / 2; } Instruction::ConstString(ins) => { - let string_idx = self.strings.get(&ins.lit).ok_or(anyhow!( - "String {} (found in code of {}) not found in dex builder", + let string_idx = index.strings.get(&ins.lit).ok_or(anyhow!( + "String {} not found in dex builder", ins.lit.__str__(), - method_id.__str__() ))?; addr += ins.get_raw_ins(*string_idx).size() / 2; } @@ -650,70 +622,63 @@ impl DexFragment { for ins in &code.insns { match ins { Instruction::ConstString(ins) => { - let string_idx = self.strings.get(&ins.lit).ok_or(anyhow!( - "String {} (found in code of {}) not found in dex builder", + let string_idx = index.strings.get(&ins.lit).ok_or(anyhow!( + "String {} not found in dex fragment", ins.lit.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*string_idx); addr += ins.size() / 2; insns.push(ins); } Instruction::ConstClass(ins) => { - let class_idx = *self.type_ids.get(&ins.lit).ok_or(anyhow!( - "Class {} (type of class found in code of {}) not found in dex builder", + let class_idx = *index.types.get(&ins.lit).ok_or(anyhow!( + "Class {} not found in dex fragment", ins.lit.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(class_idx); addr += ins.size() / 2; insns.push(ins); } Instruction::CheckCast(ins) => { - let class_idx = *self.type_ids.get(&ins.lit).ok_or(anyhow!( - "Class {} (type of class found in code of {}) not found in dex builder", + let class_idx = *index.types.get(&ins.lit).ok_or(anyhow!( + "Class {} not found in dex fragment", ins.lit.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(class_idx); addr += ins.size() / 2; insns.push(ins); } Instruction::InstanceOf(ins) => { - let class_idx = *self.type_ids.get(&ins.lit).ok_or(anyhow!( - "Class {} (type of class found in code of {}) not found in dex builder", + let class_idx = *index.types.get(&ins.lit).ok_or(anyhow!( + "Class {} not found in dex fragment", ins.lit.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(class_idx); addr += ins.size() / 2; insns.push(ins); } Instruction::NewInstance(ins) => { - let class_idx = *self.type_ids.get(&ins.lit).ok_or(anyhow!( - "Class {} (type of class found in code of {}) not found in dex builder", + let class_idx = *index.types.get(&ins.lit).ok_or(anyhow!( + "Class {} not found in dex fragment", ins.lit.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(class_idx); addr += ins.size() / 2; insns.push(ins); } Instruction::NewArray(ins) => { - let class_idx = *self.type_ids.get(&ins.lit).ok_or(anyhow!( - "Type {} (type found in code of {}) not found in dex builder", + let class_idx = *index.types.get(&ins.lit).ok_or(anyhow!( + "Type {} not found in dex fragment", ins.lit.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(class_idx); addr += ins.size() / 2; insns.push(ins); } Instruction::FilledNewArray(ins) => { - let class_idx = *self.type_ids.get(&ins.type_).ok_or(anyhow!( - "Type {} (type found in code of {}) not found in dex builder", + let class_idx = *index.types.get(&ins.type_).ok_or(anyhow!( + "Type {} not found in dex fragment", ins.type_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(class_idx); addr += ins.size() / 2; @@ -743,9 +708,8 @@ impl DexFragment { let goto_size = goto_sizes[goto_idx]; goto_idx += 1; let label_addr = label_addrs.get(&ins.label).ok_or(anyhow!( - "Label {} not found in code of {}, but found goto with this label", + "Label {} not found in code, but found goto with this label", ins.label, - method_id.__str__() ))?; let branch_offset = *label_addr as i32 - addr as i32; let ins = ins.get_raw_ins(branch_offset, goto_size); @@ -756,19 +720,17 @@ impl DexFragment { let mut key_targets = vec![]; for (key, label) in &ins.branches { let label_addr = label_addrs.get(label).ok_or(anyhow!( - "Label {} not found in code of {}, but found goto with this label", + "Label {} not found in code, but found goto with this label", label, - method_id.__str__() ))?; let branch_offset = *label_addr as i32 - addr as i32; key_targets.push((*key, branch_offset)); } key_targets.sort_by_key(|(key, _)| *key); let payload = if ins.is_packed() { - let (first_key, _) = *key_targets.first().ok_or(anyhow!( - "Found empty swith in code of {}", - method_id.__str__() - ))?; + let (first_key, _) = *key_targets + .first() + .ok_or(anyhow!("Found empty swith in code"))?; let targets: Vec<_> = key_targets.into_iter().map(|(_, target)| target).collect(); InsFormat::FormatPackedSwitchPayload { first_key, targets } @@ -792,16 +754,12 @@ impl DexFragment { } Instruction::IfEq(ins) => { let label_addr = label_addrs.get(&ins.label).ok_or(anyhow!( - "Label {} not found in code of {}, but found if with this label", + "Label {} not found in code, but found if with this label", ins.label, - method_id.__str__() ))?; let branch_offset = *label_addr as i32 - addr as i32; if branch_offset > i16::MAX as i32 || branch_offset < i16::MIN as i32 { - bail!( - "Found an if that jump to far from the instruction in code of {}", - method_id.__str__() - ); + bail!("Found an if that jump to far from the instruction in code"); } let ins = ins.get_raw_ins(branch_offset as i16); addr += ins.size() / 2; @@ -809,16 +767,12 @@ impl DexFragment { } Instruction::IfNe(ins) => { let label_addr = label_addrs.get(&ins.label).ok_or(anyhow!( - "Label {} not found in code of {}, but found if with this label", + "Label {} not found in code, but found if with this label", ins.label, - method_id.__str__() ))?; let branch_offset = *label_addr as i32 - addr as i32; if branch_offset > i16::MAX as i32 || branch_offset < i16::MIN as i32 { - bail!( - "Found an if that jump to far from the instruction in code of {}", - method_id.__str__() - ); + bail!("Found an if that jump to far from the instruction in code"); } let ins = ins.get_raw_ins(branch_offset as i16); addr += ins.size() / 2; @@ -826,16 +780,12 @@ impl DexFragment { } Instruction::IfLt(ins) => { let label_addr = label_addrs.get(&ins.label).ok_or(anyhow!( - "Label {} not found in code of {}, but found if with this label", + "Label {} not found in code, but found if with this label", ins.label, - method_id.__str__() ))?; let branch_offset = *label_addr as i32 - addr as i32; if branch_offset > i16::MAX as i32 || branch_offset < i16::MIN as i32 { - bail!( - "Found an if that jump to far from the instruction in code of {}", - method_id.__str__() - ); + bail!("Found an if that jump to far from the instruction in code"); } let ins = ins.get_raw_ins(branch_offset as i16); addr += ins.size() / 2; @@ -843,16 +793,12 @@ impl DexFragment { } Instruction::IfGe(ins) => { let label_addr = label_addrs.get(&ins.label).ok_or(anyhow!( - "Label {} not found in code of {}, but found if with this label", + "Label {} not found in code, but found if with this label", ins.label, - method_id.__str__() ))?; let branch_offset = *label_addr as i32 - addr as i32; if branch_offset > i16::MAX as i32 || branch_offset < i16::MIN as i32 { - bail!( - "Found an if that jump to far from the instruction in code of {}", - method_id.__str__() - ); + bail!("Found an if that jump to far from the instruction in code"); } let ins = ins.get_raw_ins(branch_offset as i16); addr += ins.size() / 2; @@ -860,16 +806,12 @@ impl DexFragment { } Instruction::IfGt(ins) => { let label_addr = label_addrs.get(&ins.label).ok_or(anyhow!( - "Label {} not found in code of {}, but found if with this label", + "Label {} not found in code, but found if with this label", ins.label, - method_id.__str__() ))?; let branch_offset = *label_addr as i32 - addr as i32; if branch_offset > i16::MAX as i32 || branch_offset < i16::MIN as i32 { - bail!( - "Found an if that jump to far from the instruction in code of {}", - method_id.__str__() - ); + bail!("Found an if that jump to far from the instruction in code"); } let ins = ins.get_raw_ins(branch_offset as i16); addr += ins.size() / 2; @@ -877,16 +819,12 @@ impl DexFragment { } Instruction::IfLe(ins) => { let label_addr = label_addrs.get(&ins.label).ok_or(anyhow!( - "Label {} not found in code of {}, but found if with this label", + "Label {} not found in code, but found if with this label", ins.label, - method_id.__str__() ))?; let branch_offset = *label_addr as i32 - addr as i32; if branch_offset > i16::MAX as i32 || branch_offset < i16::MIN as i32 { - bail!( - "Found an if that jump to far from the instruction in code of {}", - method_id.__str__() - ); + bail!("Found an if that jump to far from the instruction in code"); } let ins = ins.get_raw_ins(branch_offset as i16); addr += ins.size() / 2; @@ -894,16 +832,12 @@ impl DexFragment { } Instruction::IfEqZ(ins) => { let label_addr = label_addrs.get(&ins.label).ok_or(anyhow!( - "Label {} not found in code of {}, but found if with this label", + "Label {} not found in code, but found if with this label", ins.label, - method_id.__str__() ))?; let branch_offset = *label_addr as i32 - addr as i32; if branch_offset > i16::MAX as i32 || branch_offset < i16::MIN as i32 { - bail!( - "Found an if that jump to far from the instruction in code of {}", - method_id.__str__() - ); + bail!("Found an if that jump to far from the instruction in code"); } let ins = ins.get_raw_ins(branch_offset as i16); addr += ins.size() / 2; @@ -911,16 +845,12 @@ impl DexFragment { } Instruction::IfNeZ(ins) => { let label_addr = label_addrs.get(&ins.label).ok_or(anyhow!( - "Label {} not found in code of {}, but found if with this label", + "Label {} not found in code, but found if with this label", ins.label, - method_id.__str__() ))?; let branch_offset = *label_addr as i32 - addr as i32; if branch_offset > i16::MAX as i32 || branch_offset < i16::MIN as i32 { - bail!( - "Found an if that jump to far from the instruction in code of {}", - method_id.__str__() - ); + bail!("Found an if that jump to far from the instruction in code"); } let ins = ins.get_raw_ins(branch_offset as i16); addr += ins.size() / 2; @@ -928,16 +858,12 @@ impl DexFragment { } Instruction::IfLtZ(ins) => { let label_addr = label_addrs.get(&ins.label).ok_or(anyhow!( - "Label {} not found in code of {}, but found if with this label", + "Label {} not found in code, but found if with this label", ins.label, - method_id.__str__() ))?; let branch_offset = *label_addr as i32 - addr as i32; if branch_offset > i16::MAX as i32 || branch_offset < i16::MIN as i32 { - bail!( - "Found an if that jump to far from the instruction in code of {}", - method_id.__str__() - ); + bail!("Found an if that jump to far from the instruction in code"); } let ins = ins.get_raw_ins(branch_offset as i16); addr += ins.size() / 2; @@ -945,16 +871,12 @@ impl DexFragment { } Instruction::IfGeZ(ins) => { let label_addr = label_addrs.get(&ins.label).ok_or(anyhow!( - "Label {} not found in code of {}, but found if with this label", + "Label {} not found in code, but found if with this label", ins.label, - method_id.__str__() ))?; let branch_offset = *label_addr as i32 - addr as i32; if branch_offset > i16::MAX as i32 || branch_offset < i16::MIN as i32 { - bail!( - "Found an if that jump to far from the instruction in code of {}", - method_id.__str__() - ); + bail!("Found an if that jump to far from the instruction in code"); } let ins = ins.get_raw_ins(branch_offset as i16); addr += ins.size() / 2; @@ -962,16 +884,12 @@ impl DexFragment { } Instruction::IfGtZ(ins) => { let label_addr = label_addrs.get(&ins.label).ok_or(anyhow!( - "Label {} not found in code of {}, but found if with this label", + "Label {} not found in code, but found if with this label", ins.label, - method_id.__str__() ))?; let branch_offset = *label_addr as i32 - addr as i32; if branch_offset > i16::MAX as i32 || branch_offset < i16::MIN as i32 { - bail!( - "Found an if that jump to far from the instruction in code of {}", - method_id.__str__() - ); + bail!("Found an if that jump to far from the instruction in code"); } let ins = ins.get_raw_ins(branch_offset as i16); addr += ins.size() / 2; @@ -979,16 +897,12 @@ impl DexFragment { } Instruction::IfLeZ(ins) => { let label_addr = label_addrs.get(&ins.label).ok_or(anyhow!( - "Label {} not found in code of {}, but found if with this label", + "Label {} not found in code, but found if with this label", ins.label, - method_id.__str__() ))?; let branch_offset = *label_addr as i32 - addr as i32; if branch_offset > i16::MAX as i32 || branch_offset < i16::MIN as i32 { - bail!( - "Found an if that jump to far from the instruction in code of {}", - method_id.__str__() - ); + bail!("Found an if that jump to far from the instruction in code"); } let ins = ins.get_raw_ins(branch_offset as i16); addr += ins.size() / 2; @@ -996,11 +910,10 @@ impl DexFragment { } Instruction::IGet(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1008,11 +921,10 @@ impl DexFragment { } Instruction::IGetWide(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1020,11 +932,10 @@ impl DexFragment { } Instruction::IGetObject(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1032,11 +943,10 @@ impl DexFragment { } Instruction::IGetBoolean(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1044,11 +954,10 @@ impl DexFragment { } Instruction::IGetByte(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1056,11 +965,10 @@ impl DexFragment { } Instruction::IGetChar(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1068,11 +976,10 @@ impl DexFragment { } Instruction::IGetShort(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1080,11 +987,10 @@ impl DexFragment { } Instruction::IPut(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1092,11 +998,10 @@ impl DexFragment { } Instruction::IPutWide(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1104,11 +1009,10 @@ impl DexFragment { } Instruction::IPutObject(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1116,11 +1020,10 @@ impl DexFragment { } Instruction::IPutBoolean(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1128,11 +1031,10 @@ impl DexFragment { } Instruction::IPutByte(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1140,11 +1042,10 @@ impl DexFragment { } Instruction::IPutChar(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1152,11 +1053,10 @@ impl DexFragment { } Instruction::IPutShort(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1164,11 +1064,10 @@ impl DexFragment { } Instruction::SGet(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1176,11 +1075,10 @@ impl DexFragment { } Instruction::SGetWide(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1188,11 +1086,10 @@ impl DexFragment { } Instruction::SGetObject(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1200,11 +1097,10 @@ impl DexFragment { } Instruction::SGetBoolean(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1212,11 +1108,10 @@ impl DexFragment { } Instruction::SGetByte(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1224,11 +1119,10 @@ impl DexFragment { } Instruction::SGetChar(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1236,11 +1130,10 @@ impl DexFragment { } Instruction::SGetShort(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1248,11 +1141,10 @@ impl DexFragment { } Instruction::SPut(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1260,11 +1152,10 @@ impl DexFragment { } Instruction::SPutWide(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1272,11 +1163,10 @@ impl DexFragment { } Instruction::SPutObject(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1284,11 +1174,10 @@ impl DexFragment { } Instruction::SPutBoolean(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1296,11 +1185,10 @@ impl DexFragment { } Instruction::SPutByte(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1308,11 +1196,10 @@ impl DexFragment { } Instruction::SPutChar(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1320,11 +1207,10 @@ impl DexFragment { } Instruction::SPutShort(ins) => { let field = &ins.field; - let field_idx = self.field_ids.get(field).ok_or(anyhow!( - "Field {} (field of class {}, found in code of {}) not found in dex builder", + let field_idx = index.fields.get(field).ok_or(anyhow!( + "Field {} (field of class {}) not found in dex fragment", field.__str__(), field.class_.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*field_idx); addr += ins.size() / 2; @@ -1332,11 +1218,10 @@ impl DexFragment { } Instruction::InvokeVirtual(ins) => { let meth = &ins.method; - let meth_idx = self.method_ids.get(meth).ok_or(anyhow!( - "Method {} (method of class {}, found in code of {}) not found in dex builder", + let meth_idx = index.methods.get(meth).ok_or(anyhow!( + "Method {} (method of class {}) not found in dex fragment", meth.__str__(), meth.class_.__str__(), - method_id.__str__() ))?; debug_assert!( *meth_idx <= u16::MAX as usize, @@ -1349,11 +1234,10 @@ impl DexFragment { } Instruction::InvokeSuper(ins) => { let meth = &ins.method; - let meth_idx = self.method_ids.get(meth).ok_or(anyhow!( - "Method {} (method of class {}, found in code of {}) not found in dex builder", + let meth_idx = index.methods.get(meth).ok_or(anyhow!( + "Method {} (method of class {}) not found in dex fragment", meth.__str__(), meth.class_.__str__(), - method_id.__str__() ))?; debug_assert!( *meth_idx <= u16::MAX as usize, @@ -1366,11 +1250,10 @@ impl DexFragment { } Instruction::InvokeDirect(ins) => { let meth = &ins.method; - let meth_idx = self.method_ids.get(meth).ok_or(anyhow!( - "Method {} (method of class {}, found in code of {}) not found in dex builder", + let meth_idx = index.methods.get(meth).ok_or(anyhow!( + "Method {} (method of class {}) not found in dex fragment", meth.__str__(), meth.class_.__str__(), - method_id.__str__() ))?; debug_assert!( *meth_idx <= u16::MAX as usize, @@ -1383,11 +1266,10 @@ impl DexFragment { } Instruction::InvokeStatic(ins) => { let meth = &ins.method; - let meth_idx = self.method_ids.get(meth).ok_or(anyhow!( - "Method {} (method of class {}, found in code of {}) not found in dex builder", + let meth_idx = index.methods.get(meth).ok_or(anyhow!( + "Method {} (method of class {}) not found in dex fragment", meth.__str__(), meth.class_.__str__(), - method_id.__str__() ))?; debug_assert!( *meth_idx <= u16::MAX as usize, @@ -1400,11 +1282,10 @@ impl DexFragment { } Instruction::InvokeInterface(ins) => { let meth = &ins.method; - let meth_idx = self.method_ids.get(meth).ok_or(anyhow!( - "Method {} (method of class {}, found in code of {}) not found in dex builder", + let meth_idx = index.methods.get(meth).ok_or(anyhow!( + "Method {} (method of class {}) not found in dex fragment", meth.__str__(), meth.class_.__str__(), - method_id.__str__() ))?; debug_assert!( *meth_idx <= u16::MAX as usize, @@ -1417,16 +1298,14 @@ impl DexFragment { } Instruction::InvokePolymorphic(ins) => { let meth = &ins.method; - let meth_idx = self.method_ids.get(meth).ok_or(anyhow!( - "Method {} (method of class {}, found in code of {}) not found in dex builder", + let meth_idx = index.methods.get(meth).ok_or(anyhow!( + "Method {} (method of class {}) not found in dex fragment", meth.__str__(), meth.class_.__str__(), - method_id.__str__() ))?; - let proto_idx = self.proto_ids.get(&ins.proto).ok_or(anyhow!( - "Prototype {} (found in code of {}) not found in dex builder", + let proto_idx = index.protos.get(&ins.proto).ok_or(anyhow!( + "Prototype {} (found in code) not found in dex fragment", ins.proto.__str__(), - method_id.__str__() ))?; debug_assert!( *meth_idx <= u16::MAX as usize, @@ -1444,7 +1323,7 @@ impl DexFragment { } Instruction::InvokeCustom(ins) => { let call_site_idx = self.call_site_ids.len(); - self.insert_call_site_item(&ins.call_site)?; + self.insert_call_site_item(&ins.call_site, index)?; let ins = ins.get_raw_ins(call_site_idx); addr += ins.size() / 2; insns.push(ins); @@ -1457,10 +1336,9 @@ impl DexFragment { insns.push(ins); } Instruction::ConstMethodType(ins) => { - let proto_idx = self.proto_ids.get(&ins.proto).ok_or(anyhow!( - "Prototype {} (found in code of {}) not found in dex builder", + let proto_idx = index.protos.get(&ins.proto).ok_or(anyhow!( + "Prototype {} (found in code) not found in dex fragment", ins.proto.__str__(), - method_id.__str__() ))?; let ins = ins.get_raw_ins(*proto_idx); addr += ins.size() / 2; @@ -1468,15 +1346,11 @@ impl DexFragment { } Instruction::Try(try_) => { let end_block_addr = *label_addrs.get(&try_.end_label).ok_or(anyhow!( - "Label {} not found in code of {}, but found try with this label", + "Label {} not found in code, but found try with this label", &try_.end_label, - method_id.__str__() ))?; if end_block_addr < addr { - bail!( - "Found end label of a try block before the try instruction in code of {}", - method_id.__str__() - ) + bail!("Found end label of a try block before the try instruction in code") } let try_item = TryItem { start_addr: addr as u32, @@ -1490,17 +1364,14 @@ impl DexFragment { catch_all_addr: None, }; for (ty, label) in &try_.handlers { - let type_idx = Uleb128(*self.type_ids.get(ty).ok_or(anyhow!( - "Could not found type {} captured by a try block in {}\ - in the dex builder", + let type_idx = Uleb128(*index.types.get(ty).ok_or(anyhow!( + "Could not found type {} in dex fragment captured by a try block", ty.__str__(), - method_id.__str__() ))? as u32); let addr = Uleb128(*label_addrs.get(label).ok_or(anyhow!( - "Label {} not found in code of {}, but found try \ + "Label {} not found in code, but found try \ with this label as catch for type {}", &try_.end_label, - method_id.__str__(), ty.__str__(), ))? as u32); catches @@ -1509,10 +1380,9 @@ impl DexFragment { } if let Some(ref label) = try_.default_handler { let catch_all_addr = *label_addrs.get(label).ok_or(anyhow!( - "Label {} not found in code of {}, but found try \ + "Label {} not found in code, but found try \ with this label as catch all", &try_.end_label, - method_id.__str__() ))?; catches.catch_all_addr = Some(Uleb128(catch_all_addr as u32)); } @@ -1523,10 +1393,9 @@ impl DexFragment { _ => { let ins = ins.get_raw_ins().with_context(|| { format!( - "Failed to convert instruction {} (found in code of {}) to raw instruction", - ins.__str__(), - method_id.__str__() - ) + "Failed to convert instruction {} (found in code) to raw instruction", + ins.__str__(), + ) })?; addr += ins.size() / 2; insns.push(ins); @@ -1550,21 +1419,20 @@ impl DexFragment { } else { let debug_info_off = self .section_manager - .get_aligned_size(Section::DebugInfoItem); - let mut cursor = Cursor::new(code.debug_info.1); + .get_aligned_size(FragSection::DebugInfoItem); + let mut cursor = Cursor::new(&code.debug_info.1); let mut item = DebugInfoItem { line_start: Uleb128(code.debug_info.0), parameter_names: vec![], bytecode: Vec::::deserialize(&mut cursor, DbgBytecode::EndSequence)?, }; - if let Some(parameter_names) = code.parameter_names { - for name in ¶meter_names { + if let Some(parameter_names) = &code.parameter_names { + for name in parameter_names { if let Some(name) = name { item.parameter_names - .push(Uleb128p1(*self.strings.get(name).ok_or(anyhow!( - "String {} (name of param of {}) not found", + .push(Uleb128p1(*index.strings.get(name).ok_or(anyhow!( + "String {} (name of parameter) not found", name.__str__(), - method_id.__str__() ))? as u32)); } else { item.parameter_names.push(NO_INDEX); @@ -1572,7 +1440,7 @@ impl DexFragment { } } self.section_manager - .add_elt(Section::DebugInfoItem, Some(item.size())); + .add_elt(FragSection::DebugInfoItem, Some(item.size())); self.debug_info_items.push(item); debug_info_off + 1 }; @@ -1591,7 +1459,7 @@ impl DexFragment { handlers, }; self.section_manager - .add_elt(Section::CodeItem, Some(item.size())); + .add_elt(FragSection::CodeItem, Some(item.size())); self.code_items.push(item); Ok(()) } @@ -1609,15 +1477,14 @@ impl DexFragment { /// 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_data_item(&mut self, class_id: &IdType) -> Result<()> { + fn insert_class_data_item(&mut self, class: &Class, index: &FragIndex) -> Result<()> { let mut data = ClassDataItem::default(); - let (class, _) = self.class_defs.get(class_id).unwrap(); let mut static_fields: Vec = class.static_fields.keys().cloned().collect(); static_fields.sort(); let mut last_field_id = 0; for id in &static_fields { - let idx = self.field_ids.get(id).ok_or(anyhow!( + let idx = index.fields.get(id).ok_or(anyhow!( "Field {} (field of class {}) not found in dex builder", id.__str__(), class.__str__() @@ -1635,7 +1502,7 @@ impl DexFragment { instance_fields.sort(); let mut last_field_id = 0; for id in &instance_fields { - let idx = self.field_ids.get(id).ok_or(anyhow!( + let idx = index.fields.get(id).ok_or(anyhow!( "Field {} (field of class {}) not found in dex builder", id.__str__(), class.__str__() @@ -1660,8 +1527,7 @@ impl DexFragment { let mut last_method_id = 0; for id in &direct_methods { // &mut vs & of self and class make things difficult... - let (class, _) = self.class_defs.get(class_id).unwrap(); - let idx = self.method_ids.get(id).ok_or(anyhow!( + let idx = index.methods.get(id).ok_or(anyhow!( "Method {} (method of class {}) not found in dex builder", id.__str__(), class.__str__() @@ -1670,10 +1536,11 @@ impl DexFragment { last_method_id = *idx; let access_flags = Uleb128(class.direct_methods.get(id).unwrap().get_raw_access_flags()); - // No if let because ownership gunfooterie - let code_off = if class.direct_methods.get(id).unwrap().code.is_some() { - let code_off = self.section_manager.get_aligned_size(Section::CodeItem); - self.insert_code_item(id.clone(), true)?; + let code_off = if let Some(code) = &class.direct_methods.get(id).unwrap().code { + let code_off = self.section_manager.get_aligned_size(FragSection::CodeItem); + self.insert_code_item(code, index).with_context(|| { + format!("Failed to convert serialize code of {}", id.__str__()) + })?; Uleb128(code_off + 1) } else { Uleb128(0) @@ -1685,13 +1552,11 @@ impl DexFragment { }); } - let (class, _) = self.class_defs.get(class_id).unwrap(); let mut virtual_methods: Vec = class.virtual_methods.keys().cloned().collect(); virtual_methods.sort(); let mut last_method_id = 0; for id in &virtual_methods { - let (class, _) = self.class_defs.get(class_id).unwrap(); - let idx = self.method_ids.get(id).ok_or(anyhow!( + let idx = index.methods.get(id).ok_or(anyhow!( "Method {} (method of class {}) not found in dex builder", id.__str__(), class.__str__() @@ -1705,10 +1570,11 @@ impl DexFragment { .unwrap() .get_raw_access_flags(), ); - // No if let because ownership gunfooterie - let code_off = if class.virtual_methods.get(id).unwrap().code.is_some() { - let code_off = self.section_manager.get_aligned_size(Section::CodeItem); - self.insert_code_item(id.clone(), false)?; + let code_off = if let Some(code) = &class.virtual_methods.get(id).unwrap().code { + let code_off = self.section_manager.get_aligned_size(FragSection::CodeItem); + self.insert_code_item(code, index).with_context(|| { + format!("Failed to convert serialize code of {}", id.__str__()) + })?; Uleb128(code_off + 1) } else { Uleb128(0) @@ -1720,9 +1586,9 @@ impl DexFragment { }); } self.section_manager - .add_elt(Section::ClassDataItem, Some(data.size())); + .add_elt(FragSection::ClassDataItem, Some(data.size())); //assert_eq!(data.size(), data.serialize_to_vec().unwrap().len()); - self.class_data_list.push(data); + self.class_data = Some(data); Ok(()) } @@ -1731,7 +1597,7 @@ impl DexFragment { /// # Warning /// /// This method can insert element in the dex file like method_handles. - pub fn dex_value_to_encoded_value( + fn dex_value_to_encoded_value( &mut self, value: &DexValue, index: &FragIndex, @@ -1832,7 +1698,7 @@ impl DexFragment { /// # Warning /// /// This method can insert element in the dex file like method_handles. - pub fn insert_call_site_item(&mut self, call_site: &CallSite) -> Result<()> { + fn insert_call_site_item(&mut self, call_site: &CallSite, index: &FragIndex) -> Result<()> { let mut values = vec![]; values.push(DexValue::MethodHandle(call_site.method_handle.clone())); values.push(DexValue::String(call_site.name.clone())); @@ -1841,15 +1707,15 @@ impl DexFragment { self.call_site_ids.push(CallSiteIdItem { call_site_off: self .section_manager - .get_aligned_size(Section::EncodedArrayItem), - }); // linked in link_call_site_ids() - self.section_manager.add_elt(Section::CallSiteIdItem, None); - self.insert_encoded_array_item(DexArray(values)) + .get_aligned_size(FragSection::EncodedArrayItem), + }); + self.section_manager + .add_elt(FragSection::CallSiteIdItem, None); + self.insert_encoded_array_item(DexArray(values), index) } /// Insert the encoded_array_item encoding the static_values of a class. - fn insert_class_static_values(&mut self, class_id: &IdType) -> Result<()> { - let (class, _) = self.class_defs.get(class_id).unwrap(); + fn insert_class_static_values(&mut self, class: &Class, index: &FragIndex) -> Result<()> { let mut static_fields: Vec = class.static_fields.keys().cloned().collect(); static_fields.sort(); let mut array = vec![]; @@ -1868,15 +1734,15 @@ impl DexFragment { "The type {} (for field {} in class {}) does not have a default value", field.descriptor.type_.__str__(), field.descriptor.__str__(), - class_id.__str__() + class.__str__() ))?); } } - self.insert_encoded_array_item(DexArray(array)) + self.insert_encoded_array_item(DexArray(array), index) .with_context(|| { format!( "Failed to serialize static values of class {}", - class_id.__str__() + class.__str__() ) }) } @@ -1898,7 +1764,7 @@ impl DexFragment { "{} (annotation element name) not found in dex builder", name.__str__() ))? as u32), - value: self.dex_value_to_encoded_value(elt)?, + value: self.dex_value_to_encoded_value(elt, index)?, }); } Ok(EncodedAnnotation { @@ -1986,612 +1852,6 @@ impl DexFragment { self.annotation_set_lists.push(list); Ok(()) } - - fn gen_type_list_section(&mut self) -> Result<()> { - debug!("Generate the type_list section"); - // Collect all type lists - for proto in self.proto_ids.keys() { - if !proto.parameters.is_empty() { - let type_list = self.gen_type_list(&proto.parameters).with_context(|| { - format!("Failed to generate param list for {}", proto.__str__()) - })?; - self.type_lists_index.insert(type_list, 0); - } - } - for (class, _) in self.class_defs.values() { - if !class.interfaces.is_empty() { - let type_list = self.gen_type_list(&class.interfaces).with_context(|| { - format!("Failed to generate interface list for {}", class.__str__()) - })?; - self.type_lists_index.insert(type_list, 0); - } - } - - // safe type lists with their offset in the section - let mut offset = 0; - for (i, (list, idx)) in self.type_lists_index.iter_mut().enumerate() { - while offset % 4 != 0 { - // Alignment - self.section_manager.incr_section_size(Section::TypeList, 1); - offset += 1; - } - *idx = i; - self.type_lists_with_offset.push((list.clone(), offset)); - self.section_manager - .add_elt(Section::TypeList, Some(list.size())); - offset += list.size() as u32; - } - // The next section requires alignment to 4 - while offset % 4 != 0 { - // Alignment - self.section_manager.incr_section_size(Section::TypeList, 1); - offset += 1; - } - Ok(()) - } - - /// Generate the map list. - /// - /// # Warning - /// - /// All sections must be generated (but not linked) before generating the map list. - /// - /// This method switch the section manager from edit mode to read only. - fn gen_map_list(&mut self) -> Result<()> { - debug!("Generate the map_list"); - // Get the size of a map item - let map_item_size = 12; /* = MapItem { - type_: MapItemType::HeaderItem, - unused: 0, - size: 0, - offset: 0, - } - .size(); */ - // Empty map has a size 4, then we add the size of a MapItem for each element - // The size of the map_list must be computed before generating the map list, - // as it affect the offset of some sections. - self.section_manager.add_elt(Section::MapList, Some(4)); - for section in Section::VARIANT_LIST { - if !section.is_data() && self.section_manager.get_nb_elt(*section) != 0 { - self.section_manager - .incr_section_size(Section::MapList, map_item_size); - } - } - // All sections are knowns and should not be eddited anymore - self.section_manager.finalize_sections(); - for section in Section::VARIANT_LIST { - if !section.is_data() && self.section_manager.get_nb_elt(*section) != 0 { - /* - match section { - // Alignment - // Until Section::MapList included, the section are naturally alligned to 4 - _ => (), - } - */ - self.map_list.list.push(MapItem { - type_: section.get_map_item_type(), - unused: 0, - size: self.section_manager.get_nb_elt(*section) as u32, - offset: self.section_manager.get_offset(*section), - }); - } - } - Ok(()) - } - - /// Link the offsets in the header. - /// - /// # Warning - /// - /// Linking can only occur once all sections are entirelly generated. - fn link_header(&mut self) { - debug!("Link the header section"); - self.header.map_off = self.section_manager.get_offset(Section::MapList); - self.header.string_ids_size = self.section_manager.get_nb_elt(Section::StringIdItem) as u32; - self.header.string_ids_off = self.section_manager.get_offset(Section::StringIdItem); - self.header.type_ids_size = self.section_manager.get_nb_elt(Section::TypeIdItem) as u32; - self.header.type_ids_off = self.section_manager.get_offset(Section::TypeIdItem); - self.header.proto_ids_size = self.section_manager.get_nb_elt(Section::ProtoIdItem) as u32; - self.header.proto_ids_off = self.section_manager.get_offset(Section::ProtoIdItem); - self.header.field_ids_size = self.section_manager.get_nb_elt(Section::FieldIdItem) as u32; - self.header.field_ids_off = self.section_manager.get_offset(Section::FieldIdItem); - self.header.method_ids_size = self.section_manager.get_nb_elt(Section::MethodIdItem) as u32; - self.header.method_ids_off = self.section_manager.get_offset(Section::MethodIdItem); - self.header.class_defs_size = self.section_manager.get_nb_elt(Section::ClassDefItem) as u32; - self.header.class_defs_off = self.section_manager.get_offset(Section::ClassDefItem); - self.header.data_size = self.section_manager.get_unaligned_size(Section::Data); - self.header.data_off = self.section_manager.get_offset(Section::Data); - } - - /// Link the offsets in the call site id items. - /// - /// # Warning - /// - /// Linking can only occur once all sections are entirelly generated. - fn link_call_site_ids(&mut self) { - debug!("Link call site id items"); - for id in &mut self.call_site_ids { - id.call_site_off += self.section_manager.get_offset(Section::EncodedArrayItem); - } - } - - /// Link the offsets in class_def_items. - /// - /// # Warning - /// - /// This is the only link method called before generating the map list and finilizing the - /// section: - /// - /// Linking can only occur once all sections are entirelly generated, however, - /// `class_data_item.direct|virtual_methods[.].code_off` are Uleb128 encoded, meaning - /// that linking class_data_item modify the size of the class_data_items, hence the position - /// of the class_data_item and all element located after, as well as the size of the data - /// section. This is pretty bothersome and means that the sections **are** modified. - fn link_class_data(&mut self) -> Result<()> { - debug!("Link class data items"); - let mut unlinked_local_offset = 0; - let mut linked_local_offset = 0; - let code_section_off = self.section_manager.get_code_item_offset_prefinalized(); - for data in self.class_data_list.iter_mut() { - let unlinked_size = data.size() as u32; - for method in &mut data.direct_methods { - if method.code_off.0 != 0 { - method.code_off.0 += code_section_off - 1; - } - } - for method in &mut data.virtual_methods { - if method.code_off.0 != 0 { - method.code_off.0 += code_section_off - 1; - } - } - self.corrected_class_data_offset - .insert(unlinked_local_offset, linked_local_offset); - linked_local_offset += data.size() as u32; - unlinked_local_offset += unlinked_size; - } - self.section_manager.incr_section_size( - Section::ClassDataItem, - linked_local_offset as usize - unlinked_local_offset as usize, - ); - Ok(()) - } - - /// Link the offsets in proto_id_items. - /// - /// # Warning - /// - /// Linking can only occur once all sections are entirelly generated. - fn link_proto_id(&mut self) -> Result<()> { - debug!("Link proto id items"); - for (proto, idx) in &self.proto_ids { - if !proto.parameters.is_empty() { - let type_list = self.gen_type_list(&proto.parameters).with_context(|| { - format!("Failed to generate param list for {}", proto.__str__()) - })?; - let offset = self.section_manager.get_offset(Section::TypeList) - + self.type_lists_with_offset[*self.type_lists_index.get(&type_list).unwrap()] - .1; - self.proto_ids_list[*idx].parameters_off = offset; - } - } - Ok(()) - } - - /// Link the offsets of class_data_items in class_def_items. - /// - /// # Warning - /// - /// Linking can only occur once all sections are entirelly generated. - fn link_class_def(&mut self) -> Result<()> { - debug!("Link class_def_items"); - for class_def in self.class_defs_list.iter_mut() { - // Link the class_data_item entries - // prelink value is set to offset in the section + 1 (to distinguish with 0) - if class_def.class_data_off != 0 { - let unlinked_local_offset = class_def.class_data_off - 1; - let linked_local_offset = *self - .corrected_class_data_offset - .get(&unlinked_local_offset) - .expect( - "Unlinked class_data_item offset not found in corrected_class_data_offset", - ); - class_def.class_data_off = - self.section_manager.get_offset(Section::ClassDataItem) + linked_local_offset; - } - // Link the annotations_directory_item entrie - // prelink value is set to offset in the section + 1 (to distinguish with 0) - if class_def.annotations_off != 0 { - class_def.annotations_off += self - .section_manager - .get_offset(Section::AnnotationsDirectoryItem) - - 1; - } - - // Link the static_values entries - if class_def.static_values_off != 0 { - class_def.static_values_off += - self.section_manager.get_offset(Section::EncodedArrayItem) - 1; - } - } - for (cls, idx) in self.class_defs.values() { - if !cls.interfaces.is_empty() { - let type_list = self.gen_type_list(&cls.interfaces).with_context(|| { - format!("Failed to generate interface list for {}", cls.__str__()) - })?; - let offset = self.section_manager.get_offset(Section::TypeList) - + self.type_lists_with_offset[*self.type_lists_index.get(&type_list).unwrap()] - .1; - self.class_defs_list[*idx].interfaces_off = offset; - } - } - Ok(()) - } - - /// Link the offset of debug info item in code items. - /// - /// # Warning - /// - /// Linking can only occur once all sections are entirelly generated. - fn link_code(&mut self) { - debug!("Link the debug_info_off entries in code_items"); - for code in self.code_items.iter_mut() { - if code.debug_info_off != 0 { - code.debug_info_off += self.section_manager.get_offset(Section::DebugInfoItem) - 1; - } - } - } - - /// Link all annotations objects. - /// - /// # Warning - /// - /// Linking can only occur once all sections are entirelly generated. - fn link_annotations(&mut self) { - for annotation in self.annotations_directory_items.iter_mut() { - if annotation.class_annotations_off != 0 { - annotation.class_annotations_off += - self.section_manager.get_offset(Section::AnnotationSetItem) - 1; - } - for field_annotation in annotation.field_annotations.iter_mut() { - if field_annotation.annotations_off != 0 { - field_annotation.annotations_off += - self.section_manager.get_offset(Section::AnnotationSetItem) - 1; - } - } - for method_annotation in annotation.method_annotations.iter_mut() { - if method_annotation.annotations_off != 0 { - method_annotation.annotations_off += - self.section_manager.get_offset(Section::AnnotationSetItem) - 1; - } - } - for parameter_annotation in annotation.parameter_annotations.iter_mut() { - if parameter_annotation.annotations_off != 0 { - parameter_annotation.annotations_off += self - .section_manager - .get_offset(Section::AnnotationSetRefList) - - 1; - } - } - } - for annotation_set in self.annotation_set_items.iter_mut() { - for entry in annotation_set.entries.iter_mut() { - entry.annotation_off += self.section_manager.get_offset(Section::AnnotationItem); - } - } - for list in self.annotation_set_lists.iter_mut() { - for annotation in list.list.iter_mut() { - if annotation.annotations_off != 0 { - annotation.annotations_off += - self.section_manager.get_offset(Section::AnnotationSetItem) - 1; - } - } - } - } - - fn write_dex_file(&mut self, writer: &mut dyn Write) -> Result<()> { - self.section_manager.reset(); - self.section_manager.add_elt(Section::HeaderItem, None); - - self.gen_string_data_section()?; - self.gen_type_ids_section()?; - self.gen_proto_ids_section()?; - self.gen_field_ids_section()?; - self.gen_method_ids_section()?; - - debug!("Sort classes and generate the class_defs and class_data section"); - for class_id in self.get_sorted_class_def()? { - self.insert_class_def_item(&class_id)?; - } - self.gen_type_list_section()?; - - // start by linking class_data_items to populate self.corrected_class_data_offset - // and update the class_data_item sections size. - // Why before gen_map_list? Because the offsets in class_data_items are F***ing Uleb128 - // encoded, so there size change when linking (see doc of self.corrected_class_data_offset). - let code_offset = self.section_manager.get_code_item_offset_prefinalized(); - self.link_class_data()?; - self.gen_map_list()?; - assert_eq!( - code_offset, - self.section_manager.get_offset(Section::CodeItem), - "Prelinking computed value and post linking value for \ - the offset of the code_item section don't match" - ); - - // From now on, all section are generated and the value in section_manager do not change, - - self.link_header(); - self.link_call_site_ids(); - self.link_proto_id()?; - self.link_class_def()?; - self.link_code(); - self.link_annotations(); - - debug!("Serialize the dex file"); - let mut buffer = Cursor::new(Vec::::new()); - - self.check_section_offset(&buffer, Section::HeaderItem); - Self::fix_section_alignement(&mut buffer, Section::HeaderItem)?; - self.header.serialize(&mut buffer)?; - // StringIdItem section - let mut string_off = self.section_manager.get_offset(Section::StringDataItem); - self.check_section_offset(&buffer, Section::StringIdItem); - for string in self.string_data_list.iter() { - let str_id = StringIdItem { - string_data_off: string_off, - }; - Self::fix_section_alignement(&mut buffer, Section::StringIdItem)?; - str_id.serialize(&mut buffer)?; - string_off += string.size() as u32; - } - // TypeId section - self.check_section_offset(&buffer, Section::TypeIdItem); - for ty in &self.type_ids_list { - Self::fix_section_alignement(&mut buffer, Section::TypeIdItem)?; - ty.serialize(&mut buffer)?; - } - // ProtoId section - self.check_section_offset(&buffer, Section::ProtoIdItem); - for proto in &self.proto_ids_list { - Self::fix_section_alignement(&mut buffer, Section::ProtoIdItem)?; - proto.serialize(&mut buffer)?; - } - // FieldIdItem section - self.check_section_offset(&buffer, Section::FieldIdItem); - for field_id in &self.field_ids_list { - Self::fix_section_alignement(&mut buffer, Section::FieldIdItem)?; - field_id.serialize(&mut buffer)?; - } - // MethodIdItem section - self.check_section_offset(&buffer, Section::MethodIdItem); - for method_id in &self.method_ids_list { - Self::fix_section_alignement(&mut buffer, Section::MethodIdItem)?; - method_id.serialize(&mut buffer)?; - } - // ClassDefItem section - self.check_section_offset(&buffer, Section::ClassDefItem); - for class_def in &self.class_defs_list { - Self::fix_section_alignement(&mut buffer, Section::ClassDefItem)?; - class_def.serialize(&mut buffer)?; - } - // CallSiteIdItem, data are inserted as encoded array item later - self.check_section_offset(&buffer, Section::CallSiteIdItem); - for call_site_id in &self.call_site_ids { - Self::fix_section_alignement(&mut buffer, Section::CallSiteIdItem)?; - call_site_id.serialize(&mut buffer)?; - } - - // MethodHandleItem section - self.check_section_offset(&buffer, Section::MethodHandleItem); - for handle in &self.method_handles { - Self::fix_section_alignement(&mut buffer, Section::MethodHandleItem)?; - handle.serialize(&mut buffer)?; - } - // MapList - self.check_section_offset(&buffer, Section::Data); - self.check_section_offset(&buffer, Section::MapList); - Self::fix_section_alignement(&mut buffer, Section::MapList)?; - self.map_list.serialize(&mut buffer)?; - // TypeList, - self.check_section_offset(&buffer, Section::TypeList); - for (list, _) in &self.type_lists_with_offset { - Self::fix_section_alignement(&mut buffer, Section::TypeList)?; - list.serialize(&mut buffer)?; - } - // AnnotationSetRefList section - self.check_section_offset(&buffer, Section::AnnotationSetRefList); - for list in &self.annotation_set_lists { - Self::fix_section_alignement(&mut buffer, Section::AnnotationSetRefList)?; - list.serialize(&mut buffer)?; - } - // AnnotationSetItem section - self.check_section_offset(&buffer, Section::AnnotationSetItem); - for set in &self.annotation_set_items { - Self::fix_section_alignement(&mut buffer, Section::AnnotationSetItem)?; - set.serialize(&mut buffer)?; - } - // CodeItem section - self.check_section_offset(&buffer, Section::CodeItem); - for code_item in &self.code_items { - Self::fix_section_alignement(&mut buffer, Section::CodeItem)?; - code_item.serialize(&mut buffer)? - } - // StringDataItem section - self.check_section_offset(&buffer, Section::StringDataItem); - for string in &self.string_data_list { - Self::fix_section_alignement(&mut buffer, Section::StringDataItem)?; - string.serialize(&mut buffer)?; - } - // DebugInfoItem section - self.check_section_offset(&buffer, Section::DebugInfoItem); - for debug_info in &self.debug_info_items { - Self::fix_section_alignement(&mut buffer, Section::DebugInfoItem)?; - debug_info.serialize(&mut buffer)?; - } - // AnnotationItem section - self.check_section_offset(&buffer, Section::AnnotationItem); - for annot in &self.annotation_items { - Self::fix_section_alignement(&mut buffer, Section::AnnotationItem)?; - annot.serialize(&mut buffer)?; - } - // EncodedArrayItem section - self.check_section_offset(&buffer, Section::EncodedArrayItem); - for array in &self.encoded_array_items { - Self::fix_section_alignement(&mut buffer, Section::EncodedArrayItem)?; - array.serialize(&mut buffer)?; - } - // AnnotationsDirectoryItem section - self.check_section_offset(&buffer, Section::AnnotationsDirectoryItem); - for dir in &self.annotations_directory_items { - Self::fix_section_alignement(&mut buffer, Section::AnnotationsDirectoryItem)?; - dir.serialize(&mut buffer)?; - } - // ClassDataItem section - self.check_section_offset(&buffer, Section::ClassDataItem); - for data in &self.class_data_list { - Self::fix_section_alignement(&mut buffer, Section::ClassDataItem)?; - data.serialize(&mut buffer)?; - } - // TODO: HiddenapiClassDataItem, - /* - self.check_section_offset(&buffer, Section::HiddenapiClassDataItem); - Self::fix_section_alignement(&mut buffer, Section::HiddenapiClassDataItem)?; - */ - - let end_data = buffer.position(); - assert_eq!( - end_data as u32, - self.header.data_off + self.header.data_size - ); - - // compute signature - buffer.seek(SeekFrom::Start(8 + 4 + 20))?; - let mut hasher = Sha1::new(); - io::copy(&mut buffer, &mut hasher)?; - self.header.signature = hasher.finalize().into(); - let size = buffer.seek(SeekFrom::End(0))? as u32; - self.header.file_size = size; - buffer.rewind()?; - self.header.serialize(&mut buffer)?; - - // Compute checksum - //buffer.seek(SeekFrom::Start(8 + 4))?; - let mut adler = Adler32::new(); - adler.write_slice(&buffer.get_ref()[8 + 4..]); - self.header.checksum = adler.checksum(); - buffer.rewind()?; - self.header.serialize(&mut buffer)?; - - // copy buffer to output - buffer.rewind()?; - io::copy(&mut buffer, writer)?; - - Ok(()) - } - - /// Insert 0 to a buffer until the right alignment is reached for an element of the - /// given section. - fn fix_section_alignement(buffer: &mut Cursor>, section: Section) -> Result<()> { - while buffer.position() % section.get_item_alignment() as u64 != 0 { - Serializable::serialize(&0u8, buffer)?; - } - Ok(()) - } - - /// Check if a section - fn check_section_offset(&self, buffer: &Cursor, section: Section) { - let mut pos = buffer.position(); - while pos % section.get_item_alignment() as u64 != 0 { - pos += 1; - } - let expected = self.section_manager.get_offset(section) as u64; - assert_eq!( - pos, expected, - "Computed section offset and actual section offset do not match for section \ - {section:?}, expected 0x{expected:x}, found 0x{pos:x}" - ); - } - - /// Compute the order of the classes in the section `class_defs`. - /// Class definitions must be sorted so that a class's superclass and interfaces - /// are before the class. - fn get_sorted_class_def(&self) -> Result> { - // Use Kahn's algorithm - let mut graph: HashMap<&IdType, (HashSet<&IdType>, HashSet<&IdType>)> = HashMap::new(); - for (ty, (def, _)) in &self.class_defs { - let mut edges_to = HashSet::new(); - if let Some(sup) = def.superclass.as_ref() { - if self.class_defs.get(sup).is_some() { - edges_to.insert(sup); - } - } - for sup in &def.interfaces { - if self.class_defs.get(sup).is_some() { - edges_to.insert(sup); - } - } - for n_to in &edges_to { - let (from, _) = graph - .entry(n_to) - .or_insert((HashSet::new(), HashSet::new())); - from.insert(ty); - } - let (_, to) = graph.entry(ty).or_insert((HashSet::new(), HashSet::new())); - to.extend(edges_to); - } - - let mut sorted = vec![]; - let mut no_outgoing: VecDeque<&IdType> = VecDeque::new(); - no_outgoing.extend( - graph - .iter() - .filter(|(_, (_, to))| to.is_empty()) - .map(|(ty, _)| ty), - ); - if no_outgoing.is_empty() { - bail!("The class inheritance topoloy is either empty or cyclic"); - } - - while let Some(n) = no_outgoing.pop_front() { - sorted.push(n.clone()); - let (from, _) = graph.get(n).cloned().unwrap(); - for n_from in from { - graph.entry(n_from).and_modify(|(_, to)| _ = to.remove(n)); - let (_, to) = graph.get(n_from).unwrap(); - if to.is_empty() { - no_outgoing.push_back(n_from); - } - } - graph - .entry(n) - .and_modify(|(from, _)| *from = HashSet::new()); - } - for (_, (from, to)) in graph { - if !from.is_empty() || !to.is_empty() { - bail!("The class inheritance topology is cyclic"); - } - } - Ok(sorted) - } - - fn gen_type_list(&self, list: &[IdType]) -> Result { - let mut type_list = TypeList { list: vec![] }; - for ty in list { - type_list.list.push(TypeItem { - type_idx: *self.type_ids.get(ty).ok_or(anyhow!( - "Could not found type {} in dex builder", - ty.__str__() - ))? as u16, - }); - } - Ok(type_list) - } - - pub fn gen_dex_file_to_vec(&mut self) -> Result> { - let mut output = Cursor::new(Vec::::new()); - self.write_dex_file(&mut output)?; - Ok(output.into_inner()) - } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -2712,7 +1972,7 @@ impl FragSection { struct FragSectionManager { sizes: [u32; Self::NB_SECTION], nb_elt: [usize; Self::NB_SECTION], - offsets: [u32; Self::NB_SECTION], + //offsets: [u32; Self::NB_SECTION], editable: bool, } @@ -2722,7 +1982,7 @@ impl FragSectionManager { fn reset(&mut self) { self.sizes = [0; Self::NB_SECTION]; self.nb_elt = [0; Self::NB_SECTION]; - self.offsets = [0; Self::NB_SECTION]; + //self.offsets = [0; Self::NB_SECTION]; self.editable = true; } @@ -2858,6 +2118,7 @@ impl FragSectionManager { "{section:?}: 0x{offset:x} -> 0x{new_offset:x} (size: 0x{size:x}, \ nb elt: {nb_elt})" ); + offset = new_offset; } } }