1use std::ffi::CStr;
4use std::slice::from_raw_parts;
5
6use crate::shuriken;
7use crate::dvm_access_flags::{ DvmAccessFlag, DvmAccessFlagType };
8
9#[derive(Debug, Clone, Copy, PartialEq)]
13pub enum DexTypes {
14 Fundamental,
16 Class,
18 Array,
20 Unknown
22}
23
24#[derive(Debug, Clone, Copy, PartialEq)]
28pub enum DexBasicTypes {
29 Boolean,
30 Byte,
31 Char,
32 Double,
33 Float,
34 Int,
35 Long,
36 Short,
37 Void,
38 FundamentalNone = 99
39}
40
41#[derive(Debug)]
45pub struct DvmHeader {
46 magic: [u8; 8],
48 checksum: u32,
50 signature: [u8; 20],
52 file_size: u32,
54 header_size: u32,
56 endian_tag: u32,
58 link_size: u32,
60 link_off: u32,
62 map_off: u32,
64 string_ids_size: u32,
66 string_ids_off: u32,
68 type_ids_size: u32,
70 type_ids_off: u32,
72 proto_ids_size: u32,
74 proto_ids_off: u32,
76 field_ids_size: u32,
78 field_ids_off: u32,
80 method_ids_size: u32,
82 method_ids_off: u32,
84 class_defs_size: u32,
86 class_defs_off: u32,
88 data_size: u32,
90 data_off: u32,
92}
93
94impl DvmHeader {
95 pub fn from_ptr(ptr: shuriken::dexheader_t) -> Self {
97 DvmHeader {
98 magic: ptr.magic,
99 checksum: ptr.checksum,
100 signature: ptr.signature,
101 file_size: ptr.file_size,
102 header_size: ptr.header_size,
103 endian_tag: ptr.endian_tag,
104 link_size: ptr.link_size,
105 link_off: ptr.link_off,
106 map_off: ptr.map_off,
107 string_ids_size: ptr.string_ids_size,
108 string_ids_off: ptr.string_ids_off,
109 type_ids_size: ptr.type_ids_size,
110 type_ids_off: ptr.type_ids_off,
111 proto_ids_size: ptr.proto_ids_size,
112 proto_ids_off: ptr.proto_ids_off,
113 field_ids_size: ptr.field_ids_size,
114 field_ids_off: ptr.field_ids_off,
115 method_ids_size: ptr.method_ids_size,
116 method_ids_off: ptr.method_ids_off,
117 class_defs_size: ptr.class_defs_size,
118 class_defs_off: ptr.class_defs_off,
119 data_size: ptr.data_size,
120 data_off: ptr.data_off,
121 }
122 }
123
124 pub fn magic(&self) -> &[u8; 8] {
126 &self.magic
127 }
128
129 pub fn checksum(&self) -> u32 {
131 self.checksum
132 }
133
134 pub fn signature(&self) -> &[u8; 20] {
136 &self.signature
137 }
138
139 pub fn file_size(&self) -> u32 {
141 self.file_size
142 }
143
144 pub fn header_size(&self) -> u32 {
146 self.header_size
147 }
148
149 pub fn endian_tag(&self) -> u32 {
151 self.endian_tag
152 }
153
154 pub fn link_size(&self) -> u32 {
156 self.link_size
157 }
158
159 pub fn link_off(&self) -> u32 {
161 self.link_off
162 }
163
164 pub fn map_off(&self) -> u32 {
166 self.map_off
167 }
168
169 pub fn string_ids_size(&self) -> u32 {
171 self.string_ids_size
172 }
173
174 pub fn string_ids_off(&self) -> u32 {
176 self.string_ids_off
177 }
178
179 pub fn type_ids_size(&self) -> u32 {
181 self.type_ids_size
182 }
183
184 pub fn type_ids_off(&self) -> u32 {
186 self.type_ids_off
187 }
188
189 pub fn proto_ids_size(&self) -> u32 {
191 self.proto_ids_size
192 }
193
194 pub fn proto_ids_off(&self) -> u32 {
196 self.proto_ids_off
197 }
198
199 pub fn field_ids_size(&self) -> u32 {
201 self.field_ids_size
202 }
203
204 pub fn field_ids_off(&self) -> u32 {
206 self.field_ids_off
207 }
208
209 pub fn method_ids_size(&self) -> u32 {
211 self.method_ids_size
212 }
213
214 pub fn method_ids_off(&self) -> u32 {
216 self.method_ids_off
217 }
218
219 pub fn class_defs_size(&self) -> u32 {
221 self.class_defs_size
222 }
223
224 pub fn class_defs_off(&self) -> u32 {
226 self.class_defs_off
227 }
228
229 pub fn data_size(&self) -> u32 {
231 self.data_size
232 }
233
234 pub fn data_off(&self) -> u32 {
236 self.data_off
237 }
238}
239
240#[derive(Debug)]
244pub struct DvmField {
245 class_name: String,
247 name: String,
249 field_type: DexTypes,
251 fundamental_value: DexBasicTypes,
256 type_value: String,
258 access_flags: Vec<DvmAccessFlag>
260}
261
262impl DvmField {
263 pub fn from_ptr(ptr: shuriken::hdvmfield_t) -> Self {
265 let class_name = unsafe {
266 CStr::from_ptr(ptr.class_name)
267 .to_str()
268 .expect("Error: string is not valid UTF-8")
269 .to_string()
270 };
271
272 let name = unsafe {
273 CStr::from_ptr(ptr.name)
274 .to_str()
275 .expect("Error: string is not valid UTF-8")
276 .to_string()
277 };
278
279 let type_value = unsafe {
280 CStr::from_ptr(ptr.type_value)
281 .to_str()
282 .expect("Error: string is not valid UTF-8")
283 .to_string()
284 };
285
286 let access_flags = DvmAccessFlag::parse(
287 ptr.access_flags as u32,
288 DvmAccessFlagType::Class
289 );
290
291 let field_type = match ptr.type_ {
292 0 => DexTypes::Fundamental,
293 1 => DexTypes::Class,
294 2 => DexTypes::Array,
295 _ => DexTypes::Unknown,
296 };
297
298 let fundamental_value = if field_type == DexTypes::Fundamental {
299 match ptr.fundamental_value {
300 0 => DexBasicTypes::Boolean,
301 1 => DexBasicTypes::Byte,
302 2 => DexBasicTypes::Char,
303 3 => DexBasicTypes::Double,
304 4 => DexBasicTypes::Float,
305 5 => DexBasicTypes::Int,
306 6 => DexBasicTypes::Long,
307 7 => DexBasicTypes::Short,
308 8 => DexBasicTypes::Void,
309 _ => panic!("Invalid fundamental value")
310 }
311 } else {
312 DexBasicTypes::FundamentalNone
313 };
314
315 Self {
316 class_name,
317 name,
318 field_type,
319 fundamental_value,
320 type_value,
321 access_flags
322 }
323 }
324
325 pub fn class_name(&self) -> &str {
327 &self.class_name
328 }
329
330 pub fn name(&self) -> &str {
332 &self.name
333 }
334
335 pub fn field_type(&self) -> DexTypes {
337 self.field_type
338 }
339
340 pub fn fundamental_value(&self) -> DexBasicTypes {
342 self.fundamental_value
343 }
344
345 pub fn type_value(&self) -> &str {
347 &self.type_value
348 }
349
350 pub fn access_flags(&self) -> &[DvmAccessFlag] {
352 &self.access_flags
353 }
354}
355
356#[derive(Debug, PartialEq)]
360pub struct DvmMethod {
361 class_name: String,
362 method_name: String,
363 prototype: String,
364 access_flags: Vec<DvmAccessFlag>,
365 code_size: usize,
366 code: Vec<u8>,
367 dalvik_name: String,
368 demangled_name: String
369}
370
371impl DvmMethod {
372 pub fn from_ptr(method: shuriken::hdvmmethod_t) -> Self {
374 let class_name = unsafe {
375 CStr::from_ptr(method.class_name)
376 .to_str()
377 .expect("Error: string is not valid UTF-8")
378 .to_string()
379 };
380
381 let method_name = unsafe {
382 CStr::from_ptr(method.method_name)
383 .to_str()
384 .expect("Error: string is not valid UTF-8")
385 .to_string()
386 };
387
388 let prototype = unsafe {
389 CStr::from_ptr(method.prototype)
390 .to_str()
391 .expect("Error: string is not valid UTF-8")
392 .to_string()
393 };
394
395 let access_flags = DvmAccessFlag::parse(method.access_flags.into(), DvmAccessFlagType::Method);
396
397 let dalvik_name = unsafe {
398 CStr::from_ptr(method.dalvik_name)
399 .to_str()
400 .expect("Error: string is not valid UTF-8")
401 .to_string()
402 };
403
404 let demangled_name = unsafe {
405 CStr::from_ptr(method.demangled_name)
406 .to_str()
407 .expect("Error: string is not valid UTF-8")
408 .to_string()
409 };
410
411 let code = unsafe {
412 from_raw_parts(method.code, method.code_size as usize)
413 .to_vec()
414 };
415
416 DvmMethod {
417 class_name,
418 method_name,
419 prototype,
420 access_flags,
421 code_size: method.code_size as usize,
422 code,
423 dalvik_name,
424 demangled_name
425 }
426 }
427
428 pub fn class_name(&self) -> &str {
430 &self.class_name
431 }
432
433 pub fn method_name(&self) -> &str {
435 &self.method_name
436 }
437
438 pub fn prototype(&self) -> &str {
440 &self.prototype
441 }
442
443 pub fn access_flags(&self) -> &[DvmAccessFlag] {
445 &self.access_flags
446 }
447
448 pub fn code_size(&self) -> usize {
450 self.code_size
451 }
452
453 pub fn code(&self) -> &[u8] {
455 &self.code
456 }
457
458 pub fn dalvik_name(&self) -> &str {
460 &self.dalvik_name
461 }
462
463 pub fn demangled_name(&self) -> &str {
465 &self.demangled_name
466 }
467}
468
469
470#[derive(Debug)]
474pub struct DvmClass {
475 class_name: String,
476 super_class: String,
477 source_file: String,
478 access_flags: Vec<DvmAccessFlag>,
479 direct_methods_size: usize,
480 direct_methods: Vec<DvmMethod>,
481 virtual_methods_size: usize,
482 virtual_methods: Vec<DvmMethod>,
483 instance_fields_size: usize,
484 instance_fields: Vec<DvmField>,
485 static_fields_size: usize,
486 static_fields: Vec<DvmField>
487}
488
489impl DvmClass {
490 pub fn from_ptr(ptr: shuriken::hdvmclass_t) -> Self {
491 let class_name = unsafe {
492 CStr::from_ptr(ptr.class_name)
493 .to_str()
494 .expect("Error: string is not valid UTF-8")
495 .to_string()
496 };
497
498 let super_class = unsafe {
499 CStr::from_ptr(ptr.super_class)
500 .to_str()
501 .expect("Error: string is not valid UTF-8")
502 .to_string()
503 };
504
505 let source_file = unsafe {
506 CStr::from_ptr(ptr.source_file)
507 .to_str()
508 .expect("Error: string is not valid UTF-8")
509 .to_string()
510 };
511
512 let access_flags = DvmAccessFlag::parse(
513 ptr.access_flags as u32,
514 DvmAccessFlagType::Class
515 );
516
517 let direct_methods = unsafe {
518 from_raw_parts(
519 ptr.direct_methods,
520 ptr.direct_methods_size.into()
521 )
522 .iter()
523 .map(|method| DvmMethod::from_ptr(*method))
524 .collect::<Vec<DvmMethod>>()
525 };
526
527 let virtual_methods = unsafe {
528 from_raw_parts(
529 ptr.virtual_methods,
530 ptr.virtual_methods_size.into()
531 )
532 .iter()
533 .map(|method| DvmMethod::from_ptr(*method))
534 .collect::<Vec<DvmMethod>>()
535 };
536
537 let instance_fields = unsafe {
538 from_raw_parts(
539 ptr.instance_fields,
540 ptr.instance_fields_size.into()
541 )
542 .iter()
543 .map(|field| DvmField::from_ptr(*field))
544 .collect::<Vec<DvmField>>()
545 };
546
547 let static_fields = unsafe {
548 from_raw_parts(
549 ptr.static_fields,
550 ptr.static_fields_size.into()
551 )
552 .iter()
553 .map(|field| DvmField::from_ptr(*field))
554 .collect::<Vec<DvmField>>()
555 };
556
557 DvmClass {
558 class_name,
559 super_class,
560 source_file,
561 access_flags,
562 direct_methods_size: ptr.direct_methods_size as usize,
563 direct_methods,
564 virtual_methods_size: ptr.virtual_methods_size as usize,
565 virtual_methods,
566 instance_fields_size: ptr.instance_fields_size as usize,
567 instance_fields,
568 static_fields_size: ptr.static_fields_size as usize,
569 static_fields
570 }
571 }
572
573 pub fn class_name(&self) -> &str {
575 self.class_name.as_str()
576 }
577
578 pub fn super_class(&self) -> &str {
580 &self.super_class
581 }
582
583 pub fn source_file(&self) -> &str {
585 &self.source_file
586 }
587
588 pub fn access_flags(&self) -> &[DvmAccessFlag] {
590 &self.access_flags
591 }
592
593 pub fn direct_methods_size(&self) -> usize {
595 self.direct_methods_size
596 }
597
598 pub fn direct_methods(&self) -> &[DvmMethod] {
600 &self.direct_methods
601 }
602
603 pub fn virtual_methods_size(&self) -> usize {
605 self.virtual_methods_size
606 }
607
608 pub fn virtual_methods(&self) -> &[DvmMethod] {
610 &self.virtual_methods
611 }
612
613 pub fn instance_fields_size(&self) -> usize {
615 self.instance_fields_size
616 }
617
618 pub fn instance_fields(&self) -> &[DvmField] {
620 &self.instance_fields
621 }
622
623 pub fn static_fields_size(&self) -> usize {
625 self.static_fields_size
626 }
627
628 pub fn static_fields(&self) -> &[DvmField] {
630 &self.static_fields
631 }
632}