use alloc::vec::Vec;
use core::{ffi::c_void, slice};
use crate::types::ImageRuntimeFunction;
use crate::unwind::ignoring_set_fpreg;
pub fn find_valid_instruction_offset(
module: *mut c_void,
runtime: &ImageRuntimeFunction,
) -> Option<u32> {
let start = module as u64 + runtime.BeginAddress as u64;
let end = module as u64 + runtime.EndAddress as u64;
let size = end - start;
let pattern = &[0x48u8, 0xFFu8, 0x15u8];
unsafe {
let bytes = slice::from_raw_parts(start as *const u8, size as usize);
memchr::memmem::find(bytes, pattern).map(|pos| (pos + 7) as u32)
}
}
pub fn find_gadget(
module: *mut c_void,
pattern: &[u8],
runtime_table: &[ImageRuntimeFunction],
required_frame_size: Option<u32>,
) -> Option<(*mut u8, u32)> {
unsafe {
let mut gadgets: Vec<(*mut u8, u32)> = runtime_table
.iter()
.filter_map(|runtime| {
let start = module as u64 + runtime.BeginAddress as u64;
let end = module as u64 + runtime.EndAddress as u64;
let size = end.saturating_sub(start);
let bytes = slice::from_raw_parts(start as *const u8, size as usize);
let pos = memchr::memmem::find(bytes, pattern)?;
let addr = (start as *mut u8).wrapping_add(pos);
let frame_size = ignoring_set_fpreg(module, runtime)?;
if frame_size == 0 {
return None;
}
if let Some(req) = required_frame_size {
if frame_size != req {
return None;
}
}
Some((addr, frame_size))
})
.collect();
if gadgets.is_empty() {
return None;
}
shuffle(&mut gadgets);
gadgets.first().copied()
}
}
pub fn shuffle<T>(list: &mut [T]) {
let mut seed = unsafe { core::arch::x86_64::_rdtsc() };
for i in (1..list.len()).rev() {
seed = seed.wrapping_mul(1103515245).wrapping_add(12345);
let j = seed as usize % (i + 1);
list.swap(i, j);
}
}
#[cfg(feature = "desync")]
pub unsafe fn find_base_thread_return_address(
kernel32: *mut c_void,
base_thread_addr: *mut c_void,
base_thread_size: usize,
) -> Option<usize> {
let _ = kernel32;
let base_addr = base_thread_addr as usize;
let stack_base: usize;
let stack_limit: usize;
core::arch::asm!(
"mov {sb}, gs:[0x08]",
"mov {sl}, gs:[0x10]",
sb = out(reg) stack_base,
sl = out(reg) stack_limit,
options(nostack, preserves_flags, readonly),
);
let mut rsp = stack_base.saturating_sub(8);
while rsp >= stack_limit {
let val = *(rsp as *const usize);
if val >= base_addr && val < base_addr + base_thread_size {
return Some(rsp);
}
rsp = rsp.saturating_sub(8);
if rsp == 0 {
break;
}
}
None
}