Skip to main content

memory_rs/external/
memory.rs

1use std::ffi::c_void;
2
3use windows_sys::Win32::{
4    Foundation::HANDLE,
5    System::{
6        Diagnostics::Debug::{ReadProcessMemory, WriteProcessMemory},
7        Memory::{
8            VirtualAllocEx, VirtualProtectEx, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READWRITE,
9        },
10    },
11};
12
13/// Kept for legacy purposes.
14
15pub fn get_aob(h_process: HANDLE, ptr: *const c_void, n: usize) -> Vec<u8> {
16    let mut read = 0;
17    let mut buffer: Vec<u8> = vec![0; n];
18
19    unsafe {
20        ReadProcessMemory(
21            h_process,
22            ptr as *const c_void,
23            buffer.as_mut_ptr() as *mut c_void,
24            n,
25            &mut read,
26        );
27    }
28
29    assert_eq!(n, read, "get_aob isn't the requested size");
30
31    buffer
32}
33
34pub fn write_aob(h_process: HANDLE, ptr: usize, source: &[u8]) -> usize {
35    let mut protection_bytes: u32 = 0x0;
36    let c_addr = ptr;
37    let size = source.len();
38    let mut written = 0;
39
40    unsafe {
41        VirtualProtectEx(
42            h_process,
43            c_addr as *const c_void,
44            size,
45            PAGE_EXECUTE_READWRITE,
46            &mut protection_bytes as _,
47        );
48
49        WriteProcessMemory(
50            h_process,
51            c_addr as *const c_void,
52            source[..].as_ptr() as *const c_void,
53            size,
54            &mut written,
55        );
56
57        VirtualProtectEx(
58            h_process,
59            c_addr as *const c_void,
60            size,
61            protection_bytes,
62            &mut protection_bytes as _,
63        );
64    }
65
66    assert_eq!(
67        written,
68        source.len(),
69        "write_aob didn't write the correct number of bytes"
70    );
71
72    written
73}
74
75pub fn write_nops(h_process: HANDLE, ptr: usize, n: usize) {
76    let nops: Vec<u8> = vec![0x90; n];
77    write_aob(h_process, ptr, &nops);
78}
79
80pub fn hook_function(h_process: HANDLE, to_hook: usize, f: usize, len: usize) {
81    assert!(len >= 5, "Not enough space to inject the shellcode");
82
83    let mut current_protection: u32 = 0x0;
84
85    unsafe {
86        VirtualProtectEx(
87            h_process,
88            to_hook as *const c_void,
89            len,
90            PAGE_EXECUTE_READWRITE,
91            &mut current_protection as _,
92        );
93    }
94
95    // just in case, we nop the space where we are injecting stuff
96    let nops = vec![0x90; len];
97    write_aob(h_process, to_hook, &nops);
98
99    let _diff = f as i64 - to_hook as i64;
100    let relative_address: u32 = (_diff as u32 - 5) as u32;
101    let relative_aob: [u8; 4] = relative_address.to_le_bytes();
102
103    let mut instructions: Vec<u8> = vec![0xE8];
104    instructions.extend_from_slice(&relative_aob[..]);
105
106    let written = write_aob(h_process, to_hook, &instructions);
107    assert_eq!(written, 5);
108
109    unsafe {
110        VirtualProtectEx(
111            h_process,
112            to_hook as *const c_void,
113            len,
114            current_protection,
115            &mut current_protection as _,
116        );
117    }
118}
119
120/// This function injects a
121/// shellcode on a desired address.
122/// # Safety
123/// This function is highly unsafe because it will
124/// change assembly code of the target program, so
125/// be aware of the crashing, wrong-results, etc.
126pub unsafe fn inject_shellcode(
127    h_process: HANDLE,
128    module_base_address: usize,
129    entry_point: *const c_void,
130    instruction_size: usize,
131    f_start: *const u8,
132    f_end: *const u8,
133) -> *const c_void {
134    let f_size = f_end as usize - f_start as usize;
135    // get the aob of the function
136    let shellcode_bytes: &'static [u8] = std::slice::from_raw_parts(f_start, f_size);
137
138    let mut shellcode_space: *const c_void = std::ptr::null();
139    // try to allocate near module
140    for i in 1..1000 {
141        let current_address = module_base_address - (0x1000 * i);
142        shellcode_space = VirtualAllocEx(
143            h_process,
144            current_address as _,
145            0x1000_usize,
146            MEM_RESERVE | MEM_COMMIT,
147            PAGE_EXECUTE_READWRITE,
148        );
149
150        if !shellcode_space.is_null() {
151            break;
152        }
153    }
154
155    let written = write_aob(h_process, shellcode_space as _, &shellcode_bytes.to_vec());
156    assert_eq!(written, f_size, "The size of the injection doesnt match");
157
158    let module_injection_address = module_base_address + (entry_point as usize);
159    hook_function(
160        h_process,
161        module_injection_address,
162        shellcode_space as _,
163        instruction_size,
164    );
165
166    shellcode_space
167}