use std::ops::DerefMut;
use std::slice::IterMut;
use crate::internal::memory::{hook_function, write_aob, MemoryPattern};
use crate::internal::memory_region::*;
use anyhow::{Context, Result};
pub trait Inject {
fn inject(&mut self);
fn remove_injection(&mut self);
}
#[derive(Debug)]
pub struct Detour {
pub entry_point: usize,
f_orig: Vec<u8>,
new_function: usize,
function_end: Option<&'static mut usize>,
}
impl Detour {
pub fn new(
entry_point: usize,
size: usize,
new_function: usize,
function_end: Option<&'static mut usize>,
) -> Detour {
let mut f_orig = vec![];
unsafe {
let slice_ = std::slice::from_raw_parts(entry_point as *const u8, size);
f_orig.extend_from_slice(slice_);
}
Detour {
entry_point,
f_orig,
new_function,
function_end,
}
}
pub fn new_from_aob(
scan: MemoryPattern,
region: &MemoryRegion,
new_function: usize,
function_end: Option<&'static mut usize>,
size_injection: usize,
offset: Option<isize>,
) -> Result<Detour> {
let mut entry_point = region.scan_aob(&scan)?.context("Couldn't find aob")?;
if let Some(v) = offset {
entry_point = ((entry_point as isize) + v) as usize;
}
Ok(Detour::new(
entry_point,
size_injection,
new_function,
function_end,
))
}
}
impl Inject for Detour {
fn inject(&mut self) {
unsafe {
hook_function(
self.entry_point,
self.new_function,
self.function_end.as_deref_mut(),
self.f_orig.len(),
)
.unwrap();
}
}
fn remove_injection(&mut self) {
unsafe {
write_aob(self.entry_point, &self.f_orig).unwrap();
}
}
}
#[cfg(feature = "impl-drop")]
impl Drop for Detour {
fn drop(&mut self) {
self.remove_injection();
}
}
#[derive(Debug)]
pub struct Injection {
pub entry_point: usize,
pub f_orig: Vec<u8>,
pub f_new: Vec<u8>,
}
impl Injection {
pub fn new(entry_point: usize, f_new: Vec<u8>) -> Injection {
let aob_size = f_new.len();
let slice = unsafe { std::slice::from_raw_parts(entry_point as *const u8, aob_size) };
let mut f_orig = Vec::new();
f_orig.extend_from_slice(slice);
Injection {
entry_point,
f_orig,
f_new,
}
}
pub fn new_from_aob(
region: &MemoryRegion,
f_new: Vec<u8>,
memory_pattern: MemoryPattern,
) -> Result<Injection> {
let entry_point = region
.scan_aob(&memory_pattern)?
.context("Couldn't find aob")?;
Ok(Injection::new(entry_point, f_new))
}
}
impl Inject for Injection {
fn inject(&mut self) {
unsafe {
write_aob(self.entry_point, &(self.f_new)).unwrap();
}
}
fn remove_injection(&mut self) {
unsafe {
write_aob(self.entry_point, &(self.f_orig)).unwrap();
}
}
}
#[cfg(feature = "impl-drop")]
impl Drop for Injection {
fn drop(&mut self) {
self.remove_injection();
}
}
pub struct StaticElement {
addr: usize,
original_value: Option<u32>,
}
impl StaticElement {
pub fn new(addr: usize) -> StaticElement {
let original_value = unsafe { Some(*(addr as *mut u32)) };
StaticElement {
addr,
original_value,
}
}
}
impl Inject for StaticElement {
fn inject(&mut self) {
unsafe {
let ptr = self.addr as *mut u32;
if self.original_value.is_none() {
self.original_value = Some(*ptr);
}
*ptr = 0;
}
}
fn remove_injection(&mut self) {
if self.original_value.is_none() {
return;
}
unsafe {
let ptr = self.addr as *mut u32;
*ptr = self.original_value.unwrap();
}
self.original_value = None;
}
}
#[cfg(feature = "impl-drop")]
impl Drop for StaticElement {
fn drop(&mut self) {
self.remove_injection();
}
}
impl Inject for Box<dyn Inject> {
fn inject(&mut self) {
self.deref_mut().inject();
}
fn remove_injection(&mut self) {
self.deref_mut().remove_injection();
}
}
impl<T: Inject> Inject for IterMut<'_, T> {
fn inject(&mut self) {
self.for_each(|x| x.inject());
}
fn remove_injection(&mut self) {
self.for_each(|x| x.remove_injection());
}
}