mem_rs/process/
refresh.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::mem::size_of;
18use windows::Win32::Foundation::{CloseHandle, FALSE, HANDLE};
19use windows::Win32::System::ProcessStatus::{K32EnumProcesses, K32GetModuleFileNameExW};
20use windows::Win32::System::Threading::{GetExitCodeProcess, IsWow64Process, OpenProcess, PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_READ, PROCESS_VM_WRITE};
21use crate::helpers::{get_file_name_from_string, w32str_to_string};
22use crate::prelude::Process;
23use crate::process::STILL_ACTIVE;
24
25impl Process
26{
27    /// Attempts to "attach" to a running process by name.
28    /// Returns an error when the process is not running or when it has exited.
29    /// Caches the main module so that pattern scans can be done against it.
30    ///
31    /// # Examples
32    ///
33    /// ```
34    /// use mem_rs::prelude::*;
35    ///
36    /// let mut process = Process::new("name_of_process.exe");
37    /// process.refresh().expect("Failed to attach/refresh!");
38    /// ```
39    pub fn refresh(&mut self) -> Result<(), String>
40    {
41        unsafe
42        {
43            //Check if a previously attached process has exited
44            let mut lp_exit_code: u32 = 0;
45            if self.process_data.borrow().attached && (!GetExitCodeProcess(self.process_data.borrow().handle, &mut lp_exit_code).is_ok() || lp_exit_code != STILL_ACTIVE)
46            {
47                let mut process_data = self.process_data.borrow_mut();
48
49                process_data.attached = false;
50                process_data.id = 0;
51                process_data.handle = HANDLE::default();
52                process_data.filename = String::new();
53                process_data.path = String::new();
54
55                return Err(String::from("Process exited"));
56            }
57
58            if self.process_data.borrow().attached
59            {
60                return Ok(());
61            }
62
63            //Look for a running process with the correct name and attach to it
64            let mut process_ids = [0u32; 2048];
65            let mut out_size = 0;
66
67            if !K32EnumProcesses(process_ids.as_mut_ptr(), (process_ids.len() * size_of::<u32>()) as u32, &mut out_size).as_bool()
68            {
69                return Err(String::from("Failed to get running processes"));
70            }
71
72            let count = out_size as usize / std::mem::size_of::<u32>();
73            for i in 0..count
74            {
75                let pid = process_ids[i];
76
77                match OpenProcess(
78                    PROCESS_QUERY_INFORMATION
79                        | PROCESS_VM_READ
80                        | PROCESS_VM_WRITE
81                        | PROCESS_VM_OPERATION,
82                    false,
83                    pid,
84                )
85                {
86                    Ok(handle) =>
87                    {
88                        let mut mod_name = [0; windows::Win32::Foundation::MAX_PATH as usize];
89
90                        if K32GetModuleFileNameExW(Some(handle), None, &mut mod_name) != 0
91                        {
92                            let file_path = w32str_to_string(&mod_name.to_vec());
93                            let file_name = get_file_name_from_string(&file_path);
94
95                            //println!("{}", filename);
96
97                            if self.process_data.borrow().name.to_lowercase() == file_name.to_lowercase()
98                            {
99                                let mut wow64 = FALSE;
100                                if IsWow64Process(handle, &mut wow64).is_ok()
101                                {
102                                    let mut process_data = self.process_data.borrow_mut();
103                                    process_data.id = pid;
104                                    process_data.handle = handle;
105                                    process_data.is_64_bit = !wow64.as_bool();
106                                    process_data.filename = file_name;
107                                    process_data.path = file_path;
108                                    process_data.attached = true;
109                                    drop(process_data);
110
111                                    let mut main_module = Process::get_process_modules(handle, &self.process_data).remove(0);
112                                    main_module.dump_memory();
113                                    self.main_module = Some(main_module);
114
115                                    return Ok(());
116                                }
117                            }
118                        }
119
120                        let _ = CloseHandle(handle);
121                    }
122                    _ => {},
123                }
124            }
125            return Err(String::from("Process not running"));
126        }
127    }
128}