mod kernel_mode;
mod user_mode;
use vmi_arch_amd64::{Amd64, Registers};
use vmi_core::{
Hex, VmiCore, VmiError,
driver::{
VmiDriver, VmiEventControl, VmiQueryRegisters, VmiRead, VmiSetProtection, VmiViewControl,
VmiVmControl, VmiWrite,
},
};
use vmi_os_windows::WindowsOs;
use self::{kernel_mode::KernelInjectorHandler, user_mode::UserInjectorHandler};
use super::{
super::{
BridgeDispatch, CallBuilder, InjectorExecutionAdapter, InjectorResultCode, KernelMode,
UserMode, arch::ArchAdapter as _,
},
OsAdapter,
};
impl<Driver, T, Bridge> InjectorExecutionAdapter<KernelMode, T, Bridge> for WindowsOs<Driver>
where
Driver: VmiDriver<Architecture = Amd64>
+ VmiRead
+ VmiWrite
+ VmiSetProtection
+ VmiQueryRegisters
+ VmiEventControl
+ VmiViewControl
+ VmiVmControl,
Bridge: BridgeDispatch<Self, InjectorResultCode>,
{
type Handler = KernelInjectorHandler<Driver, T, Bridge>;
}
impl<Driver, T, Bridge> InjectorExecutionAdapter<UserMode, T, Bridge> for WindowsOs<Driver>
where
Driver: VmiDriver<Architecture = Amd64>
+ VmiRead
+ VmiWrite
+ VmiSetProtection
+ VmiEventControl
+ VmiViewControl
+ VmiVmControl,
Bridge: BridgeDispatch<Self, InjectorResultCode>,
{
type Handler = UserInjectorHandler<Driver, T, Bridge>;
}
impl<Driver> OsAdapter for WindowsOs<Driver>
where
Driver: VmiDriver<Architecture = Amd64> + VmiRead + VmiWrite,
{
fn prepare_function_call(
&self,
vmi: &VmiCore<Self::Driver>,
registers: &mut Registers,
builder: CallBuilder,
) -> Result<(), VmiError> {
tracing::trace!(
rsp = %Hex(registers.rsp),
rip = %Hex(registers.rip),
"preparing function call"
);
let arguments = Amd64::push_arguments(vmi, registers, &builder.arguments)?;
tracing::trace!(
rsp = %Hex(registers.rsp),
"pushed arguments"
);
let mut addr = registers.rsp;
let nb_args = arguments.len();
let effective_nb_args = nb_args.max(4) as u64;
if (addr - effective_nb_args * 0x8 - 0x8) & 0xf != 8 {
addr -= 0x8;
tracing::trace!(
addr = %Hex(addr),
"aligning stack"
);
}
for index in (4..nb_args).rev() {
addr -= 0x8;
vmi.write_u64((addr.into(), registers.cr3.into()), arguments[index])?;
tracing::trace!(
index,
value = %Hex(arguments[index]),
addr = %Hex(addr),
"argument (stack)"
);
}
if nb_args > 3 {
registers.r9 = arguments[3];
tracing::trace!(
index = 3,
value = %Hex(arguments[3]),
"argument"
);
}
if nb_args > 2 {
registers.r8 = arguments[2];
tracing::trace!(
index = 2,
value = %Hex(arguments[2]),
"argument"
);
}
if nb_args > 1 {
registers.rdx = arguments[1];
tracing::trace!(
index = 1,
value = %Hex(arguments[1]),
"argument"
);
}
if nb_args > 0 {
registers.rcx = arguments[0];
tracing::trace!(
index = 0,
value = %Hex(arguments[0]),
"argument"
);
}
addr -= 0x20;
addr -= 0x8;
vmi.write_u64((addr.into(), registers.cr3.into()), registers.rip)?;
registers.rsp = addr;
registers.rip = builder.function_address.into();
tracing::trace!(
rsp = %Hex(registers.rsp),
rip = %Hex(registers.rip),
"finished preparing function call"
);
Ok(())
}
}