pub struct VmiEventResponse<Arch>where
Arch: Architecture + ?Sized,{
pub flags: VmiEventResponseFlags,
pub view: Option<View>,
pub registers: Option<<<Arch as Architecture>::Registers as Registers>::GpRegisters>,
}Expand description
A response to a VMI event.
Fields§
§flags: VmiEventResponseFlagsFlags associated with the response.
view: Option<View>The view to set for the VCPU.
registers: Option<<<Arch as Architecture>::Registers as Registers>::GpRegisters>The VCPU registers to set.
Implementations§
Source§impl<Arch> VmiEventResponse<Arch>where
Arch: Architecture + ?Sized,
impl<Arch> VmiEventResponse<Arch>where
Arch: Architecture + ?Sized,
Sourcepub fn reinject_interrupt() -> VmiEventResponse<Arch>
Available on crate feature utils only.
pub fn reinject_interrupt() -> VmiEventResponse<Arch>
utils only.Creates a response to reinject an interrupt.
Examples found in repository?
examples/windows-breakpoint-manager.rs (line 288)
273 fn interrupt(
274 &mut self,
275 vmi: &VmiContext<'_, Driver, WindowsOs<Driver>>,
276 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
277 let tag = match self.bpm.get_by_event(vmi.event(), ()) {
278 Some(breakpoints) => {
279 // Breakpoints can have multiple tags, but we have set only one
280 // tag for each breakpoint.
281 let first_breakpoint = breakpoints.into_iter().next().expect("breakpoint");
282 first_breakpoint.tag()
283 }
284 None => {
285 if BreakpointController::is_breakpoint(vmi, vmi.event())? {
286 // This breakpoint was not set by us. Reinject it.
287 tracing::warn!("Unknown breakpoint, reinjecting");
288 return Ok(VmiEventResponse::reinject_interrupt());
289 }
290 else {
291 // We have received a breakpoint event, but there is no
292 // breakpoint instruction at the current memory location.
293 // This can happen if the event was triggered by a breakpoint
294 // we just removed.
295 tracing::warn!("Ignoring old breakpoint event");
296 return Ok(
297 VmiEventResponse::toggle_fast_singlestep().and_set_view(vmi.default_view())
298 );
299 }
300 }
301 };
302
303 let process = vmi.os().current_process()?;
304 let process_id = process.id()?;
305 let process_name = process.name()?;
306 tracing::Span::current()
307 .record("pid", process_id.0)
308 .record("process", process_name);
309
310 match tag {
311 "NtCreateFile" => self.NtCreateFile(vmi)?,
312 "NtWriteFile" => self.NtWriteFile(vmi)?,
313 "PspInsertProcess" => self.PspInsertProcess(vmi)?,
314 "MmCleanProcessAddressSpace" => self.MmCleanProcessAddressSpace(vmi)?,
315 _ => panic!("Unhandled tag: {tag}"),
316 }
317
318 Ok(VmiEventResponse::toggle_fast_singlestep().and_set_view(vmi.default_view()))
319 }Sourcepub fn toggle_singlestep() -> VmiEventResponse<Arch>
Available on crate feature utils only.
pub fn toggle_singlestep() -> VmiEventResponse<Arch>
utils only.Creates a response to toggle single-step mode.
Examples found in repository?
examples/windows-breakpoint-manager.rs (line 258)
237 fn memory_access(
238 &mut self,
239 vmi: &VmiContext<'_, Driver, WindowsOs<Driver>>,
240 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
241 let memory_access = vmi.event().reason().as_memory_access();
242
243 tracing::trace!(
244 pa = %memory_access.pa,
245 va = %memory_access.va,
246 access = %memory_access.access,
247 );
248
249 if memory_access.access.contains(MemoryAccess::W) {
250 // It is assumed that a write memory access event is caused by a
251 // page table modification.
252 //
253 // The page table entry is marked as dirty in the page table monitor
254 // and a singlestep is performed to process the dirty entries.
255 self.ptm
256 .mark_dirty_entry(memory_access.pa, self.view, vmi.event().vcpu_id());
257
258 Ok(VmiEventResponse::toggle_singlestep().and_set_view(vmi.default_view()))
259 }
260 else if memory_access.access.contains(MemoryAccess::R) {
261 // When the guest tries to read from the memory, a fast-singlestep
262 // is performed over the instruction that tried to read the memory.
263 // This is done to allow the instruction to read the original memory
264 // content.
265 Ok(VmiEventResponse::toggle_fast_singlestep().and_set_view(vmi.default_view()))
266 }
267 else {
268 panic!("Unhandled memory access: {memory_access:?}");
269 }
270 }
271
272 #[tracing::instrument(skip_all, fields(pid, process))]
273 fn interrupt(
274 &mut self,
275 vmi: &VmiContext<'_, Driver, WindowsOs<Driver>>,
276 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
277 let tag = match self.bpm.get_by_event(vmi.event(), ()) {
278 Some(breakpoints) => {
279 // Breakpoints can have multiple tags, but we have set only one
280 // tag for each breakpoint.
281 let first_breakpoint = breakpoints.into_iter().next().expect("breakpoint");
282 first_breakpoint.tag()
283 }
284 None => {
285 if BreakpointController::is_breakpoint(vmi, vmi.event())? {
286 // This breakpoint was not set by us. Reinject it.
287 tracing::warn!("Unknown breakpoint, reinjecting");
288 return Ok(VmiEventResponse::reinject_interrupt());
289 }
290 else {
291 // We have received a breakpoint event, but there is no
292 // breakpoint instruction at the current memory location.
293 // This can happen if the event was triggered by a breakpoint
294 // we just removed.
295 tracing::warn!("Ignoring old breakpoint event");
296 return Ok(
297 VmiEventResponse::toggle_fast_singlestep().and_set_view(vmi.default_view())
298 );
299 }
300 }
301 };
302
303 let process = vmi.os().current_process()?;
304 let process_id = process.id()?;
305 let process_name = process.name()?;
306 tracing::Span::current()
307 .record("pid", process_id.0)
308 .record("process", process_name);
309
310 match tag {
311 "NtCreateFile" => self.NtCreateFile(vmi)?,
312 "NtWriteFile" => self.NtWriteFile(vmi)?,
313 "PspInsertProcess" => self.PspInsertProcess(vmi)?,
314 "MmCleanProcessAddressSpace" => self.MmCleanProcessAddressSpace(vmi)?,
315 _ => panic!("Unhandled tag: {tag}"),
316 }
317
318 Ok(VmiEventResponse::toggle_fast_singlestep().and_set_view(vmi.default_view()))
319 }
320
321 #[tracing::instrument(skip_all)]
322 fn singlestep(
323 &mut self,
324 vmi: &VmiContext<'_, Driver, WindowsOs<Driver>>,
325 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
326 // Get the page table modifications by processing the dirty page table
327 // entries.
328 let ptm_events = self.ptm.process_dirty_entries(vmi, vmi.event().vcpu_id())?;
329
330 for event in &ptm_events {
331 // Log the page table modifications.
332 match &event {
333 PageTableMonitorEvent::PageIn(update) => tracing::debug!(?update, "page-in"),
334 PageTableMonitorEvent::PageOut(update) => tracing::debug!(?update, "page-out"),
335 }
336
337 // Let the breakpoint controller handle the page table modifications.
338 self.bpm.handle_ptm_event(vmi, event)?;
339 }
340
341 // Disable singlestep and switch back to our view.
342 Ok(VmiEventResponse::toggle_singlestep().and_set_view(self.view))
343 }Sourcepub fn toggle_fast_singlestep() -> VmiEventResponse<Arch>
Available on crate feature utils only.
pub fn toggle_fast_singlestep() -> VmiEventResponse<Arch>
utils only.Creates a response to toggle fast single-step mode.
Examples found in repository?
examples/windows-breakpoint-manager.rs (line 265)
237 fn memory_access(
238 &mut self,
239 vmi: &VmiContext<'_, Driver, WindowsOs<Driver>>,
240 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
241 let memory_access = vmi.event().reason().as_memory_access();
242
243 tracing::trace!(
244 pa = %memory_access.pa,
245 va = %memory_access.va,
246 access = %memory_access.access,
247 );
248
249 if memory_access.access.contains(MemoryAccess::W) {
250 // It is assumed that a write memory access event is caused by a
251 // page table modification.
252 //
253 // The page table entry is marked as dirty in the page table monitor
254 // and a singlestep is performed to process the dirty entries.
255 self.ptm
256 .mark_dirty_entry(memory_access.pa, self.view, vmi.event().vcpu_id());
257
258 Ok(VmiEventResponse::toggle_singlestep().and_set_view(vmi.default_view()))
259 }
260 else if memory_access.access.contains(MemoryAccess::R) {
261 // When the guest tries to read from the memory, a fast-singlestep
262 // is performed over the instruction that tried to read the memory.
263 // This is done to allow the instruction to read the original memory
264 // content.
265 Ok(VmiEventResponse::toggle_fast_singlestep().and_set_view(vmi.default_view()))
266 }
267 else {
268 panic!("Unhandled memory access: {memory_access:?}");
269 }
270 }
271
272 #[tracing::instrument(skip_all, fields(pid, process))]
273 fn interrupt(
274 &mut self,
275 vmi: &VmiContext<'_, Driver, WindowsOs<Driver>>,
276 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
277 let tag = match self.bpm.get_by_event(vmi.event(), ()) {
278 Some(breakpoints) => {
279 // Breakpoints can have multiple tags, but we have set only one
280 // tag for each breakpoint.
281 let first_breakpoint = breakpoints.into_iter().next().expect("breakpoint");
282 first_breakpoint.tag()
283 }
284 None => {
285 if BreakpointController::is_breakpoint(vmi, vmi.event())? {
286 // This breakpoint was not set by us. Reinject it.
287 tracing::warn!("Unknown breakpoint, reinjecting");
288 return Ok(VmiEventResponse::reinject_interrupt());
289 }
290 else {
291 // We have received a breakpoint event, but there is no
292 // breakpoint instruction at the current memory location.
293 // This can happen if the event was triggered by a breakpoint
294 // we just removed.
295 tracing::warn!("Ignoring old breakpoint event");
296 return Ok(
297 VmiEventResponse::toggle_fast_singlestep().and_set_view(vmi.default_view())
298 );
299 }
300 }
301 };
302
303 let process = vmi.os().current_process()?;
304 let process_id = process.id()?;
305 let process_name = process.name()?;
306 tracing::Span::current()
307 .record("pid", process_id.0)
308 .record("process", process_name);
309
310 match tag {
311 "NtCreateFile" => self.NtCreateFile(vmi)?,
312 "NtWriteFile" => self.NtWriteFile(vmi)?,
313 "PspInsertProcess" => self.PspInsertProcess(vmi)?,
314 "MmCleanProcessAddressSpace" => self.MmCleanProcessAddressSpace(vmi)?,
315 _ => panic!("Unhandled tag: {tag}"),
316 }
317
318 Ok(VmiEventResponse::toggle_fast_singlestep().and_set_view(vmi.default_view()))
319 }Sourcepub fn emulate() -> VmiEventResponse<Arch>
Available on crate feature utils only.
pub fn emulate() -> VmiEventResponse<Arch>
utils only.Creates a response to emulate the instruction.
Sourcepub fn set_view(view: View) -> VmiEventResponse<Arch>
Available on crate feature utils only.
pub fn set_view(view: View) -> VmiEventResponse<Arch>
utils only.Creates a response to set a specific view.
Sourcepub fn set_registers(
registers: <<Arch as Architecture>::Registers as Registers>::GpRegisters,
) -> VmiEventResponse<Arch>
Available on crate feature utils only.
pub fn set_registers( registers: <<Arch as Architecture>::Registers as Registers>::GpRegisters, ) -> VmiEventResponse<Arch>
utils only.Creates a response to set specific CPU registers.
Sourcepub fn and_reinject_interrupt(self) -> VmiEventResponse<Arch>
Available on crate feature utils only.
pub fn and_reinject_interrupt(self) -> VmiEventResponse<Arch>
utils only.Adds the reinject interrupt flag to the response.
Sourcepub fn and_toggle_singlestep(self) -> VmiEventResponse<Arch>
Available on crate feature utils only.
pub fn and_toggle_singlestep(self) -> VmiEventResponse<Arch>
utils only.Adds the toggle single-step flag to the response.
Sourcepub fn and_toggle_fast_singlestep(self) -> VmiEventResponse<Arch>
Available on crate feature utils only.
pub fn and_toggle_fast_singlestep(self) -> VmiEventResponse<Arch>
utils only.Adds the toggle fast single-step flag to the response.
Sourcepub fn and_emulate(self) -> VmiEventResponse<Arch>
Available on crate feature utils only.
pub fn and_emulate(self) -> VmiEventResponse<Arch>
utils only.Adds the emulate flag to the response.
Sourcepub fn and_set_view(self, view: View) -> VmiEventResponse<Arch>
Available on crate feature utils only.
pub fn and_set_view(self, view: View) -> VmiEventResponse<Arch>
utils only.Sets a specific view for the response.
Examples found in repository?
examples/windows-breakpoint-manager.rs (line 258)
237 fn memory_access(
238 &mut self,
239 vmi: &VmiContext<'_, Driver, WindowsOs<Driver>>,
240 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
241 let memory_access = vmi.event().reason().as_memory_access();
242
243 tracing::trace!(
244 pa = %memory_access.pa,
245 va = %memory_access.va,
246 access = %memory_access.access,
247 );
248
249 if memory_access.access.contains(MemoryAccess::W) {
250 // It is assumed that a write memory access event is caused by a
251 // page table modification.
252 //
253 // The page table entry is marked as dirty in the page table monitor
254 // and a singlestep is performed to process the dirty entries.
255 self.ptm
256 .mark_dirty_entry(memory_access.pa, self.view, vmi.event().vcpu_id());
257
258 Ok(VmiEventResponse::toggle_singlestep().and_set_view(vmi.default_view()))
259 }
260 else if memory_access.access.contains(MemoryAccess::R) {
261 // When the guest tries to read from the memory, a fast-singlestep
262 // is performed over the instruction that tried to read the memory.
263 // This is done to allow the instruction to read the original memory
264 // content.
265 Ok(VmiEventResponse::toggle_fast_singlestep().and_set_view(vmi.default_view()))
266 }
267 else {
268 panic!("Unhandled memory access: {memory_access:?}");
269 }
270 }
271
272 #[tracing::instrument(skip_all, fields(pid, process))]
273 fn interrupt(
274 &mut self,
275 vmi: &VmiContext<'_, Driver, WindowsOs<Driver>>,
276 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
277 let tag = match self.bpm.get_by_event(vmi.event(), ()) {
278 Some(breakpoints) => {
279 // Breakpoints can have multiple tags, but we have set only one
280 // tag for each breakpoint.
281 let first_breakpoint = breakpoints.into_iter().next().expect("breakpoint");
282 first_breakpoint.tag()
283 }
284 None => {
285 if BreakpointController::is_breakpoint(vmi, vmi.event())? {
286 // This breakpoint was not set by us. Reinject it.
287 tracing::warn!("Unknown breakpoint, reinjecting");
288 return Ok(VmiEventResponse::reinject_interrupt());
289 }
290 else {
291 // We have received a breakpoint event, but there is no
292 // breakpoint instruction at the current memory location.
293 // This can happen if the event was triggered by a breakpoint
294 // we just removed.
295 tracing::warn!("Ignoring old breakpoint event");
296 return Ok(
297 VmiEventResponse::toggle_fast_singlestep().and_set_view(vmi.default_view())
298 );
299 }
300 }
301 };
302
303 let process = vmi.os().current_process()?;
304 let process_id = process.id()?;
305 let process_name = process.name()?;
306 tracing::Span::current()
307 .record("pid", process_id.0)
308 .record("process", process_name);
309
310 match tag {
311 "NtCreateFile" => self.NtCreateFile(vmi)?,
312 "NtWriteFile" => self.NtWriteFile(vmi)?,
313 "PspInsertProcess" => self.PspInsertProcess(vmi)?,
314 "MmCleanProcessAddressSpace" => self.MmCleanProcessAddressSpace(vmi)?,
315 _ => panic!("Unhandled tag: {tag}"),
316 }
317
318 Ok(VmiEventResponse::toggle_fast_singlestep().and_set_view(vmi.default_view()))
319 }
320
321 #[tracing::instrument(skip_all)]
322 fn singlestep(
323 &mut self,
324 vmi: &VmiContext<'_, Driver, WindowsOs<Driver>>,
325 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
326 // Get the page table modifications by processing the dirty page table
327 // entries.
328 let ptm_events = self.ptm.process_dirty_entries(vmi, vmi.event().vcpu_id())?;
329
330 for event in &ptm_events {
331 // Log the page table modifications.
332 match &event {
333 PageTableMonitorEvent::PageIn(update) => tracing::debug!(?update, "page-in"),
334 PageTableMonitorEvent::PageOut(update) => tracing::debug!(?update, "page-out"),
335 }
336
337 // Let the breakpoint controller handle the page table modifications.
338 self.bpm.handle_ptm_event(vmi, event)?;
339 }
340
341 // Disable singlestep and switch back to our view.
342 Ok(VmiEventResponse::toggle_singlestep().and_set_view(self.view))
343 }Sourcepub fn and_set_registers(
self,
registers: <<Arch as Architecture>::Registers as Registers>::GpRegisters,
) -> VmiEventResponse<Arch>
Available on crate feature utils only.
pub fn and_set_registers( self, registers: <<Arch as Architecture>::Registers as Registers>::GpRegisters, ) -> VmiEventResponse<Arch>
utils only.Sets specific CPU registers for the response.
Trait Implementations§
Source§impl<Arch> Debug for VmiEventResponse<Arch>
impl<Arch> Debug for VmiEventResponse<Arch>
Source§impl<Arch> Default for VmiEventResponse<Arch>where
Arch: Architecture + ?Sized,
impl<Arch> Default for VmiEventResponse<Arch>where
Arch: Architecture + ?Sized,
Source§fn default() -> VmiEventResponse<Arch>
fn default() -> VmiEventResponse<Arch>
Returns the “default value” for a type. Read more
Auto Trait Implementations§
impl<Arch> Freeze for VmiEventResponse<Arch>
impl<Arch> RefUnwindSafe for VmiEventResponse<Arch>
impl<Arch> Send for VmiEventResponse<Arch>
impl<Arch> Sync for VmiEventResponse<Arch>
impl<Arch> Unpin for VmiEventResponse<Arch>
impl<Arch> UnwindSafe for VmiEventResponse<Arch>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more