rusty_dex/dex/
methods.rs

1//! Methods identifiers
2//!
3//! This module deals with method identifiers. Each DEX file contains a list
4//! of identifiers for all methods reffered to in the code. The list is sorted
5//! by the defining type (by `type_id` index), method name (by `string_id`
6//! index), and method prototype (by `proto_id` index), and cannot contain
7//! duplicates.
8
9use std::io::{Seek, SeekFrom};
10use std::cmp::Ordering;
11
12use crate::error::DexError;
13use crate::dex::reader::DexReader;
14use crate::dex::types::DexTypes;
15use crate::dex::protos::DexProtos;
16use crate::dex::strings::DexStrings;
17
18/// Identifier of a method
19#[derive(Debug)]
20struct MethodIdItem {
21    class_idx: u16,
22    proto_idx: u16,
23    name_idx: u32,
24    decoded: String
25}
26
27/// Sorted list of method IDs
28#[derive(Debug)]
29pub struct DexMethods {
30    pub items: Vec<String>
31}
32
33impl DexMethods {
34    /// Implement correct sorting method for method identifiers
35    fn sort(a: &MethodIdItem, b: &MethodIdItem) -> Ordering {
36        // First sort by defining type
37        let mut order = a.class_idx.cmp(&b.class_idx);
38
39        if order == Ordering::Equal {
40            // If that fails, sort by method name
41            order = a.name_idx.cmp(&b.name_idx);
42        }
43
44        if order == Ordering::Equal {
45            // If that fails too, sort by prototype
46            order = a.proto_idx.cmp(&b.proto_idx);
47        }
48
49        order
50    }
51
52    /// Build the list of method identifiers from a file
53    pub fn build(dex_reader: &mut DexReader,
54                 offset: u32,
55                 size: u32,
56                 types_list: &DexTypes,
57                 protos_list: &DexProtos,
58                 strings_list: &DexStrings) -> Result<Self, DexError> {
59        dex_reader.bytes.seek(SeekFrom::Start(offset.into()))?;
60
61        let mut methods = Vec::new();
62
63        for _ in 0..size {
64            let class_idx = dex_reader.read_u16()?;
65            let proto_idx = dex_reader.read_u16()?;
66            let name_idx = dex_reader.read_u32()?;
67
68            let mut decoded = String::new();
69            decoded.push_str(types_list.items.get(class_idx as usize).ok_or(DexError::InvalidTypeIdx)?);
70            decoded.push_str("->");
71            decoded.push_str(strings_list.strings.get(name_idx as usize).ok_or(DexError::InvalidStringIdx)?);
72            decoded.push_str(protos_list.items.get(proto_idx as usize).ok_or(DexError::InvalidTypeIdx)?); 
73
74            methods.push(MethodIdItem {
75                class_idx,
76                proto_idx,
77                name_idx,
78                decoded
79            });
80        }
81
82        methods.sort_by(DexMethods::sort);
83
84        let mut items = Vec::new();
85        for dex_method in methods.into_iter() {
86            items.push(dex_method.decoded);
87        }
88        items.dedup();
89
90        Ok(DexMethods { items })
91    }
92}