use std::ptr;
#[cfg(debug_assertions)]
use crate::utils::logger;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum RwError {
#[error("Null pointer")]
NullPointer,
#[error("Image not found: {0}")]
ImageBaseNotFound(#[from] crate::memory::info::image::ImageError),
#[error("Protection failed: {0}")]
ProtectionFailed(i32),
#[error("Thread error: {0}")]
ThreadError(#[from] crate::memory::platform::thread::ThreadError),
}
pub unsafe fn read<T: Copy>(address: usize) -> Result<T, RwError> {
unsafe {
if address == 0 {
return Err(RwError::NullPointer);
}
Ok(ptr::read(address as *const T))
}
}
pub unsafe fn read_at_rva<T: Copy>(rva: usize) -> Result<T, RwError> {
unsafe {
let image_name = crate::config::get_target_image_name().ok_or_else(|| {
crate::memory::info::image::ImageError::NotFound("call mem_init first".to_string())
})?;
let base = crate::memory::info::image::get_image_base(&image_name)?;
read::<T>(base + rva)
}
}
pub unsafe fn read_pointer_chain(base: usize, offsets: &[usize]) -> Result<usize, RwError> {
unsafe {
if base == 0 {
return Err(RwError::NullPointer);
}
let mut current = base;
for (i, &offset) in offsets.iter().enumerate() {
if i < offsets.len() - 1 {
let ptr = (current + offset) as *const usize;
if ptr.is_null() {
return Err(RwError::NullPointer);
}
current = ptr::read(ptr);
if current == 0 {
return Err(RwError::NullPointer);
}
} else {
current += offset;
}
}
Ok(current)
}
}
pub unsafe fn write<T: Copy>(address: usize, value: T) -> Result<(), RwError> {
unsafe {
if address == 0 {
return Err(RwError::NullPointer);
}
ptr::write(address as *mut T, value);
Ok(())
}
}
pub unsafe fn write_code<T: Copy>(address: usize, value: T) -> Result<(), RwError> {
unsafe {
if address == 0 {
return Err(RwError::NullPointer);
}
let size = std::mem::size_of::<T>();
let data = std::slice::from_raw_parts(&value as *const T as *const u8, size);
write_bytes(address, data)
}
}
pub unsafe fn write_at_rva<T: Copy>(rva: usize, value: T) -> Result<(), RwError> {
unsafe {
let image_name = crate::config::get_target_image_name().ok_or_else(|| {
crate::memory::info::image::ImageError::NotFound("call mem_init first".to_string())
})?;
let base = crate::memory::info::image::get_image_base(&image_name)?;
write::<T>(base + rva, value)
}
}
pub unsafe fn write_bytes(address: usize, data: &[u8]) -> Result<(), RwError> {
unsafe {
let suspended = crate::memory::platform::thread::suspend_other_threads()?;
let result = super::patch::stealth_write(address, data).map_err(|e| match e {
super::patch::PatchError::ProtectionFailed(kr) => RwError::ProtectionFailed(kr),
_ => RwError::ProtectionFailed(0),
});
crate::memory::platform::thread::resume_threads(&suspended);
if result.is_ok() {
#[cfg(debug_assertions)]
logger::debug("Bytes written");
}
result
}
}