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>;