#![allow(
dead_code,
reason = "each example uses a different subset of these helpers"
)]
use std::sync::{Arc, atomic::AtomicBool};
use anyhow::{Context as _, Error};
use isr::{Profile, cache::IsrCache};
use tracing_subscriber::EnvFilter;
use vmi::{
VcpuId, VmiCore, VmiSession,
arch::amd64::Amd64,
driver::{VmiFullDriver, xen::VmiXenDriver},
os::{
ProcessId, VmiOsProcess as _,
windows::{WindowsKernelInformation, WindowsOs},
},
};
pub struct VmiSetup {
core: VmiCore<VmiXenDriver<Amd64>>,
os: WindowsOs<VmiXenDriver<Amd64>>,
isr: IsrCache,
profile: Profile<'static>,
kernel_info: WindowsKernelInformation,
terminate_flag: Arc<AtomicBool>,
}
impl VmiSetup {
pub fn new() -> Result<Self, Error> {
let filter = EnvFilter::default()
.add_directive(tracing::Level::DEBUG.into())
.add_directive("reqwest=warn".parse()?)
.add_directive("rustls=warn".parse()?);
tracing_subscriber::fmt()
.with_env_filter(filter)
.with_target(false)
.init();
let terminate_flag = Arc::new(AtomicBool::new(false));
signal_hook::flag::register(signal_hook::consts::SIGHUP, terminate_flag.clone())?;
signal_hook::flag::register(signal_hook::consts::SIGINT, terminate_flag.clone())?;
signal_hook::flag::register(signal_hook::consts::SIGALRM, terminate_flag.clone())?;
signal_hook::flag::register(signal_hook::consts::SIGTERM, terminate_flag.clone())?;
let driver = VmiXenDriver::<Amd64>::try_from_env()?
.context("invalid VMI_XEN_DOMAIN environment variable")?;
let core = VmiCore::new(driver)?;
let kernel_info = {
let _pause_guard = core.pause_guard()?;
let registers = core.registers(VcpuId(0))?;
WindowsOs::find_kernel(&core, ®isters)?.context("cannot find kernel information")?
};
tracing::info!(codeview = ?kernel_info.codeview, "loading kernel profile");
let isr = IsrCache::new("cache")?;
let entry = isr.entry_from_codeview(kernel_info.codeview.clone())?;
let entry = Box::leak(Box::new(entry));
let profile = entry.profile()?;
tracing::info!("creating VMI session");
let os = WindowsOs::<VmiXenDriver<Amd64>>::new(&profile)?;
Ok(Self {
core,
os,
isr,
profile,
kernel_info,
terminate_flag,
})
}
pub fn session(&self) -> VmiSession<'_, WindowsOs<VmiXenDriver<Amd64>>> {
VmiSession::new(&self.core, &self.os)
}
pub fn profile(&self) -> &Profile<'static> {
&self.profile
}
pub fn isr(&self) -> &IsrCache {
&self.isr
}
pub fn kernel_info(&self) -> &WindowsKernelInformation {
&self.kernel_info
}
pub fn terminate_flag(&self) -> Arc<AtomicBool> {
self.terminate_flag.clone()
}
}
pub fn find_process_id<Driver>(
session: &VmiSession<'_, WindowsOs<Driver>>,
process_name: &str,
) -> Result<ProcessId, Error>
where
Driver: VmiFullDriver<Architecture = Amd64>,
{
let paused = session.pause_guard()?;
let vmi = paused.state();
let process = vmi
.os()
.find_process(process_name)?
.with_context(|| format!("process `{process_name}` not found"))?;
let process_id = process.id()?;
tracing::info!(
process = process_name,
pid = %process_id,
"found target process"
);
Ok(process_id)
}