rusty_dex/dex/
code_item.rs

1//! DEX bytecode
2//!
3//! Code item elements contain the actual bytecode of the app.
4//! Each code item represent a function and the associated bytecode,
5//! along with some metadata such as the number of registers, try/catch
6//! offsets, etc.
7
8use std::io::{Seek, SeekFrom};
9
10use crate::error::DexError;
11use crate::dex::{
12    reader::DexReader,
13    types::DexTypes,
14    instructions,
15    instructions::Instructions
16};
17
18/// A `try` statement with offset to the `catch` part
19#[derive(Clone, Debug)]
20pub struct TryItem {
21    start_addr : u32,
22    insn_count : u16,
23    handler_off: u16
24}
25
26/// A `catch` statement
27#[derive(Clone, Debug)]
28pub struct EncodedCatchHandler {
29    size          : i32,
30    handlers      : Vec<EncodedTypeAddrPair>,
31    catch_all_addr: Option<u32>,
32}
33
34/// Addresses of the handler for an exception of the given type
35#[derive(Clone, Debug)]
36pub struct EncodedTypeAddrPair {
37    decoded_type: String,
38    addr        : u32,
39}
40
41/// Code structure for a method
42#[derive(Debug)]
43pub struct CodeItem {
44    registers_size: u16,
45    ins_size      : u16,
46    outs_size     : u16,
47    debug_info_off: u32,
48    pub insns         : Option<Vec<Instructions>>,
49    tries         : Option<Vec<TryItem>>,
50    handlers      : Option<Vec<EncodedCatchHandler>>
51}
52
53impl CodeItem {
54    /// Build a `CodeItem` struct from the reader
55    ///
56    /// The `offset` argument corresponds to the offset of the code item in the cursor
57    pub fn build(dex_reader: &mut DexReader,
58                 offset: u32,
59                 types_list: &DexTypes) -> Result<Self, DexError> {
60
61        // Go to start of code item
62        dex_reader.bytes.seek(SeekFrom::Start(offset.into()))?;
63
64        // Get the metadata
65        let registers_size = dex_reader.read_u16()?;
66        let ins_size       = dex_reader.read_u16()?;
67        let outs_size      = dex_reader.read_u16()?;
68        let tries_size     = dex_reader.read_u16()?;
69        let debug_info_off = dex_reader.read_u32()?;
70        let insns_size     = dex_reader.read_u32()?;
71
72        // Get the actual bytecode
73        let mut insns = Vec::with_capacity(insns_size as usize);
74        let end_offset = dex_reader.bytes.position() + (insns_size * 2) as u64;
75
76        // No need to update the stream's position manually: it is updated in
77        // `parse_instruction` when reading bytes from it
78        while dex_reader.bytes.position() < end_offset {
79            let _ = instructions::parse_instruction(dex_reader, &mut insns)?;
80        }
81
82        // Check if there is some padding
83        if tries_size != 0 && insns_size % 2 == 1 {
84            _ = dex_reader.read_u16()?;
85        }
86
87        let mut tries = Vec::<TryItem>::new();
88        let mut handlers = Vec::<EncodedCatchHandler>::new();
89
90        if tries_size != 0 {
91            tries = Vec::with_capacity(tries_size as usize);
92            for _ in 0..tries_size {
93                let start_addr = dex_reader.read_u32()?;
94                let insn_count = dex_reader.read_u16()?;
95                let handler_off = dex_reader.read_u16()?;
96
97                tries.push(TryItem {
98                    start_addr,
99                    insn_count,
100                    handler_off
101                });
102            }
103
104            let (handlers_list_size, _) = dex_reader.read_uleb128()?;
105            handlers = Vec::with_capacity(handlers_list_size as usize);
106
107            for _ in 0..handlers_list_size {
108                let (handler_size, _) = dex_reader.read_sleb128()?;
109                let mut type_add_pairs = Vec::with_capacity(handler_size.unsigned_abs() as usize);
110
111                for _ in 0..handler_size.abs() {
112                    let (type_idx, _) = dex_reader.read_uleb128()?;
113                    let decoded_type = types_list.items.get(type_idx as usize)
114                                                       .ok_or(DexError::InvalidTypeIdx)?;
115                    let (addr, _) = dex_reader.read_uleb128()?;
116
117                    type_add_pairs.push(EncodedTypeAddrPair {
118                        decoded_type: decoded_type.to_owned(),
119                        addr
120                    });
121
122                }
123
124                if handler_size <= 0 {
125                    let (catch_all_addr, _) = dex_reader.read_uleb128()?;
126                    handlers.push(EncodedCatchHandler {
127                        size: handler_size,
128                        handlers: type_add_pairs,
129                        catch_all_addr: Some(catch_all_addr)
130                    });
131                } else {
132                    handlers.push(EncodedCatchHandler {
133                        size: handler_size,
134                        handlers: type_add_pairs,
135                        catch_all_addr: None
136                    });
137                }
138            }
139        }
140
141        if tries_size != 0 {
142            Ok(
143                CodeItem {
144                    registers_size,
145                    ins_size,
146                    outs_size,
147                    debug_info_off,
148                    // insns: parsed_ins,
149                    insns: Some(insns),
150                    tries: Some(tries),
151                    handlers: Some(handlers)
152                }
153            )
154        } else {
155            Ok(
156                CodeItem {
157                    registers_size,
158                    ins_size,
159                    outs_size,
160                    debug_info_off,
161                    // insns: parsed_ins,
162                    insns: Some(insns),
163                    tries: None,
164                    handlers: None
165                }
166            )
167        }
168    }
169}