windows_breakpoint_manager/common/
mod.rs1#![allow(
4 dead_code,
5 reason = "each example uses a different subset of these helpers"
6)]
7
8use std::sync::{Arc, atomic::AtomicBool};
9
10use anyhow::{Context as _, Error};
11use isr::{Profile, cache::IsrCache};
12use tracing_subscriber::EnvFilter;
13use vmi::{
14 VcpuId, VmiCore, VmiSession,
15 arch::amd64::Amd64,
16 driver::{VmiFullDriver, xen::VmiXenDriver},
17 os::{
18 ProcessId, VmiOsProcess as _,
19 windows::{WindowsKernelInformation, WindowsOs},
20 },
21};
22
23pub struct VmiSetup {
25 core: VmiCore<VmiXenDriver<Amd64>>,
26 os: WindowsOs<VmiXenDriver<Amd64>>,
27 isr: IsrCache,
28 profile: Profile<'static>,
29 kernel_info: WindowsKernelInformation,
30 terminate_flag: Arc<AtomicBool>,
31}
32
33impl VmiSetup {
34 pub fn new() -> Result<Self, Error> {
36 let filter = EnvFilter::default()
37 .add_directive(tracing::Level::DEBUG.into())
38 .add_directive("reqwest=warn".parse()?)
39 .add_directive("rustls=warn".parse()?);
40
41 tracing_subscriber::fmt()
42 .with_env_filter(filter)
43 .with_target(false)
44 .init();
45
46 let terminate_flag = Arc::new(AtomicBool::new(false));
48 signal_hook::flag::register(signal_hook::consts::SIGHUP, terminate_flag.clone())?;
49 signal_hook::flag::register(signal_hook::consts::SIGINT, terminate_flag.clone())?;
50 signal_hook::flag::register(signal_hook::consts::SIGALRM, terminate_flag.clone())?;
51 signal_hook::flag::register(signal_hook::consts::SIGTERM, terminate_flag.clone())?;
52
53 let driver = VmiXenDriver::<Amd64>::try_from_env()?
55 .context("invalid VMI_XEN_DOMAIN environment variable")?;
56 let core = VmiCore::new(driver)?;
57
58 let kernel_info = {
61 let _pause_guard = core.pause_guard()?;
63
64 let registers = core.registers(VcpuId(0))?;
66
67 WindowsOs::find_kernel(&core, ®isters)?.context("cannot find kernel information")?
76 };
77
78 tracing::info!(codeview = ?kernel_info.codeview, "loading kernel profile");
81 let isr = IsrCache::new("cache")?;
82 let entry = isr.entry_from_codeview(kernel_info.codeview.clone())?;
83
84 let entry = Box::leak(Box::new(entry));
87 let profile = entry.profile()?;
88
89 tracing::info!("creating VMI session");
90 let os = WindowsOs::<VmiXenDriver<Amd64>>::new(&profile)?;
91
92 Ok(Self {
93 core,
94 os,
95 isr,
96 profile,
97 kernel_info,
98 terminate_flag,
99 })
100 }
101
102 pub fn session(&self) -> VmiSession<'_, WindowsOs<VmiXenDriver<Amd64>>> {
104 VmiSession::new(&self.core, &self.os)
105 }
106
107 pub fn profile(&self) -> &Profile<'static> {
109 &self.profile
110 }
111
112 pub fn isr(&self) -> &IsrCache {
114 &self.isr
115 }
116
117 pub fn kernel_info(&self) -> &WindowsKernelInformation {
119 &self.kernel_info
120 }
121
122 pub fn terminate_flag(&self) -> Arc<AtomicBool> {
124 self.terminate_flag.clone()
125 }
126}
127
128pub fn find_process_id<Driver>(
130 session: &VmiSession<'_, WindowsOs<Driver>>,
131 process_name: &str,
132) -> Result<ProcessId, Error>
133where
134 Driver: VmiFullDriver<Architecture = Amd64>,
135{
136 let paused = session.pause_guard()?;
137 let vmi = paused.state();
138 let process = vmi
139 .os()
140 .find_process(process_name)?
141 .with_context(|| format!("process `{process_name}` not found"))?;
142
143 let process_id = process.id()?;
144
145 tracing::info!(
146 process = process_name,
147 pid = %process_id,
148 "found target process"
149 );
150
151 Ok(process_id)
152}