1use std::ffi::CStr;
4use std::slice::from_raw_parts;
5
6use crate::shuriken;
7use crate::parser::DvmMethod;
8
9#[derive(Debug, Clone, Copy, PartialEq)]
13pub enum DexInstType {
14 DexInstruction00x,
15 DexInstruction10x,
16 DexInstruction12x,
17 DexInstruction11n,
18 DexInstruction11x,
19 DexInstruction10t,
20 DexInstruction20t,
21 DexInstruction20bc,
22 DexInstruction22x,
23 DexInstruction21t,
24 DexInstruction21s,
25 DexInstruction21h,
26 DexInstruction21c,
27 DexInstruction23x,
28 DexInstruction22b,
29 DexInstruction22t,
30 DexInstruction22s,
31 DexInstruction22c,
32 DexInstruction22cs,
33 DexInstruction30t,
34 DexInstruction32x,
35 DexInstruction31i,
36 DexInstruction31t,
37 DexInstruction31c,
38 DexInstruction35c,
39 DexInstruction3rc,
40 DexInstruction45cc,
41 DexInstruction4rcc,
42 DexInstruction51l,
43 DexPackedSwitch,
44 DexSparseSwitch,
45 DexFillArrayData,
46 DexDalvikIncorrect,
47 DexNoneOp = 99,
48}
49
50#[derive(Debug, PartialEq)]
54pub struct DvmInstruction {
55 instruction_type: DexInstType,
56 instruction_length: usize,
57 address: u64,
58 op: u32,
60 disassembly: String
61}
62
63impl DvmInstruction {
64 pub fn from_ins(ins: shuriken::hdvminstruction_t) -> Self {
65 let instruction_type = match ins.instruction_type {
66 0 => DexInstType::DexInstruction00x,
67 1 => DexInstType::DexInstruction10x,
68 2 => DexInstType::DexInstruction12x,
69 3 => DexInstType::DexInstruction11n,
70 4 => DexInstType::DexInstruction11x,
71 5 => DexInstType::DexInstruction10t,
72 6 => DexInstType::DexInstruction20t,
73 7 => DexInstType::DexInstruction20bc,
74 8 => DexInstType::DexInstruction22x,
75 9 => DexInstType::DexInstruction21t,
76 10 => DexInstType::DexInstruction21s,
77 11 => DexInstType::DexInstruction21h,
78 12 => DexInstType::DexInstruction21c,
79 13 => DexInstType::DexInstruction23x,
80 14 => DexInstType::DexInstruction22b,
81 15 => DexInstType::DexInstruction22t,
82 16 => DexInstType::DexInstruction22s,
83 17 => DexInstType::DexInstruction22c,
84 18 => DexInstType::DexInstruction22cs,
85 19 => DexInstType::DexInstruction30t,
86 20 => DexInstType::DexInstruction32x,
87 21 => DexInstType::DexInstruction31i,
88 22 => DexInstType::DexInstruction31t,
89 23 => DexInstType::DexInstruction31c,
90 24 => DexInstType::DexInstruction35c,
91 25 => DexInstType::DexInstruction3rc,
92 26 => DexInstType::DexInstruction45cc,
93 27 => DexInstType::DexInstruction4rcc,
94 28 => DexInstType::DexInstruction51l,
95 29 => DexInstType::DexPackedSwitch,
96 30 => DexInstType::DexSparseSwitch,
97 31 => DexInstType::DexFillArrayData,
98 99 => DexInstType::DexNoneOp,
99 _ => DexInstType::DexDalvikIncorrect,
100 };
101
102 let disassembly = unsafe {
103 CStr::from_ptr(ins.disassembly)
104 .to_str()
105 .expect("Error: string is not valid UTF-8")
106 .to_string()
107 };
108
109 DvmInstruction {
110 instruction_type,
111 instruction_length: ins.instruction_length as usize,
112 address: ins.address,
113 op: ins.op,
114 disassembly
115 }
116 }
117
118 pub fn instruction_type(&self) -> DexInstType {
120 self.instruction_type
121 }
122
123 pub fn instruction_length(&self) -> usize {
125 self.instruction_length
126 }
127
128 pub fn address(&self) -> u64 {
130 self.address
131 }
132
133 pub fn op(&self) -> u32 {
135 self.op
136 }
137
138 pub fn disassembly(&self) -> &str {
140 &self.disassembly
141 }
142}
143
144#[derive(Debug, PartialEq)]
148pub struct DvmHandlerData {
149 handler_type: String,
150 handler_start_addr: u64
151}
152
153impl DvmHandlerData {
154 fn from_ptr(ptr: shuriken::dvmhandler_data_t) -> Self {
155 let handler_type = unsafe {
156 CStr::from_ptr(ptr.handler_type)
157 .to_str()
158 .expect("Error: string is not valid UTF-8")
159 .to_string()
160 };
161
162 Self {
163 handler_type,
164 handler_start_addr: ptr.handler_start_addr
165 }
166 }
167
168 pub fn handler_type(&self) -> &str {
170 &self.handler_type
171 }
172
173 pub fn handler_start_addr(&self) -> u64 {
175 self.handler_start_addr
176 }
177}
178
179#[derive(Debug, PartialEq)]
183pub struct DvmException {
184 try_value_start_addr: u64,
185 try_value_end_addr: u64,
186 n_of_handlers: usize,
187 handlers: Vec<DvmHandlerData>
188}
189
190impl DvmException {
191 fn from_ptr(ptr: shuriken::dvmexceptions_data_t) -> Self {
192 let handlers = unsafe {
193 from_raw_parts(ptr.handler, ptr.n_of_handlers)
194 .iter()
195 .map(|handler| DvmHandlerData::from_ptr(*handler))
196 .collect::<Vec<DvmHandlerData>>()
197 };
198
199 Self {
200 try_value_start_addr: ptr.try_value_start_addr,
201 try_value_end_addr: ptr.try_value_end_addr,
202 n_of_handlers: ptr.n_of_handlers,
203 handlers
204 }
205 }
206
207 pub fn try_value_start_addr(&self) -> u64 {
209 self.try_value_start_addr
210 }
211
212 pub fn try_value_end_addr(&self) -> u64 {
214 self.try_value_end_addr
215 }
216
217 pub fn n_of_handlers(&self) -> usize {
219 self.n_of_handlers
220 }
221
222 pub fn handlers(&self) -> &[DvmHandlerData] {
224 &self.handlers
225 }
226}
227
228#[derive(Debug, PartialEq)]
232pub struct DvmDisassembledMethod {
233 method_id: DvmMethod,
235 n_of_registers: usize,
236 n_of_exceptions: usize,
237 exception_information: Vec<DvmException>,
238 n_of_instructions: usize,
239 instructions: Vec<DvmInstruction>,
240 method_string: String,
241}
242
243impl DvmDisassembledMethod {
244 pub fn from_dvmdisassembled_method_t(
245 dvm_disas: shuriken::dvmdisassembled_method_t,
246 dvm_method: DvmMethod
247 ) -> Self
248 {
249
250 let method_string = unsafe {
251 CStr::from_ptr(dvm_disas.method_string)
252 .to_str()
253 .expect("Error: string is not valid UTF-8")
254 .to_string()
255 };
256
257 let exception_information = unsafe {
258 from_raw_parts(dvm_disas.exception_information, dvm_disas.n_of_exceptions)
259 .iter()
260 .map(|exc| DvmException::from_ptr(*exc))
261 .collect::<Vec<DvmException>>()
262 };
263
264 let instructions = unsafe {
265 from_raw_parts(dvm_disas.instructions, dvm_disas.n_of_instructions)
266 .iter()
267 .map(|ins| DvmInstruction::from_ins(*ins))
268 .collect::<Vec<DvmInstruction>>()
269 };
270
271 Self {
272 method_id: dvm_method,
273 n_of_registers: dvm_disas.n_of_registers.into(),
274 n_of_exceptions: dvm_disas.n_of_exceptions,
275 exception_information,
276 n_of_instructions: dvm_disas.n_of_instructions,
277 instructions,
278 method_string
279 }
280 }
281
282 pub fn from_ptr(ptr: shuriken::dvmdisassembled_method_t) -> Self {
288 if ptr.method_id.is_null() {
290 panic!("DvmMethod pointer is null");
291 }
292
293 let dvm_method = unsafe { DvmMethod::from_ptr(*ptr.method_id) };
294
295 DvmDisassembledMethod::from_dvmdisassembled_method_t(ptr, dvm_method)
296 }
297
298 pub fn method_id(&self) -> &DvmMethod {
300 &self.method_id
301 }
302
303 pub fn n_of_registers(&self) -> usize {
305 self.n_of_registers
306 }
307
308 pub fn n_of_exceptions(&self) -> usize {
310 self.n_of_exceptions
311 }
312
313 pub fn exception_information(&self) -> &[DvmException] {
315 &self.exception_information
316 }
317
318 pub fn n_of_instructions(&self) -> usize {
320 self.n_of_instructions
321 }
322
323 pub fn method_string(&self) -> &str {
325 &self.method_string
326 }
327
328 pub fn instructions(&self) -> &[DvmInstruction] {
330 &self.instructions
331 }
332}