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