use core::ffi::c_void;
use crate::helper::{search_bytes, JopcallError};
use core::arch::global_asm;
use core::ptr::slice_from_raw_parts;
#[repr(C)]
#[derive(Debug)]
pub struct Syscall {
pub ssn:u16,
pub address:*const c_void,
pub hooked:bool,
}
#[macro_export]
macro_rules! jopcall {
($gadget_list:expr, $syscall:expr $(,$args:expr)*) => {
{
fn enforce_syscall(value:&$crate::syscall::Syscall)->&$crate::syscall::Syscall{
&value
}
fn enforce_slice(value:&[*const c_void])->&[*const c_void]{
if value.len() > 5 {
panic!("Too many gadgets! Provide fewer than 5");
}
value
}
let gadget_list = enforce_slice($gadget_list);
let gadget_count = gadget_list.len() as u16;
let pgadget_list = (*(gadget_list.clone())).as_ptr() as *const c_void;
let syscall = enforce_syscall(&$syscall);
let ssn = syscall.ssn;
let address = syscall.address;
let mut arg_count:u16 = 0;
$(
let arg = $args;
arg_count += 1;
)*
let syscall_count = $crate::syscall::SyscallCount(gadget_count, arg_count);
$crate::syscall::isc(pgadget_list, ssn, address, syscall_count, $($args), *)
}
}
}
#[macro_export]
macro_rules! syscall{
($syscall:expr $(,$args:expr)*) => {
{
fn enforce_syscall(value:&$crate::syscall::Syscall)->&$crate::syscall::Syscall{
&value
}
let syscall = enforce_syscall(&$syscall);
let ssn = syscall.ssn;
let address = syscall.address;
let pgadget_list = [syscall.address;1];
let mut arg_count:u16 = 0;
$(
let arg = $args;
arg_count += 1;
)*
let syscall_count = $crate::syscall::SyscallCount(1 as u16, arg_count);
$crate::syscall::isc(pgadget_list.as_ptr() as *const c_void, ssn, address, syscall_count, $($args), *)
}
}
}
#[macro_export]
macro_rules! get_syscall{
($dll_name:expr, $syscall_name:expr) => {
$crate::syscall::lookup_syscall($crate::pfunction::get_function_pointer($crate::peb_walk::get_dll_base_address($dll_name).unwrap(), $syscall_name))
}
}
#[repr(C)]
pub struct SyscallCount(pub u16, pub u16);
pub unsafe fn lookup_syscall(function_address:*const c_void)->Result<Syscall, JopcallError>{
let ntdll_prefix:&[u8] = &[0x4C, 0x8B, 0xD1, 0xB8];
let function_bytes:&[u8] = &*slice_from_raw_parts(function_address as *const u8, 36) as &[u8];
let prefix_offset:usize = match search_bytes(&ntdll_prefix, function_bytes) {
Ok(index) => index,
Err(e) => {return Err(e)}
};
let hooked = if prefix_offset > 0 {
true
} else {
false
};
let ssn_bytes:&[u8] = &*slice_from_raw_parts(function_address.cast::<u8>().offset((ntdll_prefix.len() + prefix_offset) as isize) as *const u8, 4) as &[u8];
if ssn_bytes[2] != 0 && ssn_bytes[3] != 0 {
return Err(JopcallError::InvalidSSN);
}
let ssn:u16 = (ssn_bytes[1] as u16) << 8 | ssn_bytes[0] as u16;
let syscall_instruction:&[u8] = &[0x0F, 0x05];
let syscall_offset:usize = match search_bytes(syscall_instruction,function_bytes) {
Ok(index) => index,
Err(e) => {return Err(e)}
};
let address:*const c_void = function_address.cast::<u8>().offset(syscall_offset as isize) as *const c_void;
Ok(Syscall {
ssn,
address,
hooked
})
}
extern "C" {
pub fn isc(
gadget_list:*const c_void,
ssn:u16,
addr:*const c_void,
syscall_count:SyscallCount,
...)->i64;
}
global_asm!(
"
.global isc
isc:
mov [rsp - 0x8], rsi
mov [rsp - 0x10], rdi
mov [rsp - 0x18], r12
mov [rsp - 0x20], r14
", "
mov r11, rcx
mov rcx, r9
", "
xor r14, r14
mov r14w, cx
shl r14w, 3
", "
shr ecx, 16
movzx ecx, cx
", "
mov rax, r14
cmp rax, 0x08
je 2f
sub rax, 0x08
3:
push [r11 + rax];
sub rax, 0x08
cmp rax, 0
jne 3b
2:
", " mov r11, [r11]
", "
mov eax, edx
mov r12, r8
", "
sub r14, 0x08
mov r10, [rsp + 0x28 + r14]
mov rdx, [rsp + 0x30 + r14]
mov r8, [rsp + 0x38 + r14]
mov r9, [rsp + 0x40 + r14]
sub rcx, 0x4
jle 4f
", "
lea rsi, [rsp + 0x48 + r14]
lea rdi, [rsp + 0x28]
rep movsq
4:
", "
mov rcx, r12
mov rsi, [rsp - 0x8]
mov rdi, [rsp - 0x10]
mov r12, [rsp - 0x18]
mov r14, [rsp - 0x20]
jmp r11
"
);