shuriken_bindings/
parser.rs

1//! Parser data structs
2
3use std::ffi::CStr;
4use std::slice::from_raw_parts;
5
6use crate::shuriken;
7use crate::dvm_access_flags::{ DvmAccessFlag, DvmAccessFlagType };
8
9/// Type alias for Shuriken's `htype_e`
10///
11/// DEX types of the DVM we have by default fundamental, classes and array
12#[derive(Debug, Clone, Copy, PartialEq)]
13pub enum DexTypes {
14    /// Fundamental type (int, float...)
15    Fundamental,
16    /// User defined class
17    Class,
18    /// Array type
19    Array,
20    /// Maybe wrong?
21    Unknown
22}
23
24/// Type alias for Shuriken's `hfundamental_e`
25///
26/// Enum with the basic DEX types
27#[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/// Type alias for Shuriken's `dexheader_t`
42///
43/// Structure which contains the information from the header of a DEX file
44#[derive(Debug)]
45pub struct DvmHeader {
46    /// Magic bytes from dex, different values are possible
47    magic: [u8; 8],
48    /// Checksum to see if file is correct
49    checksum: u32,
50    /// Signature of dex
51    signature: [u8; 20],
52    /// Current file size
53    file_size: u32,
54    /// Size of this header
55    header_size: u32,
56    /// Type of endianess of the file
57    endian_tag: u32,
58    /// Size of the link section, or 0 if this file isn't statically linked
59    link_size: u32,
60    /// Offset from the start of the file to the link section
61    link_off: u32,
62    /// Offset from the start of the file to the map item
63    map_off: u32,
64    /// Number of DexStrings
65    string_ids_size: u32,
66    /// Offset of the DexStrings
67    string_ids_off: u32,
68    /// Number of DexTypes
69    type_ids_size: u32,
70    /// Offset of the DexTypes
71    type_ids_off: u32,
72    /// Number of prototypes
73    proto_ids_size: u32,
74    /// Offset of the prototypes
75    proto_ids_off: u32,
76    /// Number of fields
77    field_ids_size: u32,
78    /// Offset of the fields
79    field_ids_off: u32,
80    /// Number of methods
81    method_ids_size: u32,
82    /// Offset of the methods
83    method_ids_off: u32,
84    /// Number of class definitions
85    class_defs_size: u32,
86    /// Offset of the class definitions
87    class_defs_off: u32,
88    /// Data area, containing all the support data for the tables listed above
89    data_size: u32,
90    /// Data offset
91    data_off: u32,
92}
93
94impl DvmHeader {
95    /// Convert an `dexheader_t` into a `DvmHeader`
96    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    /// Returns a reference to the magic bytes from DEX
125    pub fn magic(&self) -> &[u8; 8] {
126        &self.magic
127    }
128
129    /// Returns a reference to the checksum
130    pub fn checksum(&self) -> u32 {
131        self.checksum
132    }
133
134    /// Returns a reference to the signature of DEX
135    pub fn signature(&self) -> &[u8; 20] {
136        &self.signature
137    }
138
139    /// Returns the current file size
140    pub fn file_size(&self) -> u32 {
141        self.file_size
142    }
143
144    /// Returns the size of this header
145    pub fn header_size(&self) -> u32 {
146        self.header_size
147    }
148
149    /// Returns the type of endianess of the file
150    pub fn endian_tag(&self) -> u32 {
151        self.endian_tag
152    }
153
154    /// Returns the size of the link section, or 0 if this file isn't statically linked
155    pub fn link_size(&self) -> u32 {
156        self.link_size
157    }
158
159    /// Returns the offset from the start of the file to the link section
160    pub fn link_off(&self) -> u32 {
161        self.link_off
162    }
163
164    /// Returns the offset from the start of the file to the map item
165    pub fn map_off(&self) -> u32 {
166        self.map_off
167    }
168
169    /// Returns the number of DexStrings
170    pub fn string_ids_size(&self) -> u32 {
171        self.string_ids_size
172    }
173
174    /// Returns the offset of the DexStrings
175    pub fn string_ids_off(&self) -> u32 {
176        self.string_ids_off
177    }
178
179    /// Returns the number of DexTypes
180    pub fn type_ids_size(&self) -> u32 {
181        self.type_ids_size
182    }
183
184    /// Returns the offset of the DexTypes
185    pub fn type_ids_off(&self) -> u32 {
186        self.type_ids_off
187    }
188
189    /// Returns the number of prototypes
190    pub fn proto_ids_size(&self) -> u32 {
191        self.proto_ids_size
192    }
193
194    /// Returns the offset of the prototypes
195    pub fn proto_ids_off(&self) -> u32 {
196        self.proto_ids_off
197    }
198
199    /// Returns the number of fields
200    pub fn field_ids_size(&self) -> u32 {
201        self.field_ids_size
202    }
203
204    /// Returns the offset of the fields
205    pub fn field_ids_off(&self) -> u32 {
206        self.field_ids_off
207    }
208
209    /// Returns the number of methods
210    pub fn method_ids_size(&self) -> u32 {
211        self.method_ids_size
212    }
213
214    /// Returns the offset of the methods
215    pub fn method_ids_off(&self) -> u32 {
216        self.method_ids_off
217    }
218
219    /// Returns the number of class definitions
220    pub fn class_defs_size(&self) -> u32 {
221        self.class_defs_size
222    }
223
224    /// Returns the offset of the class definitions
225    pub fn class_defs_off(&self) -> u32 {
226        self.class_defs_off
227    }
228
229    /// Returns the data area, containing all the support data for the tables listed above
230    pub fn data_size(&self) -> u32 {
231        self.data_size
232    }
233
234    /// Returns the data offset
235    pub fn data_off(&self) -> u32 {
236        self.data_off
237    }
238}
239
240/// Type alias for Shuriken's `hdvmfield_t`
241///
242/// Structure which keeps information from a field this can be accessed from the class data
243#[derive(Debug)]
244pub struct DvmField {
245    /// Name of the class the field belong to
246    class_name: String,
247    /// Name of the field
248    name: String,
249    /// Type of the field
250    field_type: DexTypes,
251    /// If `field_type` is `Fundamental`
252    ///
253    /// Note: if `field_type` is `Array` and the base type is
254    /// a fundamental value, it contains that value
255    fundamental_value: DexBasicTypes,
256    /// String value of the type
257    type_value: String,
258    /// Access flags of the field
259    access_flags: Vec<DvmAccessFlag>
260}
261
262impl DvmField {
263    /// Convert an `hdvmfield_t` into a `DvmField`
264    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    /// Return a reference to the class name
326    pub fn class_name(&self) -> &str {
327        &self.class_name
328    }
329
330    /// Return a reference to the field name
331    pub fn name(&self) -> &str {
332        &self.name
333    }
334
335    /// Return a reference to the field type
336    pub fn field_type(&self) -> DexTypes {
337        self.field_type
338    }
339
340    /// Return a reference to the fundamental value
341    pub fn fundamental_value(&self) -> DexBasicTypes {
342        self.fundamental_value
343    }
344
345    /// Return a reference to the field type value
346    pub fn type_value(&self) -> &str {
347        &self.type_value
348    }
349
350    /// Return a reference to the access flags
351    pub fn access_flags(&self) -> &[DvmAccessFlag] {
352        &self.access_flags
353    }
354}
355
356/// Type alias for Shuriken's `hdvmmethod_t`
357///
358/// Structure which keeps information from a method this can be accessed from the class data
359#[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    /// Convert an `hdvmmethod_t` into a `DvmMethod`
373    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    /// Return a reference to the class name
429    pub fn class_name(&self) -> &str {
430        &self.class_name
431    }
432
433    /// Return a reference to the method name
434    pub fn method_name(&self) -> &str {
435        &self.method_name
436    }
437
438    /// Return a reference to the method prototype
439    pub fn prototype(&self) -> &str {
440        &self.prototype
441    }
442
443    /// Return a reference to the method access flags
444    pub fn access_flags(&self) -> &[DvmAccessFlag] {
445        &self.access_flags
446    }
447
448    /// Return the method's code size
449    pub fn code_size(&self) -> usize {
450        self.code_size
451    }
452
453    /// Return the method's code
454    pub fn code(&self) -> &[u8] {
455        &self.code
456    }
457
458    /// Return a reference to the dalvik name
459    pub fn dalvik_name(&self) -> &str {
460        &self.dalvik_name
461    }
462
463    /// Return a reference to the method demangled name
464    pub fn demangled_name(&self) -> &str {
465        &self.demangled_name
466    }
467}
468
469
470/// Type alias for Shuriken's `hdvmclass_t`
471///
472/// Structure representing the classes in the DEX file
473#[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    /// Returns a reference to the class name
574    pub fn class_name(&self) -> &str {
575        self.class_name.as_str()
576    }
577
578    /// Returns a reference to the super class
579    pub fn super_class(&self) -> &str {
580        &self.super_class
581    }
582
583    /// Returns a reference to the source file
584    pub fn source_file(&self) -> &str {
585        &self.source_file
586    }
587
588    /// Returns a reference to the access flags
589    pub fn access_flags(&self) -> &[DvmAccessFlag] {
590        &self.access_flags
591    }
592
593    /// Returns a reference to the direct methods size
594    pub fn direct_methods_size(&self) -> usize {
595        self.direct_methods_size
596    }
597
598    /// Returns a reference to the direct methods
599    pub fn direct_methods(&self) -> &[DvmMethod] {
600        &self.direct_methods
601    }
602
603    /// Returns a reference to the virtual methods size
604    pub fn virtual_methods_size(&self) -> usize {
605        self.virtual_methods_size
606    }
607
608    /// Returns a reference to the virtual methods
609    pub fn virtual_methods(&self) -> &[DvmMethod] {
610        &self.virtual_methods
611    }
612
613    /// Returns a reference to the instance fields size
614    pub fn instance_fields_size(&self) -> usize {
615        self.instance_fields_size
616    }
617
618    /// Returns a reference to the instance fields
619    pub fn instance_fields(&self) -> &[DvmField] {
620        &self.instance_fields
621    }
622
623    /// Returns a reference to the static fields size
624    pub fn static_fields_size(&self) -> usize {
625        self.static_fields_size
626    }
627
628    /// Returns a reference to the static fields
629    pub fn static_fields(&self) -> &[DvmField] {
630        &self.static_fields
631    }
632}