process_memory_reader/
linux.rs

1use crate::{MemoryReadError, Process};
2use libc::{iovec, process_vm_readv};
3use std::fs::{read_dir, File};
4use std::io::{Error as IoError, BufReader, BufRead};
5
6/// Opens process with specified id.
7///
8/// If the process is not found or could not be opened `None` will be returned.
9pub fn open_process(pid: u32) -> Option<LinuxProcess> {
10    Some(LinuxProcess { pid })
11}
12
13/// Finds all processes with matching name.
14pub fn find_by_name(name: &str) -> Result<Vec<LinuxProcess>, IoError> {
15    let paths = read_dir("/proc")?;
16    let mut processes = vec![];
17
18    for path_entry in paths {
19        if let Ok(path) = path_entry {
20            let maps_path = path.path().join("maps");
21
22            if let Ok(file) = File::open(maps_path) {
23                let mut reader = BufReader::new(file);
24                let mut buffer = String::new();
25                reader.read_line(&mut buffer)?;
26
27                if buffer.trim().ends_with(name) {
28                    if let Some(pid_name) = path.file_name().to_str() {
29                        let pid = pid_name.parse::<u32>().unwrap();
30
31                        open_process(pid).map(|process| processes.push(process));
32                    }
33                }
34            }
35        }
36    }
37
38    Ok(processes)
39}
40
41#[derive(Debug)]
42pub struct LinuxProcess {
43    pub pid: u32,
44}
45
46impl Process for LinuxProcess {
47    fn base_address(&self, module_name: &str) -> Option<usize> {
48        let file_name = format!("/proc/{}/maps", self.pid);
49        let file = File::open(file_name).ok()?;
50        let reader = BufReader::new(file);
51
52        for result in reader.lines() {
53            if let Ok(line) = result {
54                if line.trim().ends_with(module_name) {
55                    let split_line: Vec<&str> = line.split("-").collect();
56                    let address_str = split_line[0];
57
58                    return usize::from_str_radix(address_str, 16).ok();
59                }
60            }
61        }
62
63        None
64    }
65
66    fn read_bytes(&self, address: usize, buffer: &mut [u8]) -> Result<(), MemoryReadError> {
67        let local_iov = iovec {
68            iov_base: buffer.as_mut_ptr() as *mut _,
69            iov_len: buffer.len(),
70        };
71
72        let remote_iov = iovec {
73            iov_base: address as *mut _,
74            iov_len: buffer.len(),
75        };
76
77        let result = unsafe { process_vm_readv(self.pid as i32, &local_iov, 1, &remote_iov, 1, 0) };
78
79        if result == -1 {
80            return Err(MemoryReadError::IOError {
81                io_error: IoError::last_os_error(),
82            });
83        }
84
85        Ok(())
86    }
87}