use core::{
ffi::{c_void, CStr},
ptr::read,
slice::from_raw_parts,
};
use crate::{
helper::PE,
hash::jenkins3,
syscall::{DOWN, RANGE, UP}
};
pub fn ssn(function_name: &str, module: *mut c_void) -> Option<u16> {
unsafe {
let export_dir = PE::parse(module)
.exports()
.directory()?;
let hash = jenkins3(function_name);
let module = module as usize;
let names = from_raw_parts((
module + (*export_dir).AddressOfNames as usize) as *const u32,
(*export_dir).NumberOfNames as usize
);
let functions = from_raw_parts(
(module + (*export_dir).AddressOfFunctions as usize) as *const u32,
(*export_dir).NumberOfFunctions as usize
);
let ordinals = from_raw_parts(
(module + (*export_dir).AddressOfNameOrdinals as usize) as *const u16,
(*export_dir).NumberOfNames as usize
);
for i in 0..(*export_dir).NumberOfNames as isize {
let ordinal = ordinals[i as usize] as usize;
let address = (module + functions[ordinal] as usize) as *const u8;
let name = CStr::from_ptr((module + names[i as usize] as usize) as *const i8)
.to_str()
.unwrap_or("");
if jenkins3(&name) == hash {
if read(address) == 0xB8
&& read(address.add(3)) == 0x00
&& read(address.add(4)) == 0x00
{
let high = read(address.add(2)) as u16;
let low = read(address.add(1)) as u16;
let ssn = (high << 8) | low;
return Some(ssn);
}
if read(address) == 0xE9 {
for idx in 1..RANGE {
if read(address.add(idx * DOWN)) == 0xB8
&& read(address.add(3 + idx * DOWN)) == 0x00
&& read(address.add(4 + idx * DOWN)) == 0x00
{
let high = read(address.add(2 + idx * DOWN)) as u16;
let low = read(address.add(1 + idx * DOWN)) as u16;
let ssn = (high << 8) | (low - (idx * 2) as u16);
return Some(ssn);
}
if read(address.offset(idx as isize * UP)) == 0xB8
&& read(address.offset(3 + idx as isize * UP)) == 0x00
&& read(address.offset(4 + idx as isize * UP)) == 0x00
{
let high = read(address.offset(2 + idx as isize * UP)) as u16;
let low = read(address.offset(1 + idx as isize * UP)) as u16;
let ssn = (high << 8) | (low + (idx * 2) as u16);
return Some(ssn);
}
}
}
if read(address.add(3)) == 0xE9 {
for idx in 1..RANGE {
if read(address.add(idx * DOWN)) == 0xB8
&& read(address.add(3 + idx * DOWN)) == 0x00
&& read(address.add(4 + idx * DOWN)) == 0x00
{
let high = read(address.add(2 + idx * DOWN)) as u16;
let low = read(address.add(1 + idx * DOWN)) as u16;
let ssn = (high << 8) | (low - (idx * 2) as u16);
return Some(ssn);
}
if read(address.offset(idx as isize * UP)) == 0xB8
&& read(address.offset(3 + idx as isize * UP)) == 0x00
&& read(address.offset(4 + idx as isize * UP)) == 0x00
{
let high = read(address.offset(2 + idx as isize * UP)) as u16;
let low = read(address.offset(1 + idx as isize * UP)) as u16;
let ssn = (high << 8) | (low + (idx * 2) as u16);
return Some(ssn);
}
}
}
}
}
}
None
}
pub fn get_syscall_address(address: *mut c_void) -> Option<u32> {
unsafe {
let address = address.cast::<u8>();
if is_wow64() {
return (1..255).find_map(|i| {
if read(address.add(i)) == 0xFF
&& read(address.add(i + 1)) == 0xD2
{
Some(address.add(i) as u32)
} else {
None
}
});
}
(1..255).find_map(|i| {
if read(address.add(i)) == 0x8B
&& read(address.add(i + 1)) == 0xD4
&& read(address.add(i + 2)) == 0x0F
&& read(address.add(i + 3)) == 0x34
&& read(address.add(i + 4)) == 0xC3
{
Some(address.add(i + 2) as u32)
} else {
None
}
})
}
}
#[inline(always)]
pub(crate) fn is_wow64() -> bool {
let addr = unsafe { super::__readfsdword(0xC0) };
addr != 0
}