1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#![cfg(target_arch = "arm")]
use std::ptr::null_mut;
use std::ptr::NonNull;
use crate::injector_core::common::*;
use crate::injector_core::patch_trait::*;
pub(crate) struct PatchArm;
impl PatchTrait for PatchArm {
fn replace_function_with_other_function(
src: FuncPtrInternal,
target: FuncPtrInternal,
) -> PatchGuard {
// Thumb mode (T32) functions are aligned on odd addresses,
// while ARM mode (A32) functions are aligned on even addresses.
let is_src_thumb = src.as_ptr() as usize & 1 != 0;
// Even if the function jump is on an odd address, the previous byte
// is executed in Thumb mode, so we need to align the memory on 2 bytes.
let src_ptr = if is_src_thumb {
(src.as_ptr() as u32 - 1) as *const ()
} else {
src.as_ptr()
};
let patch_size = 12;
let original_bytes = unsafe { read_bytes(src_ptr as *mut u8, patch_size) };
let instructions: [u32; 3] = if is_src_thumb {
[
// ldr r7, [pc, #0] ; 0x4F00. It will load pc + 0 into r6, so the target word
// bx r7 ; 4738
// Reversed because of little endian
0x47384F00,
// .word target
target.as_ptr() as u32,
// .word anything (unused)
0x00000000,
]
} else {
[
// ldr r9, [pc, #-0] ; Load pc + 8 into r9, so the target word
0xE51F9000,
// bx r9 ; Branch to the target function
0xE12FFF19,
// .word target
target.as_ptr() as u32,
]
};
let mut patch = [0u8; 12];
patch[0..4].copy_from_slice(&instructions[0].to_le_bytes());
patch[4..8].copy_from_slice(&instructions[1].to_le_bytes());
patch[8..12].copy_from_slice(&instructions[2].to_le_bytes());
// In thumb mode, if the source is not aligned on 32 bit, add a NOP to align it, so the target adress is also aligned on 32 bit
// If we don't do that, the load adress will be misaligned and will load the bx instruction instead of the target function.
if is_src_thumb && (src_ptr as usize % 4 != 0) {
patch.rotate_right(2);
patch[0] = 0xC0;
patch[1] = 0x46; // NOP instruction in Thumb mode
}
unsafe {
patch_function(src_ptr as *mut u8, &patch);
}
PatchGuard::new(
src_ptr as *mut u8,
original_bytes,
patch_size,
null_mut(), // No JIT memory needed for ARM
0,
)
}
fn replace_function_return_boolean(src: FuncPtrInternal, value: bool) -> PatchGuard {
Self::replace_function_with_other_function(src, unsafe {
FuncPtrInternal::new(
NonNull::new(if value { return_true } else { return_false } as *mut ())
.expect("Failed to create FuncPtrInternal"), // Should never fail
)
})
}
}
fn return_true() -> bool {
true
}
fn return_false() -> bool {
false
}