use alloc::string::String;
use core::ptr::read;
use data::lc;
#[doc(hidden)]
pub mod asm;
const RANGE: usize = 255;
const DOWN: usize = 32;
const UP: isize = -32;
pub fn extract_ssn(address: *const u8) -> Option<u16> {
unsafe {
if read(address) == 0x4C
&& read(address.add(1)) == 0x8B
&& read(address.add(2)) == 0xD1
&& read(address.add(3)) == 0xB8
&& read(address.add(6)) == 0x00
&& read(address.add(7)) == 0x00
{
let high = read(address.add(5)) as u16;
let low = read(address.add(4)) as u16;
return Some((high << 8) | low);
}
if read(address) == 0xE9 {
return search_neighbors(address);
}
if read(address.add(3)) == 0xE9 {
return search_neighbors(address);
}
}
None
}
fn search_neighbors(address: *const u8) -> Option<u16> {
unsafe {
for idx in 1..RANGE {
if read(address.add(idx * DOWN)) == 0x4C
&& read(address.add(1 + idx * DOWN)) == 0x8B
&& read(address.add(2 + idx * DOWN)) == 0xD1
&& read(address.add(3 + idx * DOWN)) == 0xB8
&& read(address.add(6 + idx * DOWN)) == 0x00
&& read(address.add(7 + idx * DOWN)) == 0x00
{
let high = read(address.add(5 + idx * DOWN)) as u16;
let low = read(address.add(4 + idx * DOWN)) as u16;
let neighbor_ssn = (high << 8) | low;
return Some(neighbor_ssn.wrapping_sub(idx as u16));
}
if read(address.offset(idx as isize * UP)) == 0x4C
&& read(address.offset(1 + idx as isize * UP)) == 0x8B
&& read(address.offset(2 + idx as isize * UP)) == 0xD1
&& read(address.offset(3 + idx as isize * UP)) == 0xB8
&& read(address.offset(6 + idx as isize * UP)) == 0x00
&& read(address.offset(7 + idx as isize * UP)) == 0x00
{
let high = read(address.offset(5 + idx as isize * UP)) as u16;
let low = read(address.offset(4 + idx as isize * UP)) as u16;
let neighbor_ssn = (high << 8) | low;
return Some(neighbor_ssn.wrapping_add(idx as u16));
}
}
}
None
}
pub fn get_syscall_address(address: *mut core::ffi::c_void) -> Option<usize> {
unsafe {
let p = address.cast::<u8>();
(1..RANGE).find_map(|i| {
if read(p.add(i)) == 0x0F
&& read(p.add(i + 1)) == 0x05
&& read(p.add(i + 2)) == 0xC3
{
Some(p.add(i) as usize)
} else {
None
}
})
}
}
#[derive(Debug)]
pub enum SyscallError {
NtdllMissing,
FunctionNotFound(String),
SsnNotFound(String),
SyscallAddrNotFound(String),
}
impl core::fmt::Display for SyscallError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
SyscallError::NtdllMissing => write!(f, "ntdll.dll not loaded"),
SyscallError::FunctionNotFound(n) => write!(f, "export not found: {}", n),
SyscallError::SsnNotFound(n) => write!(f, "SSN not extractable for {}", n),
SyscallError::SyscallAddrNotFound(n) => write!(f, "syscall instr not found for {}", n),
}
}
}
impl core::error::Error for SyscallError {}
pub fn resolve_syscall(name: &str) -> Result<(u16, usize), SyscallError> {
let ntdll = crate::get_module_base_address(&lc!("ntdll.dll"));
if ntdll == 0 {
return Err(SyscallError::NtdllMissing);
}
let stub = crate::get_function_address(ntdll, name);
if stub == 0 {
return Err(SyscallError::FunctionNotFound(name.into()));
}
let ssn = extract_ssn(stub as *const u8)
.ok_or_else(|| SyscallError::SsnNotFound(name.into()))?;
let addr = get_syscall_address(stub as *mut _)
.ok_or_else(|| SyscallError::SyscallAddrNotFound(name.into()))?;
Ok((ssn, addr))
}