mem_rs/process/
inject_dll.rs

1// This file is part of the mem-rs distribution (https://github.com/FrankvdStam/mem-rs).
2// Copyright (c) 2022 Frank van der Stam.
3// https://github.com/FrankvdStam/mem-rs/blob/main/LICENSE
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, version 3.
8//
9// This program is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17use std::ffi::c_void;
18use std::mem::size_of;
19use windows::Win32::System::LibraryLoader::{GetModuleHandleW, GetProcAddress};
20use windows::Win32::System::Memory::{MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE, VirtualAllocEx, VirtualFreeEx};
21use windows::Win32::System::Threading::{CreateRemoteThread, OpenProcess, PROCESS_CREATE_THREAD, PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_READ, PROCESS_VM_WRITE, WaitForSingleObject};
22use crate::helpers::{get_pcstr_from_str, get_pcwstr_from_str, vec_u16_to_u8};
23use crate::prelude::*;
24
25
26impl Process
27{
28    /// Attempts to inject a dll into the attached process using LoadLibraryW
29    ///
30    /// # Examples
31    ///
32    /// ```
33    /// use mem_rs::prelude::*;
34    ///
35    /// let mut process = Process::new("name_of_process.exe");
36    /// process.refresh().expect("Failed to attach/refresh!");
37    /// process.inject_dll(r#"C:\temp\native.dll"#).expect("Failed to inject!");
38    /// ```
39    pub fn inject_dll(&self, dll_path: &str) -> Result<(), String>
40    {
41        let mut path_w32_str: Vec<u16> = dll_path.encode_utf16().collect();
42        path_w32_str.push(0);
43
44        unsafe
45        {
46            if self.is_attached()
47            {
48                let process_handle_result = OpenProcess(
49                    PROCESS_CREATE_THREAD |
50                        PROCESS_QUERY_INFORMATION |
51                        PROCESS_VM_OPERATION |
52                        PROCESS_VM_WRITE |
53                        PROCESS_VM_READ, false, self.process_data.borrow().id);
54
55                if process_handle_result.is_err()
56                {
57                    return Err(String::from("process handle invalid"));
58                }
59
60                let process_handle = process_handle_result.unwrap();
61
62                //Allocate a chunk of memory inside a process and write the path to the dll in this chunk
63                let allocated_dll_path_str = VirtualAllocEx(
64                    process_handle,
65                    None,
66                    path_w32_str.len() * size_of::<u16>(),
67                    MEM_COMMIT | MEM_RESERVE,
68                    PAGE_READWRITE);
69
70                self.write_memory_abs(allocated_dll_path_str as usize, &vec_u16_to_u8(&path_w32_str));
71
72                //Get a ptr to LoadLibraryW via kernel32.dll
73                let kernel32_pcwstr = get_pcwstr_from_str(&"kernel32.dll\0");
74
75                let kernel_32_handle = GetModuleHandleW(kernel32_pcwstr);
76                if kernel_32_handle.is_err()
77                {
78                    return  Err(String::from("failed to load module kernel32.dll"));
79                }
80
81                let load_library_w_pcstr = get_pcstr_from_str(&"LoadLibraryW\0");
82                let load_library_w = GetProcAddress(kernel_32_handle.unwrap(), load_library_w_pcstr);
83                if load_library_w.is_none()
84                {
85                    return  Err(String::from("Failed to find LoadLibraryW"));
86                }
87
88                let thread = CreateRemoteThread(
89                    process_handle,
90                    None,
91                    0,
92                    Some(*(&load_library_w.unwrap() as *const _ as *const extern "system" fn(*mut c_void) -> u32)),
93                    Some(allocated_dll_path_str),
94                    0,
95                    None);
96
97                if thread.is_err()
98                {
99                    return  Err(String::from("Failed to start remote thread"));
100                }
101
102                let _ = WaitForSingleObject(thread.unwrap(), 10000);
103                let _ = VirtualFreeEx(process_handle, allocated_dll_path_str, 0, MEM_RELEASE);
104            }
105            return Ok(());
106        }
107    }
108}