windows_recipe_messagebox/common/
mod.rs

1use isr::{
2    Profile,
3    cache::{IsrCache, JsonCodec},
4};
5use vmi::{
6    VcpuId, VmiCore, VmiDriver, VmiError, VmiOs, VmiSession, VmiState,
7    arch::amd64::Amd64,
8    driver::xen::VmiXenDriver,
9    os::{VmiOsProcess as _, windows::WindowsOs},
10};
11use xen::XenStore;
12
13pub fn create_vmi_session() -> Result<
14    (
15        VmiSession<'static, VmiXenDriver<Amd64>, WindowsOs<VmiXenDriver<Amd64>>>,
16        Profile<'static>,
17    ),
18    Box<dyn std::error::Error>,
19> {
20    tracing_subscriber::fmt()
21        .with_max_level(tracing::Level::DEBUG)
22        .with_target(false)
23        .init();
24
25    let domain_id = 'x: {
26        for name in &["win7", "win10", "win11", "ubuntu22"] {
27            if let Some(domain_id) = XenStore::new()?.domain_id_from_name(name)? {
28                break 'x domain_id;
29            }
30        }
31
32        panic!("Domain not found");
33    };
34
35    tracing::debug!(?domain_id);
36
37    // Setup VMI.
38    let driver = VmiXenDriver::<Amd64>::new(domain_id)?;
39    let core = VmiCore::new(driver)?;
40
41    // Try to find the kernel information.
42    // This is necessary in order to load the profile.
43    let kernel_info = {
44        // Pause the VCPU to get consistent state.
45        let _pause_guard = core.pause_guard()?;
46
47        // Get the register state for the first VCPU.
48        let registers = core.registers(VcpuId(0))?;
49
50        // On AMD64 architecture, the kernel is usually found using the
51        // `MSR_LSTAR` register, which contains the address of the system call
52        // handler. This register is set by the operating system during boot
53        // and is left unchanged (unless some rootkits are involved).
54        //
55        // Therefore, we can take an arbitrary registers at any point in time
56        // (as long as the OS has booted and the page tables are set up) and
57        // use them to find the kernel.
58        WindowsOs::find_kernel(&core, &registers)?.expect("kernel information")
59    };
60
61    // Load the profile.
62    // The profile contains offsets to kernel functions and data structures.
63    let isr = IsrCache::<JsonCodec>::new("cache")?;
64    let entry = isr.entry_from_codeview(kernel_info.codeview)?;
65    let entry = Box::leak(Box::new(entry));
66    let profile = entry.profile()?;
67
68    // Create the VMI session.
69    tracing::info!("Creating VMI session");
70    let os = WindowsOs::<VmiXenDriver<Amd64>>::new(&profile)?;
71
72    // Please don't do this in production code.
73    // This is only done for the sake of the example.
74    let core = Box::leak(Box::new(core));
75    let os = Box::leak(Box::new(os));
76
77    Ok((VmiSession::new(core, os), profile))
78}
79
80pub fn find_process<'a, Driver, Os>(
81    vmi: &VmiState<'a, Driver, Os>,
82    name: &str,
83) -> Result<Option<Os::Process<'a>>, VmiError>
84where
85    Driver: VmiDriver,
86    Os: VmiOs<Driver>,
87{
88    for process in vmi.os().processes()? {
89        let process = process?;
90
91        if process.name()?.to_lowercase() == name {
92            return Ok(Some(process));
93        }
94    }
95
96    Ok(None)
97}