ddcore_rs/memory/
proc_mem_wrapper.rs

1//
2//  We have fun around these parts
3//
4
5use anyhow::Result;
6
7#[cfg(target_os = "windows")]
8use std::os::windows::prelude::OwnedHandle;
9#[cfg(target_os = "windows")]
10use process_memory::Architecture;
11
12#[cfg(target_os = "linux")]
13use process_memory::{CopyAddress, ProcessHandle, ProcessHandleExt, TryIntoProcessHandle};
14
15#[cfg(target_os = "windows")]
16pub struct Handle {
17    pub win_handle: OwnedHandle,
18    pub pid: usize,
19}
20
21#[cfg(target_os = "linux")]
22pub struct Handle {
23    pub inner: ProcessHandle,
24    pub pid: usize,
25}
26
27impl Handle {
28    #[cfg(target_os = "windows")]
29    pub fn new(pid: usize) -> Result<Self> {
30        use std::os::windows::prelude::FromRawHandle;
31
32        use winapi::shared::minwindef::DWORD;
33        let handle = unsafe {
34            winapi::um::processthreadsapi::OpenProcess(
35                winapi::um::winnt::PROCESS_ALL_ACCESS,
36                winapi::shared::minwindef::FALSE,
37                pid as DWORD,
38            )
39        };
40        if handle == (0 as winapi::um::winnt::HANDLE) {
41            Err(anyhow::anyhow!(std::io::Error::last_os_error()))
42        } else {
43            let handle = unsafe { OwnedHandle::from_raw_handle(handle) };
44            Ok(Handle { win_handle: handle, pid })
45        }
46    }
47
48    #[cfg(target_os = "windows")]
49    pub fn get_offset(&self, offsets: &[usize]) -> Result<usize> {
50        let mut offset: usize = 0;
51        let noffsets: usize = offsets.len();
52        let arch = Architecture::from_native();
53        let mut copy = vec![0_u8; arch as usize];
54        for next_offset in offsets.iter().take(noffsets - 1) {
55            offset += next_offset;
56            self.copy_address(offset, &mut copy)?;
57            offset = arch.pointer_from_ne_bytes(&copy);
58        }
59
60        offset += offsets[noffsets - 1];
61        Ok(offset)
62    }
63
64    #[cfg(target_os = "windows")]
65    pub fn check_handle(&self) -> bool {
66        use std::os::windows::prelude::AsRawHandle;
67        self.win_handle.as_raw_handle().is_null()
68    }
69
70    #[cfg(target_os = "windows")]
71    pub fn copy_address(&self, addr: usize, buf: &mut [u8]) -> Result<()> {
72        use std::os::windows::prelude::AsRawHandle;
73        use winapi::shared::minwindef;
74        if buf.is_empty() {
75            return Ok(());
76        }
77
78        if unsafe {
79            winapi::um::memoryapi::ReadProcessMemory(
80                self.win_handle.as_raw_handle(),
81                addr as minwindef::LPVOID,
82                buf.as_mut_ptr() as minwindef::LPVOID,
83                buf.len() as winapi::shared::basetsd::SIZE_T,
84                std::ptr::null_mut(),
85            )
86        } == winapi::shared::minwindef::FALSE
87        {
88            Err(anyhow::anyhow!(std::io::Error::last_os_error()))
89        } else {
90            Ok(())
91        }
92    }
93
94    #[cfg(target_os = "windows")]
95    pub fn put_address(&self, addr: usize, buf: &[u8]) -> Result<()> {
96        use std::os::windows::prelude::AsRawHandle;
97        use winapi::shared::minwindef;
98
99        if buf.is_empty() {
100            return Ok(());
101        }
102        if unsafe {
103            winapi::um::memoryapi::WriteProcessMemory(
104                self.win_handle.as_raw_handle(),
105                addr as minwindef::LPVOID,
106                buf.as_ptr() as minwindef::LPCVOID,
107                buf.len() as winapi::shared::basetsd::SIZE_T,
108                std::ptr::null_mut(),
109            )
110        } == winapi::shared::minwindef::FALSE
111        {
112            Err(anyhow::anyhow!(std::io::Error::last_os_error()))
113        } else {
114            Ok(())
115        }
116    }
117
118    #[cfg(target_os = "windows")]
119    pub fn null_type() -> Self {
120        use std::os::windows::prelude::FromRawHandle;
121        Self {
122            win_handle: unsafe { OwnedHandle::from_raw_handle(std::ptr::null_mut()) },
123            pid: 0,
124        }
125    }
126
127    #[cfg(target_os = "linux")]
128    pub fn new(pid: usize) -> Result<Self> {
129        Ok(Self {
130            inner: (pid as i32).try_into_process_handle()?,
131            pid
132        })
133    }
134
135    #[cfg(target_os = "linux")]
136    pub fn null_type() -> Self {
137        Self {
138            inner: ProcessHandle::null_type(),
139            pid: 0
140        }
141    }
142
143    #[cfg(target_os = "linux")]
144    pub fn copy_address(&self, addr: usize, buf: &mut [u8]) -> Result<()> {
145        Ok(self.inner.copy_address(addr, buf)?)
146    }
147
148    #[cfg(target_os = "linux")]
149    pub fn put_address(&self, addr: usize, buf: &[u8]) -> Result<()> {
150        use process_memory::PutAddress;
151        self.inner.put_address(addr, buf)?;
152        Ok(())
153    }
154
155    #[cfg(target_os = "linux")]
156    pub fn get_offset(&self, offsets: &[usize]) -> Result<usize> {
157        Ok(self.inner.get_offset(offsets)?)
158    }
159
160    #[cfg(target_os = "linux")]
161    pub fn check_handle(&self) -> bool {
162        self.inner.check_handle()
163    }
164}