use windows::Win32::Foundation::HANDLE;
use crate::memory::{read_memory_bytes, write_memory_bytes, MemoryError};
use crate::memory_hook::utils::{ProtectionGuard, SendableHandle};
pub struct BytesSwitch {
handle: SendableHandle,
target_address: usize,
original_bytes: Vec<u8>,
patch_bytes: Vec<u8>,
is_enabled: bool,
}
impl BytesSwitch {
pub fn new(
handle: HANDLE,
target_address: usize,
original_bytes: Vec<u8>,
patch_bytes: Vec<u8>,
) -> Self {
Self {
handle: SendableHandle(handle),
target_address,
original_bytes,
patch_bytes,
is_enabled: false,
}
}
pub fn new_nop(handle: HANDLE, target_address: usize, byte_count: usize) -> Result<Self, MemoryError> {
let original_bytes = read_memory_bytes(handle, target_address, byte_count)?;
let patch_bytes = vec![0x90; byte_count];
Ok(Self::new(handle, target_address, original_bytes, patch_bytes))
}
pub fn builder() -> crate::memory_hook::bytes_switch::builder::BytesSwitchBuilder {
crate::memory_hook::bytes_switch::builder::BytesSwitchBuilder::new()
}
pub fn enable(&mut self) -> Result<(), MemoryError> {
if self.is_enabled {
return Err(MemoryError::WriteFailed("Patch already enabled".to_string()));
}
if self.original_bytes.len() != self.patch_bytes.len() {
return Err(MemoryError::WriteFailed(
"Original and patch bytes length mismatch".to_string()
));
}
let _guard = ProtectionGuard::new(
self.handle.0,
self.target_address,
self.patch_bytes.len()
)?;
write_memory_bytes(self.handle.0, self.target_address, &self.patch_bytes)?;
self.is_enabled = true;
Ok(())
}
pub fn disable(&mut self) -> Result<(), MemoryError> {
if !self.is_enabled {
return Err(MemoryError::WriteFailed("Patch not enabled".to_string()));
}
let _guard = ProtectionGuard::new(
self.handle.0,
self.target_address,
self.original_bytes.len()
)?;
write_memory_bytes(self.handle.0, self.target_address, &self.original_bytes)?;
self.is_enabled = false;
Ok(())
}
pub fn toggle(&mut self) -> Result<(), MemoryError> {
if self.is_enabled {
self.disable()
} else {
self.enable()
}
}
pub fn reset(&mut self) {
if self.is_enabled {
let _ = self.disable();
}
self.original_bytes.clear();
self.patch_bytes.clear();
self.is_enabled = false;
}
pub fn is_enabled(&self) -> bool {
self.is_enabled
}
pub fn target_address(&self) -> usize {
self.target_address
}
pub fn original_bytes(&self) -> &[u8] {
&self.original_bytes
}
pub fn patch_bytes(&self) -> &[u8] {
&self.patch_bytes
}
}
impl Drop for BytesSwitch {
fn drop(&mut self) {
if self.is_enabled {
let _ = self.disable();
}
}
}