rusty_dex/dex/
file.rs

1//! Representation of a DEX file
2//!
3//! This is the main class of the parser. When creating `DexFile` object, the builder will parse
4//! the header and from there decode the contents of the file (strings, methods, etc). Some apps
5//! will have multiple DEX files. In this case, the builder will initially create a `DexFile`
6//! object per DEX file and then merge them into one. This extra step is needed as the contents of
7//! the final `DexFile` object must contain all the contents of the intermediary DEX files but
8//! sorted (the actual sorting method depends on the type of content being sorted -- see the
9//! classes documentations for details).
10
11use 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/// Representation of a DEX file
24#[derive(Debug)]
25pub struct DexFile {
26    /// Header of the file
27    pub header: DexHeader,
28    /// List of strings defined in the DEX file
29    pub strings: DexStrings,
30    /// List of types defined in the DEX file
31    pub types: DexTypes,
32    /// List of prototypes defined in the DEX file
33    pub protos: DexProtos,
34    /// List of class fields defined in the DEX file
35    pub fields: DexFields,
36    /// List of methods defined in the DEX file
37    pub methods: DexMethods,
38    /// List of classes defined in the DEX file
39    pub classes: DexClasses,
40}
41
42impl DexFile {
43    /// Parse a DEX file from the reader and create a `DexFile` object
44    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    /// Create a `DexFile` from a collection of `DexReader`.
94    ///
95    /// This function will create an intermediary `DexFile` object for each reader and then merge
96    /// them into the final `DexFile`.
97    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        // class_defs_list.dedup();
156        // class_defs_list.sort();
157
158        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    /// Returns a vector containing the names of all the classes defined in the DEX file
198    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    /// Get the `ClassDefItem` object for a given class name
209    pub fn get_class_def(&self, class_name: &String) -> Option<&ClassDefItem> {
210        self.classes.get_class_def(class_name)
211    }
212
213    /// Get the method of a given class as a vector of `EncodedMethod` objects
214    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}