1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use crate::error::{Error, Result};
use crate::memory::{error::MemoryError, error::MemoryResult, MemoryManipulation};
use crate::process::Process;
use sysinfo::{ProcessExt, System, SystemExt};

#[cfg(target_os = "linux")]
use {
    nix::{
        sys::uio::{self, IoVec, RemoteIoVec},
        unistd::Pid,
    },
    std::{
        fs::OpenOptions,
        io::{prelude::*, SeekFrom},
    },
};

/// Manipulates the process memory from the outside with system calls
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct ExternalManipulator {
    pid: i32,
}

impl ExternalManipulator {
    /// Creates a new External Manipulator from an unchecked pid
    pub fn new_unchecked(pid: i32) -> ExternalManipulator {
        ExternalManipulator { pid }
    }
    /// Searches for the given process name and creates an external manipulator
    pub fn new(name: &str) -> Result<ExternalManipulator> {
        let system = System::new_all();
        let process_list = system.get_process_by_name(name);
        if !process_list.is_empty() {
            let pid = process_list[0].pid();
            return Ok(ExternalManipulator { pid });
        }
        Err(Error::ProcessNotFound(name.to_owned()))
    }
}

#[cfg(target_os = "linux")]
impl MemoryManipulation for ExternalManipulator {
    fn read(&self, address: usize, buf: &mut [u8]) -> MemoryResult<usize> {
        let remote = [RemoteIoVec {
            base: address,
            len: std::mem::size_of_val(buf),
        }];
        let local = [IoVec::from_mut_slice(buf)];
        match uio::process_vm_readv(Pid::from_raw(self.pid), &local, &remote) {
            Ok(x) if x > 0 => Ok(x),
            Err(e) => Err(MemoryError::ReadError(e.to_string())),
            _ => Err(MemoryError::ReadError("No bytes read".to_owned())),
        }
    }
    fn write(&self, address: usize, payload: &[u8]) -> MemoryResult<usize> {
        let remote = [RemoteIoVec {
            base: address,
            len: std::mem::size_of_val(payload),
        }];
        let local = [IoVec::from_slice(payload)];
        match uio::process_vm_writev(Pid::from_raw(self.pid), &local, &remote) {
            Ok(x) if x > 0 => Ok(x),
            Err(e) => Err(MemoryError::WriteError(e.to_string())),
            _ => Err(MemoryError::WriteError("No bytes written".to_owned())),
        }
    }
}

impl Process for ExternalManipulator {
    fn pid(&self) -> i32 {
        self.pid
    }
}
/// Manipulates the process memory from the outside with the memory mapped mem file
#[cfg(target_os = "linux")]
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct AnonManipulator {
    pid: i32,
}

impl AnonManipulator {
    /// Searches for the given process name and creates an anon manipulator
    pub fn new(name: &str) -> Result<AnonManipulator> {
        let system = System::new_all();
        let process_list = system.get_process_by_name(name);
        if !process_list.is_empty() {
            let pid = process_list[0].pid();
            return Ok(AnonManipulator { pid });
        }
        Err(Error::ProcessNotFound(name.to_owned()))
    }
}

#[cfg(target_os = "linux")]
impl MemoryManipulation for AnonManipulator {
    fn read(&self, address: usize, buf: &mut [u8]) -> MemoryResult<usize> {
        let mut mem_file = OpenOptions::new()
            .read(true)
            .open(format!("/proc/{}/mem", self.pid))?;
        mem_file.seek(SeekFrom::Start(address as u64))?;
        mem_file.read_exact(buf)?;
        Ok(buf.len())
    }
    fn write(&self, address: usize, payload: &[u8]) -> MemoryResult<usize> {
        let mut mem_file = OpenOptions::new()
            .write(true)
            .append(false)
            .open(format!("/proc/{}/mem", self.pid))?;
        mem_file.seek(SeekFrom::Start(address as u64))?;
        mem_file.write_all(payload)?;
        Ok(payload.len())
    }
}

impl Process for AnonManipulator {
    fn pid(&self) -> i32 {
        self.pid
    }
}