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 };
21
22/// Representation of a DEX file
23#[derive(Debug)]
24pub struct DexFile {
25    /// Header of the file
26    pub header: DexHeader,
27    /// List of strings defined in the DEX file
28    pub strings: DexStrings,
29    /// List of types defined in the DEX file
30    pub types: DexTypes,
31    /// List of prototypes defined in the DEX file
32    pub protos: DexProtos,
33    /// List of class fields defined in the DEX file
34    pub fields: DexFields,
35    /// List of methods defined in the DEX file
36    pub methods: DexMethods,
37    /// List of classes defined in the DEX file
38    pub classes: DexClasses,
39}
40
41impl DexFile {
42    /// Parse a DEX file from the reader and create a `DexFile` object
43    pub fn build(mut dex_reader: DexReader) -> Self {
44        let dex_header = DexHeader::new(&mut dex_reader).unwrap();
45
46        let strings_list = DexStrings::build(&mut dex_reader,
47                                             dex_header.string_ids_off,
48                                             dex_header.string_ids_size);
49
50        let type_ids_list = DexTypes::build(&mut dex_reader,
51                                            dex_header.type_ids_off,
52                                            dex_header.type_ids_size,
53                                            &strings_list);
54
55        let proto_ids_list = DexProtos::build(&mut dex_reader,
56                                              dex_header.proto_ids_off,
57                                              dex_header.proto_ids_size,
58                                              &type_ids_list);
59
60        let field_ids_list = DexFields::build(&mut dex_reader,
61                                              dex_header.fields_ids_off,
62                                              dex_header.fields_ids_size,
63                                              &type_ids_list,
64                                              &strings_list);
65
66        let method_ids_list = DexMethods::build(&mut dex_reader,
67                                                dex_header.method_ids_off,
68                                                dex_header.method_ids_size,
69                                                &type_ids_list,
70                                                &proto_ids_list,
71                                                &strings_list);
72
73        let class_defs_list = DexClasses::build(&mut dex_reader,
74                                                dex_header.class_defs_off,
75                                                dex_header.class_defs_size,
76                                                &field_ids_list,
77                                                &type_ids_list,
78                                                &strings_list,
79                                                &method_ids_list);
80
81        DexFile {
82            header: dex_header,
83            strings: strings_list,
84            types: type_ids_list,
85            protos: proto_ids_list,
86            fields: field_ids_list,
87            methods: method_ids_list,
88            classes: class_defs_list,
89        }
90    }
91
92    /// Create a `DexFile` from a collection of `DexReader`.
93    /// This function will create an intermediary `DexFile` object for each reader and then merge
94    /// them into the final `DexFile`.
95    pub fn merge(readers: Vec<DexReader>) -> Self {
96        let mut strings_list = Vec::new();
97        let mut type_ids_list = Vec::new();
98        let mut proto_ids_list = Vec::new();
99        let mut field_ids_list = Vec::new();
100        let mut method_ids_list = Vec::new();
101        let mut class_defs_list = Vec::new();
102
103        info!("start merging DEX files");
104        for reader in readers.into_iter() {
105            let current_dex_file = DexFile::build(reader);
106
107            info!("  merging strings");
108            for string in current_dex_file.strings.strings.into_iter() {
109                strings_list.push(string);
110            }
111
112            info!("  merging types");
113            for type_id in current_dex_file.types.items.into_iter() {
114                type_ids_list.push(type_id);
115            }
116
117            info!("  merging protos");
118            for proto_id in current_dex_file.protos.items.into_iter() {
119                proto_ids_list.push(proto_id);
120            }
121
122            info!("  merging fields");
123            for field_id in current_dex_file.fields.items.into_iter() {
124                field_ids_list.push(field_id);
125            }
126
127            info!("  merging methods");
128            for method_id in current_dex_file.methods.items.into_iter() {
129                method_ids_list.push(method_id);
130            }
131
132            info!("  merging classes");
133            for class_def_id in current_dex_file.classes.items.into_iter() {
134                class_defs_list.push(class_def_id);
135            }
136        }
137
138        info!("removing strings duplicates and storing strings");
139        strings_list.dedup();
140        strings_list.sort();
141        info!("removing strings duplicates and storing types");
142        type_ids_list.dedup();
143        type_ids_list.sort();
144        info!("removing strings duplicates and storing protos");
145        proto_ids_list.dedup();
146        proto_ids_list.sort();
147        info!("removing strings duplicates and storing fields");
148        field_ids_list.dedup();
149        field_ids_list.sort();
150        info!("removing strings duplicates and storing methods");
151        method_ids_list.dedup();
152        method_ids_list.sort();
153        // class_defs_list.dedup();
154        // class_defs_list.sort();
155
156        info!("done merging");
157
158        let header = DexHeader {
159            version: [0x00; 3],
160            checksum: 0x0,
161            signature: [0x00; 20],
162            file_size: 0x00,
163            header_size: 0x00,
164            endian_tag: 0x00,
165            link_size: 0x00,
166            link_off: 0x00,
167            map_off: 0x00,
168            string_ids_size: strings_list.len() as u32,
169            string_ids_off: 0x00,
170            type_ids_size: type_ids_list.len() as u32,
171            type_ids_off: 0x00,
172            proto_ids_size: proto_ids_list.len() as u32,
173            proto_ids_off: 0x00,
174            fields_ids_size: field_ids_list.len() as u32,
175            fields_ids_off: 0x00,
176            method_ids_size: method_ids_list.len() as u32,
177            method_ids_off: 0x00,
178            class_defs_size: class_defs_list.len() as u32,
179            class_defs_off: 0x00,
180            data_size: 0x00,
181            data_off: 0x00
182        };
183
184        DexFile {
185            header: header,
186            strings: DexStrings { strings: strings_list },
187            types: DexTypes { items: type_ids_list },
188            protos: DexProtos { items: proto_ids_list },
189            fields: DexFields { items: field_ids_list },
190            methods: DexMethods { items: method_ids_list },
191            classes: DexClasses { items: class_defs_list },
192        }
193    }
194
195    /// Returns a vector containing the names of all the classes defined in the DEX file
196    pub fn get_classes_names(&self) -> Vec<&String> {
197        let mut class_names = Vec::new();
198
199        for class in &self.classes.items {
200            class_names.push(class.get_class_name());
201        }
202
203        class_names
204    }
205
206    /// Get the `ClassDefItem` object for a given class name
207    pub fn get_class_def(&self, class_name: &String) -> Option<&ClassDefItem> {
208        self.classes.get_class_def(class_name)
209    }
210
211    /// Get the method of a given class as a vector of `EncodedMethod` objects
212    pub fn get_methods_for_class(&self, class_name: &String) -> Vec<&EncodedMethod> {
213        if let Some(class_def) = self.get_class_def(class_name) {
214            return class_def.get_methods();
215        }
216        Vec::new()
217    }
218}