1use log::info;
12
13use crate::dex::reader::DexReader;
14use crate::dex::header::DexHeader;
15use crate::dex::strings::DexStrings;
16use crate::dex::types::DexTypes;
17use crate::dex::protos::DexProtos;
18use crate::dex::fields::DexFields;
19use crate::dex::methods::DexMethods;
20use crate::dex::classes::{ DexClasses, ClassDefItem, EncodedMethod };
21use crate::error::DexError;
22
23#[derive(Debug)]
25pub struct DexFile {
26 pub header: DexHeader,
28 pub strings: DexStrings,
30 pub types: DexTypes,
32 pub protos: DexProtos,
34 pub fields: DexFields,
36 pub methods: DexMethods,
38 pub classes: DexClasses,
40}
41
42impl DexFile {
43 pub fn build(mut dex_reader: DexReader) -> Result<Self, DexError> {
45 let dex_header = DexHeader::new(&mut dex_reader)?;
46
47 let strings_list = DexStrings::build(&mut dex_reader,
48 dex_header.string_ids_off,
49 dex_header.string_ids_size)?;
50
51 let type_ids_list = DexTypes::build(&mut dex_reader,
52 dex_header.type_ids_off,
53 dex_header.type_ids_size,
54 &strings_list)?;
55
56 let proto_ids_list = DexProtos::build(&mut dex_reader,
57 dex_header.proto_ids_off,
58 dex_header.proto_ids_size,
59 &type_ids_list)?;
60
61 let field_ids_list = DexFields::build(&mut dex_reader,
62 dex_header.fields_ids_off,
63 dex_header.fields_ids_size,
64 &type_ids_list,
65 &strings_list)?;
66
67 let method_ids_list = DexMethods::build(&mut dex_reader,
68 dex_header.method_ids_off,
69 dex_header.method_ids_size,
70 &type_ids_list,
71 &proto_ids_list,
72 &strings_list)?;
73
74 let class_defs_list = DexClasses::build(&mut dex_reader,
75 dex_header.class_defs_off,
76 dex_header.class_defs_size,
77 &field_ids_list,
78 &type_ids_list,
79 &strings_list,
80 &method_ids_list)?;
81
82 Ok(DexFile {
83 header: dex_header,
84 strings: strings_list,
85 types: type_ids_list,
86 protos: proto_ids_list,
87 fields: field_ids_list,
88 methods: method_ids_list,
89 classes: class_defs_list,
90 })
91 }
92
93 pub fn merge(readers: Vec<DexReader>) -> Result<Self, DexError> {
98 let mut strings_list = Vec::new();
99 let mut type_ids_list = Vec::new();
100 let mut proto_ids_list = Vec::new();
101 let mut field_ids_list = Vec::new();
102 let mut method_ids_list = Vec::new();
103 let mut class_defs_list = Vec::new();
104
105 info!("start merging DEX files");
106 for reader in readers.into_iter() {
107 let current_dex_file = DexFile::build(reader)?;
108
109 info!(" merging strings");
110 for string in current_dex_file.strings.strings.into_iter() {
111 strings_list.push(string);
112 }
113
114 info!(" merging types");
115 for type_id in current_dex_file.types.items.into_iter() {
116 type_ids_list.push(type_id);
117 }
118
119 info!(" merging protos");
120 for proto_id in current_dex_file.protos.items.into_iter() {
121 proto_ids_list.push(proto_id);
122 }
123
124 info!(" merging fields");
125 for field_id in current_dex_file.fields.items.into_iter() {
126 field_ids_list.push(field_id);
127 }
128
129 info!(" merging methods");
130 for method_id in current_dex_file.methods.items.into_iter() {
131 method_ids_list.push(method_id);
132 }
133
134 info!(" merging classes");
135 for class_def_id in current_dex_file.classes.items.into_iter() {
136 class_defs_list.push(class_def_id);
137 }
138 }
139
140 info!("removing strings duplicates and storing strings");
141 strings_list.dedup();
142 strings_list.sort();
143 info!("removing strings duplicates and storing types");
144 type_ids_list.dedup();
145 type_ids_list.sort();
146 info!("removing strings duplicates and storing protos");
147 proto_ids_list.dedup();
148 proto_ids_list.sort();
149 info!("removing strings duplicates and storing fields");
150 field_ids_list.dedup();
151 field_ids_list.sort();
152 info!("removing strings duplicates and storing methods");
153 method_ids_list.dedup();
154 method_ids_list.sort();
155 info!("done merging");
159
160 let header = DexHeader {
161 version: [0x00; 3],
162 checksum: 0x0,
163 signature: [0x00; 20],
164 file_size: 0x00,
165 header_size: 0x00,
166 endian_tag: 0x00,
167 link_size: 0x00,
168 link_off: 0x00,
169 map_off: 0x00,
170 string_ids_size: strings_list.len() as u32,
171 string_ids_off: 0x00,
172 type_ids_size: type_ids_list.len() as u32,
173 type_ids_off: 0x00,
174 proto_ids_size: proto_ids_list.len() as u32,
175 proto_ids_off: 0x00,
176 fields_ids_size: field_ids_list.len() as u32,
177 fields_ids_off: 0x00,
178 method_ids_size: method_ids_list.len() as u32,
179 method_ids_off: 0x00,
180 class_defs_size: class_defs_list.len() as u32,
181 class_defs_off: 0x00,
182 data_size: 0x00,
183 data_off: 0x00
184 };
185
186 Ok(DexFile {
187 header,
188 strings: DexStrings { strings: strings_list },
189 types: DexTypes { items: type_ids_list },
190 protos: DexProtos { items: proto_ids_list },
191 fields: DexFields { items: field_ids_list },
192 methods: DexMethods { items: method_ids_list },
193 classes: DexClasses { items: class_defs_list },
194 })
195 }
196
197 pub fn get_classes_names(&self) -> Vec<&String> {
199 let mut class_names = Vec::new();
200
201 for class in &self.classes.items {
202 class_names.push(class.get_class_name());
203 }
204
205 class_names
206 }
207
208 pub fn get_class_def(&self, class_name: &String) -> Option<&ClassDefItem> {
210 self.classes.get_class_def(class_name)
211 }
212
213 pub fn get_methods_for_class(&self, class_name: &String) -> Vec<&EncodedMethod> {
215 if let Some(class_def) = self.get_class_def(class_name) {
216 return class_def.get_methods();
217 }
218
219 Vec::new()
220 }
221}