use crate::{CopyAddress, Memory, ProcessHandle, PutAddress};
#[derive(Clone, Debug)]
pub struct DataMember<T> {
offsets: Vec<usize>,
process: ProcessHandle,
_phantom: std::marker::PhantomData<*mut T>,
}
impl<T: Sized + Copy> DataMember<T> {
#[must_use]
pub fn new(handle: ProcessHandle) -> Self {
Self {
offsets: Vec::new(),
process: handle,
_phantom: std::marker::PhantomData,
}
}
#[must_use]
pub fn new_offset(handle: ProcessHandle, offsets: Vec<usize>) -> Self {
Self {
offsets,
process: handle,
_phantom: std::marker::PhantomData,
}
}
}
impl<T: Sized + Copy> Memory<T> for DataMember<T> {
fn set_offset(&mut self, new_offsets: Vec<usize>) {
self.offsets = new_offsets;
}
fn get_offset(&self) -> std::io::Result<usize> {
self.process.get_offset(&self.offsets)
}
unsafe fn read(&self) -> std::io::Result<T> {
let offset = self.process.get_offset(&self.offsets)?;
let mut buffer = vec![0_u8; std::mem::size_of::<T>()];
self.process.copy_address(offset, &mut buffer)?;
Ok(buffer.as_ptr().cast::<T>().read_unaligned())
}
fn write(&self, value: &T) -> std::io::Result<()> {
use std::slice;
let offset = self.process.get_offset(&self.offsets)?;
let buffer: &[u8] = unsafe {
slice::from_raw_parts((value as *const T).cast::<u8>(), std::mem::size_of::<T>())
};
self.process.put_address(offset, buffer)
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::TryIntoProcessHandle;
#[test]
fn modify_remote_i32() {
let test = 4_i32;
#[allow(clippy::cast_possible_wrap)]
let handle = (std::process::id() as crate::Pid)
.try_into_process_handle()
.unwrap();
println!("Process Handle: {:?}", handle);
let mut member = DataMember::<i32>::new(handle);
member.set_offset(vec![std::ptr::addr_of!(test) as usize]);
unsafe {
assert_eq!(test, member.read().unwrap());
}
member.write(&5_i32).unwrap();
assert_eq!(test, 5_i32);
}
#[test]
fn modify_remote_i64() {
let test = 3_i64;
#[allow(clippy::cast_possible_wrap)]
let handle = (std::process::id() as crate::Pid)
.try_into_process_handle()
.unwrap();
println!("Process Handle: {:?}", handle);
let mut member = DataMember::<i64>::new(handle);
member.set_offset(vec![std::ptr::addr_of!(test) as usize]);
unsafe {
assert_eq!(test, member.read().unwrap());
}
member.write(&-1_i64).unwrap();
assert_eq!(test, -1);
}
#[test]
fn modify_remote_usize() {
let test = 0_usize;
#[allow(clippy::cast_possible_wrap)]
let handle = (std::process::id() as crate::Pid)
.try_into_process_handle()
.unwrap();
println!("Process Handle: {:?}", handle);
let mut member = DataMember::<usize>::new(handle);
member.set_offset(vec![std::ptr::addr_of!(test) as usize]);
unsafe {
assert_eq!(test, member.read().unwrap());
}
member.write(&0xffff).unwrap();
assert_eq!(test, 0xffff);
}
}