Skip to main content

windows_recipe_writefile_advanced/common/
mod.rs

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