memflow/os/process.rs
1//! Describes process context
2
3use super::{
4 ExportCallback, ExportInfo, ImportCallback, ImportInfo, ModuleAddressInfo, ModuleInfo,
5 ModuleInfoCallback, SectionCallback, SectionInfo,
6};
7use crate::cglue::*;
8use crate::prelude::v1::{Result, *};
9use std::prelude::v1::*;
10
11/// Type meant for process IDs
12///
13/// If there is a case where Pid can be over 32-bit limit, or negative, please open an issue, we
14/// would love to see that.
15pub type Pid = u32;
16
17/// Exit code of a process
18pub type ExitCode = i32;
19
20/// The state of a process
21///
22/// # Remarks
23///
24/// In case the exit code isn't known ProcessState::Unknown is set.
25#[repr(C)]
26#[derive(Debug, Clone, Eq, PartialEq)]
27#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
28#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))]
29pub enum ProcessState {
30 Unknown,
31 Alive,
32 Dead(ExitCode),
33}
34
35impl ProcessState {
36 pub fn is_alive(&self) -> bool {
37 matches!(*self, ProcessState::Alive)
38 }
39
40 pub fn is_dead(&self) -> bool {
41 matches!(*self, ProcessState::Dead(_))
42 }
43
44 pub fn is_unknown(&self) -> bool {
45 matches!(*self, ProcessState::Unknown)
46 }
47}
48
49/// Provides all actions on processes
50///
51/// This trait provides a lot of typical functionality for processes, such as memory access, module lists, and basic information.
52///
53/// Future expansions could include threads, keyboard input, and more.
54#[cfg_attr(feature = "plugins", cglue_trait)]
55#[int_result]
56pub trait Process: Send {
57 /// Retrieves the state of the process
58 fn state(&mut self) -> ProcessState;
59
60 /// Changes the dtb this process uses for memory translations
61 ///
62 /// # Remarks
63 ///
64 /// In case the architecture only uses a single dtb for translation the second parameter should be set to `Address::invalid()`.
65 fn set_dtb(&mut self, dtb1: Address, dtb2: Address) -> Result<()>;
66
67 /// Walks the process' module list and calls the provided callback for each module structure
68 /// address
69 ///
70 /// # Arguments
71 /// * `target_arch` - sets which architecture to retrieve the modules for (if emulated). Choose
72 /// between `Some(ProcessInfo::sys_arch())`, and `Some(ProcessInfo::proc_arch())`. `None` for all.
73 /// * `callback` - where to pass each matching module to. This is an opaque callback.
74 fn module_address_list_callback(
75 &mut self,
76 target_arch: Option<&ArchitectureIdent>,
77 callback: ModuleAddressCallback,
78 ) -> Result<()>;
79
80 /// Walks the process' module list and calls the provided callback for each module
81 ///
82 /// # Arguments
83 /// * `target_arch` - sets which architecture to retrieve the modules for (if emulated). Choose
84 /// between `Some(ProcessInfo::sys_arch())`, and `Some(ProcessInfo::proc_arch())`. `None` for all.
85 /// * `callback` - where to pass each matching module to. This is an opaque callback.
86 fn module_list_callback(
87 &mut self,
88 target_arch: Option<&ArchitectureIdent>,
89 mut callback: ModuleInfoCallback,
90 ) -> Result<()> {
91 // This is safe, because control will flow back to the callback.
92 let sptr = self as *mut Self;
93 let inner_callback = &mut |ModuleAddressInfo { address, arch }| match unsafe { &mut *sptr }
94 .module_by_address(address, arch)
95 {
96 Ok(info) => callback.call(info),
97 Err(e) => {
98 log::trace!("Error when reading module {:x} {:?}", address, e);
99 true // continue iteration
100 }
101 };
102 unsafe { sptr.as_mut().unwrap() }
103 .module_address_list_callback(target_arch, inner_callback.into())
104 }
105
106 /// Retrieves a module by its structure address and architecture
107 ///
108 /// # Arguments
109 /// * `address` - address where module's information resides in
110 /// * `architecture` - architecture of the module. Should be either `ProcessInfo::proc_arch`, or `ProcessInfo::sys_arch`.
111 fn module_by_address(
112 &mut self,
113 address: Address,
114 architecture: ArchitectureIdent,
115 ) -> Result<ModuleInfo>;
116
117 /// Finds a process module by its name under specified architecture
118 ///
119 /// This function can be useful for quickly accessing a specific module
120 ///
121 /// # Arguments
122 /// * `name` - name of the module to find
123 /// * `architecture` - architecture of the module. Should be either `ProcessInfo::proc_arch`, or `ProcessInfo::sys_arch`, or None for both.
124 fn module_by_name_arch(
125 &mut self,
126 name: &str,
127 architecture: Option<&ArchitectureIdent>,
128 ) -> Result<ModuleInfo> {
129 let mut ret = Err(Error(ErrorOrigin::OsLayer, ErrorKind::ModuleNotFound));
130 let callback = &mut |data: ModuleInfo| {
131 if data.name.as_ref() == name {
132 ret = Ok(data);
133 false
134 } else {
135 true
136 }
137 };
138 self.module_list_callback(architecture, callback.into())?;
139 ret
140 }
141
142 /// Finds a process module by its name under specified architecture using case-insensitive comparison
143 ///
144 /// This function can be useful for quickly accessing a specific module
145 ///
146 /// # Arguments
147 /// * `name` - name of the module to find (case-insensitive)
148 /// * `architecture` - architecture of the module. Should be either `ProcessInfo::proc_arch`, or `ProcessInfo::sys_arch`, or None for both.
149 #[skip_func]
150 fn module_by_name_arch_ignore_ascii_case(
151 &mut self,
152 name: &str,
153 architecture: Option<&ArchitectureIdent>,
154 ) -> Result<ModuleInfo> {
155 let mut ret = Err(Error(ErrorOrigin::OsLayer, ErrorKind::ModuleNotFound));
156 let callback = &mut |data: ModuleInfo| {
157 if data.name.as_ref().eq_ignore_ascii_case(name) {
158 ret = Ok(data);
159 false
160 } else {
161 true
162 }
163 };
164 self.module_list_callback(architecture, callback.into())?;
165 ret
166 }
167
168 /// Finds any architecture process module by its name
169 ///
170 /// This function can be useful for quickly accessing a specific module
171 ///
172 /// # Arguments
173 /// * `name` - name of the module to find
174 fn module_by_name(&mut self, name: &str) -> Result<ModuleInfo> {
175 self.module_by_name_arch(name, None)
176 }
177
178 /// Finds any architecture process module by its name using case-insensitive comparison
179 ///
180 /// This function can be useful for quickly accessing a specific module
181 ///
182 /// # Arguments
183 /// * `name` - name of the module to find (case-insensitive)
184 #[skip_func]
185 fn module_by_name_ignore_ascii_case(&mut self, name: &str) -> Result<ModuleInfo> {
186 self.module_by_name_arch_ignore_ascii_case(name, None)
187 }
188
189 /// Retrieves a module list for the process
190 ///
191 /// # Arguments
192 /// * `target_arch` - sets which architecture to retrieve the modules for (if emulated). Choose
193 /// between `Some(ProcessInfo::sys_arch())`, and `Some(ProcessInfo::proc_arch())`. `None` for all.
194 #[skip_func]
195 fn module_list_arch(
196 &mut self,
197 target_arch: Option<&ArchitectureIdent>,
198 ) -> Result<Vec<ModuleInfo>> {
199 let mut ret = vec![];
200 self.module_list_callback(target_arch, (&mut ret).into())?;
201 Ok(ret)
202 }
203
204 /// Retrieves a module list for the process
205 ///
206 /// This is equivalent to `Process::module_list_arch(None)`
207 #[skip_func]
208 fn module_list(&mut self) -> Result<Vec<ModuleInfo>> {
209 self.module_list_arch(None)
210 }
211
212 /// Retrieves address of the primary module structure of the process
213 ///
214 /// This will generally be for the initial executable that was run
215 fn primary_module_address(&mut self) -> Result<Address>;
216
217 /// Retrieves information for the primary module of the process
218 ///
219 /// This will generally be the initial executable that was run
220 fn primary_module(&mut self) -> Result<ModuleInfo> {
221 let addr = self.primary_module_address()?;
222 self.module_by_address(addr, self.info().proc_arch)
223 }
224
225 /// Retrieves a list of all imports of a given module
226 fn module_import_list_callback(
227 &mut self,
228 info: &ModuleInfo,
229 callback: ImportCallback,
230 ) -> Result<()>;
231
232 /// Retrieves a list of all exports of a given module
233 fn module_export_list_callback(
234 &mut self,
235 info: &ModuleInfo,
236 callback: ExportCallback,
237 ) -> Result<()>;
238
239 /// Retrieves a list of all sections of a given module
240 fn module_section_list_callback(
241 &mut self,
242 info: &ModuleInfo,
243 callback: SectionCallback,
244 ) -> Result<()>;
245
246 /// Retrieves a list of all imports of a given module
247 #[skip_func]
248 fn module_import_list(&mut self, info: &ModuleInfo) -> Result<Vec<ImportInfo>> {
249 let mut ret = vec![];
250 self.module_import_list_callback(info, (&mut ret).into())?;
251 Ok(ret)
252 }
253
254 /// Retrieves a list of all exports of a given module
255 #[skip_func]
256 fn module_export_list(&mut self, info: &ModuleInfo) -> Result<Vec<ExportInfo>> {
257 let mut ret = vec![];
258 self.module_export_list_callback(info, (&mut ret).into())?;
259 Ok(ret)
260 }
261
262 /// Retrieves a list of all sections of a given module
263 #[skip_func]
264 fn module_section_list(&mut self, info: &ModuleInfo) -> Result<Vec<SectionInfo>> {
265 let mut ret = vec![];
266 self.module_section_list_callback(info, (&mut ret).into())?;
267 Ok(ret)
268 }
269
270 /// Finds a single import of a given module by its name
271 fn module_import_by_name(&mut self, info: &ModuleInfo, name: &str) -> Result<ImportInfo> {
272 let mut ret = Err(Error(ErrorOrigin::OsLayer, ErrorKind::ImportNotFound));
273 let callback = &mut |data: ImportInfo| {
274 if data.name.as_ref() == name {
275 ret = Ok(data);
276 false
277 } else {
278 true
279 }
280 };
281 self.module_import_list_callback(info, callback.into())?;
282 ret
283 }
284
285 /// Finds a single export of a given module by its name
286 fn module_export_by_name(&mut self, info: &ModuleInfo, name: &str) -> Result<ExportInfo> {
287 let mut ret = Err(Error(ErrorOrigin::OsLayer, ErrorKind::ExportNotFound));
288 let callback = &mut |data: ExportInfo| {
289 if data.name.as_ref() == name {
290 ret = Ok(data);
291 false
292 } else {
293 true
294 }
295 };
296 self.module_export_list_callback(info, callback.into())?;
297 ret
298 }
299
300 /// Finds a single section of a given module by its name
301 fn module_section_by_name(&mut self, info: &ModuleInfo, name: &str) -> Result<SectionInfo> {
302 let mut ret = Err(Error(ErrorOrigin::OsLayer, ErrorKind::SectionNotFound));
303 let callback = &mut |data: SectionInfo| {
304 if data.name.as_ref() == name {
305 ret = Ok(data);
306 false
307 } else {
308 true
309 }
310 };
311 self.module_section_list_callback(info, callback.into())?;
312 ret
313 }
314
315 /// Retrieves the process info
316 fn info(&self) -> &ProcessInfo;
317
318 fn mapped_mem_range(
319 &mut self,
320 gap_size: imem,
321 start: Address,
322 end: Address,
323 out: MemoryRangeCallback,
324 );
325
326 #[skip_func]
327 fn mapped_mem_range_vec(
328 &mut self,
329 gap_size: imem,
330 start: Address,
331 end: Address,
332 ) -> Vec<MemoryRange> {
333 let mut out = vec![];
334 self.mapped_mem_range(gap_size, start, end, (&mut out).into());
335 out
336 }
337
338 fn mapped_mem(&mut self, gap_size: imem, out: MemoryRangeCallback) {
339 self.mapped_mem_range(gap_size, Address::null(), Address::invalid(), out)
340 }
341
342 #[skip_func]
343 fn mapped_mem_vec(&mut self, gap_size: imem) -> Vec<MemoryRange> {
344 let mut out = vec![];
345 self.mapped_mem(gap_size, (&mut out).into());
346 out
347 }
348}
349
350/// Process information structure
351///
352/// This structure implements basic process information. Architectures are provided both of the
353/// system, and of the process.
354#[repr(C)]
355#[derive(Clone, Debug)]
356#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
357#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))]
358pub struct ProcessInfo {
359 /// The base address of this process.
360 ///
361 /// # Remarks
362 ///
363 /// On Windows this will be the address of the [`_EPROCESS`](https://www.nirsoft.net/kernel_struct/vista/EPROCESS.html) structure.
364 pub address: Address,
365 /// ID of this process.
366 pub pid: Pid,
367 /// The current status of the process at the time when this process info was fetched.
368 ///
369 /// # Remarks
370 ///
371 /// This field is highly volatile and can be re-checked with the [`Process::state()`] function.
372 pub state: ProcessState,
373 /// Name of the process.
374 pub name: ReprCString,
375 /// Path of the process binary
376 pub path: ReprCString,
377 /// Command line the process was started with.
378 pub command_line: ReprCString,
379 /// System architecture of the target system.
380 pub sys_arch: ArchitectureIdent,
381 /// Process architecture
382 ///
383 /// # Remarks
384 ///
385 /// Specifically on 64-bit systems this could be different
386 /// to the `sys_arch` in case the process is an emulated 32-bit process.
387 ///
388 /// On windows this technique is called [`WOW64`](https://docs.microsoft.com/en-us/windows/win32/winprog64/wow64-implementation-details).
389 pub proc_arch: ArchitectureIdent,
390 /// Directory Table Base
391 ///
392 /// # Remarks
393 ///
394 /// These fields contain the translation base used to translate virtual memory addresses into physical memory addresses.
395 /// On x86 systems only `dtb1` is set because only one dtb is used.
396 /// On arm systems both `dtb1` and `dtb2` are set to their corresponding values.
397 pub dtb1: Address,
398 pub dtb2: Address,
399}
400
401pub type ProcessInfoCallback<'a> = OpaqueCallback<'a, ProcessInfo>;