process_memory/
windows.rs

1use winapi::shared::minwindef;
2
3use std::os::windows::io::AsRawHandle;
4use std::process::Child;
5use std::ptr;
6
7use super::{Architecture, CopyAddress, ProcessHandleExt, PutAddress, TryIntoProcessHandle};
8
9/// On Windows a `Pid` is a `DWORD`.
10pub type Pid = minwindef::DWORD;
11/// On Windows a `ProcessHandle` is a `HANDLE`.
12pub type ProcessHandle = (winapi::um::winnt::HANDLE, Architecture);
13
14impl ProcessHandleExt for ProcessHandle {
15    #[must_use]
16    fn check_handle(&self) -> bool {
17        self.0.is_null()
18    }
19    #[must_use]
20    fn null_type() -> ProcessHandle {
21        (ptr::null_mut(), Architecture::from_native())
22    }
23    #[must_use]
24    fn set_arch(self, arch: Architecture) -> Self {
25        (self.0, arch)
26    }
27}
28
29/// A `Pid` can be turned into a `ProcessHandle` with `OpenProcess`.
30impl TryIntoProcessHandle for minwindef::DWORD {
31    fn try_into_process_handle(&self) -> std::io::Result<ProcessHandle> {
32        let handle = unsafe {
33            winapi::um::processthreadsapi::OpenProcess(
34                winapi::um::winnt::PROCESS_CREATE_THREAD
35                    | winapi::um::winnt::PROCESS_QUERY_INFORMATION
36                    | winapi::um::winnt::PROCESS_VM_READ
37                    | winapi::um::winnt::PROCESS_VM_WRITE
38                    | winapi::um::winnt::PROCESS_VM_OPERATION,
39                winapi::shared::minwindef::FALSE,
40                *self,
41            )
42        };
43        if handle == (0 as winapi::um::winnt::HANDLE) {
44            Err(std::io::Error::last_os_error())
45        } else {
46            Ok((handle, Architecture::from_native()))
47        }
48    }
49}
50
51/// A `std::process::Child` has a `HANDLE` from calling `CreateProcess`.
52impl TryIntoProcessHandle for Child {
53    fn try_into_process_handle(&self) -> std::io::Result<ProcessHandle> {
54        Ok((self.as_raw_handle().cast(), Architecture::from_native()))
55    }
56}
57
58/// Use `ReadProcessMemory` to read memory from another process on Windows.
59impl CopyAddress for ProcessHandle {
60    #[allow(clippy::inline_always)]
61    #[inline(always)]
62    fn get_pointer_width(&self) -> Architecture {
63        self.1
64    }
65
66    #[allow(clippy::ptr_as_ptr)]
67    fn copy_address(&self, addr: usize, buf: &mut [u8]) -> std::io::Result<()> {
68        if buf.is_empty() {
69            return Ok(());
70        }
71
72        if unsafe {
73            winapi::um::memoryapi::ReadProcessMemory(
74                self.0,
75                addr as minwindef::LPVOID,
76                buf.as_mut_ptr() as minwindef::LPVOID,
77                buf.len() as winapi::shared::basetsd::SIZE_T,
78                ptr::null_mut(),
79            )
80        } == winapi::shared::minwindef::FALSE
81        {
82            Err(std::io::Error::last_os_error())
83        } else {
84            Ok(())
85        }
86    }
87}
88
89/// Use `WriteProcessMemory` to write memory from another process on Windows.
90impl PutAddress for ProcessHandle {
91    #[allow(clippy::ptr_as_ptr)]
92    fn put_address(&self, addr: usize, buf: &[u8]) -> std::io::Result<()> {
93        if buf.is_empty() {
94            return Ok(());
95        }
96        if unsafe {
97            winapi::um::memoryapi::WriteProcessMemory(
98                self.0,
99                addr as minwindef::LPVOID,
100                buf.as_ptr() as minwindef::LPCVOID,
101                buf.len() as winapi::shared::basetsd::SIZE_T,
102                ptr::null_mut(),
103            )
104        } == winapi::shared::minwindef::FALSE
105        {
106            Err(std::io::Error::last_os_error())
107        } else {
108            Ok(())
109        }
110    }
111}