1use std::io::{Seek, SeekFrom};
6use lazy_static::lazy_static;
7use regex::Regex;
8use log::{ warn, debug };
9
10use crate::dex::reader::DexReader;
11use crate::dex::access_flags::{ AccessFlag, AccessFlagType };
12use crate::dex::code_item::CodeItem;
13
14use crate::dex::strings::DexStrings;
15use crate::dex::types::DexTypes;
16use crate::dex::fields::DexFields;
17use crate::dex::methods::DexMethods;
18
19const NO_INDEX: u32 = 0xffffffff;
21
22lazy_static!{
23 static ref METHOD_REGEX: Regex = Regex::new(r"(?x)
25 (?P<class>L[a-zA-Z/$0-9]+;)
26 (->)
27 (?P<method><?[a-zA-Z0-9]+>?[\$\d+]*)
28 (?P<args>\(.*\).*)
29 ").unwrap();
30}
31
32#[derive(Debug)]
34pub struct ClassDefItem {
35 class_str: String,
36 access_flags: Vec<AccessFlag>,
37 superclass_str: Option<String>,
38 interfaces_off: u32,
39 source_file_str: Option<String>,
40 annotations_off: u32,
41 class_data_off: u32,
42 static_value_off: u32,
43 class_data: Option<ClassDataItem>
44}
45
46#[derive(Debug)]
47pub struct EncodedField {
48 field: String,
49 access_flags: Vec<AccessFlag>,
50}
51
52#[derive(Debug)]
53pub struct EncodedMethod {
54 pub proto: String,
55 pub access_flags: Vec<AccessFlag>,
56 pub code_item: Option<CodeItem>,
57}
58
59#[derive(Debug)]
60pub struct ClassDataItem {
61 static_fields: Vec<EncodedField>,
62 instance_fields: Vec<EncodedField>,
63 direct_methods: Vec<EncodedMethod>,
64 virtual_methods: Vec<EncodedMethod>,
65}
66
67#[derive(Debug)]
68pub struct DexClasses {
69 pub items: Vec<ClassDefItem>
70}
71
72impl DexClasses {
73 pub fn build(dex_reader: &mut DexReader,
74 offset: u32,
75 size: u32,
76 fields_list: &DexFields,
77 types_list: &DexTypes,
78 strings_list: &DexStrings,
79 methods_list: &DexMethods) -> Self {
80 dex_reader.bytes.seek(SeekFrom::Start(offset.into())).unwrap();
81
82 let mut methods = Vec::new();
83
84 for _ in 0..size {
85 let class_idx = dex_reader.read_u32().unwrap();
86 let access_flags = dex_reader.read_u32().unwrap();
87 let access_flags_decoded = AccessFlag::parse(access_flags,
88 AccessFlagType::Class);
89
90 let superclass_idx = dex_reader.read_u32().unwrap();
91 let interfaces_off = dex_reader.read_u32().unwrap();
92 let source_file_idx = dex_reader.read_u32().unwrap();
93 let annotations_off = dex_reader.read_u32().unwrap();
94 let class_data_off = dex_reader.read_u32().unwrap();
95 let static_value_off = dex_reader.read_u32().unwrap();
96
97 let class_str = types_list.items
99 .get(class_idx as usize).unwrap();
100
101 let mut superclass_str = None;
102 if superclass_idx != NO_INDEX {
103 superclass_str = Some(types_list.items
104 .get(superclass_idx as usize)
105 .unwrap());
106 }
107
108 let mut source_file_str = None;
109 if source_file_idx != NO_INDEX {
110 source_file_str = Some(strings_list.strings
111 .get(source_file_idx as usize)
112 .unwrap());
113 }
114
115 let mut class_data = None;
117 if class_data_off != 0 {
118 let current_offset = dex_reader.bytes.position();
122
123 dex_reader.bytes.seek(SeekFrom::Start(class_data_off.into())).unwrap();
125
126 let (static_fields_size, _) = dex_reader.read_uleb128().unwrap();
127 let (instance_fields_size, _) = dex_reader.read_uleb128().unwrap();
128 let (direct_methods_size, _) = dex_reader.read_uleb128().unwrap();
129 let (virtual_methods_size, _) = dex_reader.read_uleb128().unwrap();
130
131 let mut static_fields = Vec::<EncodedField>::with_capacity(static_fields_size as usize);
132 let mut instance_fields = Vec::<EncodedField>::with_capacity(instance_fields_size as usize);
133 let mut direct_methods = Vec::<EncodedMethod>::with_capacity(direct_methods_size as usize);
134 let mut virtual_methods = Vec::<EncodedMethod>::with_capacity(virtual_methods_size as usize);
135
136 let mut field_idx = 0;
138 for _ in 0..static_fields_size {
139 let (idx, _) = dex_reader.read_uleb128().unwrap();
140 let (access_flags, _) = dex_reader.read_uleb128().unwrap();
141
142 field_idx += idx;
143
144 let decoded_field = fields_list.items.get(field_idx as usize)
145 .unwrap()
146 .to_string();
147 let decoded_flags = AccessFlag::parse(access_flags,
148 AccessFlagType::Field);
149
150 static_fields.push(EncodedField {
151 field: decoded_field,
152 access_flags: decoded_flags
153 });
154 }
155
156 let mut field_idx = 0;
157 for _ in 0..instance_fields_size {
158 let (idx, _) = dex_reader.read_uleb128().unwrap();
159 let (access_flags, _) = dex_reader.read_uleb128().unwrap();
160
161 field_idx += idx;
162
163 let decoded_field = fields_list.items.get(field_idx as usize)
164 .unwrap()
165 .to_string();
166 let decoded_flags = AccessFlag::parse(access_flags,
167 AccessFlagType::Field);
168
169 instance_fields.push(EncodedField {
170 field: decoded_field,
171 access_flags: decoded_flags
172 });
173 }
174
175 let mut method_idx = 0;
177 for _ in 0..direct_methods_size {
178 let (idx, _) = dex_reader.read_uleb128().unwrap();
179 let (access_flags, _) = dex_reader.read_uleb128().unwrap();
180 let (code_offset, _) = dex_reader.read_uleb128().unwrap();
181
182 method_idx += idx;
183
184 let proto = methods_list.items.get(method_idx as usize)
185 .unwrap()
186 .to_string();
187 let decoded_flags = AccessFlag::parse(access_flags,
188 AccessFlagType::Method);
189
190 if code_offset == 0 {
191 direct_methods.push(EncodedMethod {
193 proto: proto.to_string(),
194 access_flags: decoded_flags,
195 code_item: None
196 });
197 } else {
198 let current_offset = dex_reader.bytes.position();
199 let code_item = CodeItem::build(dex_reader,
200 code_offset,
201 types_list);
202 dex_reader.bytes.seek(SeekFrom::Start(current_offset)).unwrap();
203
204 direct_methods.push(EncodedMethod {
205 proto: proto.to_string(),
206 access_flags: decoded_flags,
207 code_item: Some(code_item),
208 });
209 }
210 }
211
212 let mut method_idx = 0;
213 for _ in 0..virtual_methods_size {
214 let (idx, _) = dex_reader.read_uleb128().unwrap();
215 let (access_flags, _) = dex_reader.read_uleb128().unwrap();
216 let (code_offset, _) = dex_reader.read_uleb128().unwrap();
217
218 method_idx += idx;
219
220 let proto = methods_list.items.get(method_idx as usize)
221 .unwrap()
222 .to_string();
223 let decoded_flags = AccessFlag::parse(access_flags,
224 AccessFlagType::Method);
225
226 if code_offset == 0 {
227 virtual_methods.push(EncodedMethod {
229 proto: proto.to_string(),
230 access_flags: decoded_flags,
231 code_item: None
232 });
233 } else {
234 let current_offset = dex_reader.bytes.position();
235 let code_item = CodeItem::build(dex_reader,
236 code_offset,
237 types_list);
238 dex_reader.bytes.seek(SeekFrom::Start(current_offset)).unwrap();
239
240 virtual_methods.push(EncodedMethod {
241 proto: proto.to_string(),
242 access_flags: decoded_flags,
243 code_item: Some(code_item),
244 });
245 }
246 }
247
248 dex_reader.bytes.seek(SeekFrom::Start(current_offset)).unwrap();
250
251 class_data = Some(ClassDataItem {
252 static_fields,
253 instance_fields,
254 direct_methods,
255 virtual_methods,
256 });
257 }
258
259 methods.push(ClassDefItem {
260 class_str: class_str.to_string(),
261 access_flags: access_flags_decoded,
262 superclass_str: superclass_str.cloned(),
263 interfaces_off,
264 source_file_str: source_file_str.cloned(),
265 annotations_off,
266 class_data_off,
267 static_value_off,
268 class_data
269 });
270 }
271
272 DexClasses { items: methods }
273 }
274
275 pub fn get_class_def(&self, class_name: &String) -> Option<&ClassDefItem> {
276 for item in self.items.iter() {
277 if &item.class_str == class_name {
278 return Some(&item);
279 }
280 }
281
282 None
283 }
284}
285
286impl ClassDefItem {
287 pub fn get_class_name(&self) -> &String {
288 &self.class_str
289 }
290
291 pub fn get_access_flags(&self) -> String {
292 AccessFlag::vec_to_string(&self.access_flags)
293 }
294
295 pub fn get_methods(&self) -> Vec<&EncodedMethod> {
296 let mut methods = Vec::new();
297
298 if let Some(class_data) = &self.class_data {
299 methods.extend(&class_data.direct_methods);
300 methods.extend(&class_data.virtual_methods);
301 }
302
303 methods
304 }
305
306 pub fn get_encoded_method(&self, method_name: &String) -> Option<&EncodedMethod> {
307 if let Some(class_data) = &self.class_data {
308 for method in &class_data.direct_methods {
309 if method.get_method_name() == method_name {
310 return Some(method);
311 }
312 }
313 for method in &class_data.virtual_methods {
314 if method.get_method_name() == method_name {
315 return Some(method);
316 }
317 }
318 }
319 None
320 }
321}
322
323impl EncodedMethod {
324 pub fn get_proto(&self) -> &str {
325 &self.proto
326 }
327
328 pub fn get_method_name(&self) -> &str {
329 let matches = METHOD_REGEX.captures(&self.proto);
330 let method_name = match matches {
331 Some(matched) => {
332 match matched.name("method") {
333 Some(name) => name.as_str(),
334 None => ""
335 }
336 },
337 None => ""
338 };
339
340 if method_name.is_empty() {
341 warn!("Cannot retrieve method name from prototype");
342 debug!("Prototype: {}", &self.proto);
343 };
344
345 method_name
346 }
347
348 pub fn get_access_flags(&self) -> String {
349 AccessFlag::vec_to_string(&self.access_flags)
350 }
351}