pub struct VmiEventResponse<Arch>where
Arch: Architecture,{
pub action: VmiEventAction,
pub view: Option<View>,
pub registers: Option<<<Arch as Architecture>::Registers as Registers>::GpRegisters>,
}Expand description
A response to a VMI event.
Fields§
§action: VmiEventActionThe primary action to take when resuming.
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,
impl<Arch> VmiEventResponse<Arch>where
Arch: Architecture,
Sourcepub fn deny() -> VmiEventResponse<Arch>
Available on crate features utils and injector only.
pub fn deny() -> VmiEventResponse<Arch>
utils and injector only.Creates a response to deny the event.
Sourcepub fn reinject_interrupt() -> VmiEventResponse<Arch>
Available on crate features utils and injector only.
pub fn reinject_interrupt() -> VmiEventResponse<Arch>
utils and injector only.Creates a response to reinject an interrupt.
Examples found in repository?
examples/windows-breakpoint-manager.rs (line 291)
276 fn interrupt(
277 &mut self,
278 vmi: &VmiContext<WindowsOs<Driver>>,
279 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
280 let tag = match self.bpm.get_by_event(vmi.event(), ()) {
281 Some(breakpoints) => {
282 // Breakpoints can have multiple tags, but we have set only one
283 // tag for each breakpoint.
284 let first_breakpoint = breakpoints.into_iter().next().expect("breakpoint");
285 first_breakpoint.tag()
286 }
287 None => {
288 if BreakpointController::is_breakpoint(vmi, vmi.event())? {
289 // This breakpoint was not set by us. Reinject it.
290 tracing::warn!("Unknown breakpoint, reinjecting");
291 return Ok(VmiEventResponse::reinject_interrupt());
292 }
293 else {
294 // We have received a breakpoint event, but there is no
295 // breakpoint instruction at the current memory location.
296 // This can happen if the event was triggered by a breakpoint
297 // we just removed.
298 tracing::warn!("Ignoring old breakpoint event");
299 return Ok(VmiEventResponse::fast_singlestep(vmi.default_view()));
300 }
301 }
302 };
303
304 let process = vmi.os().current_process()?;
305 let process_id = process.id()?;
306 let process_name = process.name()?;
307 tracing::Span::current()
308 .record("pid", process_id.0)
309 .record("process", process_name);
310
311 match tag {
312 "NtCreateFile" => self.NtCreateFile(vmi)?,
313 "NtWriteFile" => self.NtWriteFile(vmi)?,
314 "PspInsertProcess" => self.PspInsertProcess(vmi)?,
315 "MmCleanProcessAddressSpace" => self.MmCleanProcessAddressSpace(vmi)?,
316 _ => panic!("Unhandled tag: {tag}"),
317 }
318
319 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
320 }Sourcepub fn singlestep() -> VmiEventResponse<Arch>
Available on crate features utils and injector only.
pub fn singlestep() -> VmiEventResponse<Arch>
utils and injector only.Creates a response to single-step one instruction.
Examples found in repository?
examples/windows-breakpoint-manager.rs (line 261)
240 fn memory_access(
241 &mut self,
242 vmi: &VmiContext<WindowsOs<Driver>>,
243 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
244 let memory_access = vmi.event().reason().as_memory_access();
245
246 tracing::trace!(
247 pa = %memory_access.pa,
248 va = %memory_access.va,
249 access = %memory_access.access,
250 );
251
252 if memory_access.access.contains(MemoryAccess::W) {
253 // It is assumed that a write memory access event is caused by a
254 // page table modification.
255 //
256 // The page table entry is marked as dirty in the page table monitor
257 // and a singlestep is performed to process the dirty entries.
258 self.ptm
259 .mark_dirty_entry(memory_access.pa, self.view, vmi.event().vcpu_id());
260
261 Ok(VmiEventResponse::singlestep().with_view(vmi.default_view()))
262 }
263 else if memory_access.access.contains(MemoryAccess::R) {
264 // When the guest tries to read from the memory, a fast-singlestep
265 // is performed over the instruction that tried to read the memory.
266 // This is done to allow the instruction to read the original memory
267 // content.
268 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
269 }
270 else {
271 panic!("Unhandled memory access: {memory_access:?}");
272 }
273 }Sourcepub fn fast_singlestep(view: View) -> VmiEventResponse<Arch>
Available on crate features utils and injector only.
pub fn fast_singlestep(view: View) -> VmiEventResponse<Arch>
utils and injector only.Creates a response to fast single-step one instruction in the specified view. Unlike regular singlestep, fast singlestep never generates a VMI event.
Examples found in repository?
examples/windows-breakpoint-manager.rs (line 268)
240 fn memory_access(
241 &mut self,
242 vmi: &VmiContext<WindowsOs<Driver>>,
243 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
244 let memory_access = vmi.event().reason().as_memory_access();
245
246 tracing::trace!(
247 pa = %memory_access.pa,
248 va = %memory_access.va,
249 access = %memory_access.access,
250 );
251
252 if memory_access.access.contains(MemoryAccess::W) {
253 // It is assumed that a write memory access event is caused by a
254 // page table modification.
255 //
256 // The page table entry is marked as dirty in the page table monitor
257 // and a singlestep is performed to process the dirty entries.
258 self.ptm
259 .mark_dirty_entry(memory_access.pa, self.view, vmi.event().vcpu_id());
260
261 Ok(VmiEventResponse::singlestep().with_view(vmi.default_view()))
262 }
263 else if memory_access.access.contains(MemoryAccess::R) {
264 // When the guest tries to read from the memory, a fast-singlestep
265 // is performed over the instruction that tried to read the memory.
266 // This is done to allow the instruction to read the original memory
267 // content.
268 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
269 }
270 else {
271 panic!("Unhandled memory access: {memory_access:?}");
272 }
273 }
274
275 #[tracing::instrument(skip_all, fields(pid, process))]
276 fn interrupt(
277 &mut self,
278 vmi: &VmiContext<WindowsOs<Driver>>,
279 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
280 let tag = match self.bpm.get_by_event(vmi.event(), ()) {
281 Some(breakpoints) => {
282 // Breakpoints can have multiple tags, but we have set only one
283 // tag for each breakpoint.
284 let first_breakpoint = breakpoints.into_iter().next().expect("breakpoint");
285 first_breakpoint.tag()
286 }
287 None => {
288 if BreakpointController::is_breakpoint(vmi, vmi.event())? {
289 // This breakpoint was not set by us. Reinject it.
290 tracing::warn!("Unknown breakpoint, reinjecting");
291 return Ok(VmiEventResponse::reinject_interrupt());
292 }
293 else {
294 // We have received a breakpoint event, but there is no
295 // breakpoint instruction at the current memory location.
296 // This can happen if the event was triggered by a breakpoint
297 // we just removed.
298 tracing::warn!("Ignoring old breakpoint event");
299 return Ok(VmiEventResponse::fast_singlestep(vmi.default_view()));
300 }
301 }
302 };
303
304 let process = vmi.os().current_process()?;
305 let process_id = process.id()?;
306 let process_name = process.name()?;
307 tracing::Span::current()
308 .record("pid", process_id.0)
309 .record("process", process_name);
310
311 match tag {
312 "NtCreateFile" => self.NtCreateFile(vmi)?,
313 "NtWriteFile" => self.NtWriteFile(vmi)?,
314 "PspInsertProcess" => self.PspInsertProcess(vmi)?,
315 "MmCleanProcessAddressSpace" => self.MmCleanProcessAddressSpace(vmi)?,
316 _ => panic!("Unhandled tag: {tag}"),
317 }
318
319 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
320 }Sourcepub fn emulate() -> VmiEventResponse<Arch>
Available on crate features utils and injector only.
pub fn emulate() -> VmiEventResponse<Arch>
utils and injector only.Creates a response to emulate the instruction.
Sourcepub fn with_view(self, view: View) -> VmiEventResponse<Arch>
Available on crate features utils and injector only.
pub fn with_view(self, view: View) -> VmiEventResponse<Arch>
utils and injector only.Sets a specific view for the response.
Examples found in repository?
examples/windows-breakpoint-manager.rs (line 261)
240 fn memory_access(
241 &mut self,
242 vmi: &VmiContext<WindowsOs<Driver>>,
243 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
244 let memory_access = vmi.event().reason().as_memory_access();
245
246 tracing::trace!(
247 pa = %memory_access.pa,
248 va = %memory_access.va,
249 access = %memory_access.access,
250 );
251
252 if memory_access.access.contains(MemoryAccess::W) {
253 // It is assumed that a write memory access event is caused by a
254 // page table modification.
255 //
256 // The page table entry is marked as dirty in the page table monitor
257 // and a singlestep is performed to process the dirty entries.
258 self.ptm
259 .mark_dirty_entry(memory_access.pa, self.view, vmi.event().vcpu_id());
260
261 Ok(VmiEventResponse::singlestep().with_view(vmi.default_view()))
262 }
263 else if memory_access.access.contains(MemoryAccess::R) {
264 // When the guest tries to read from the memory, a fast-singlestep
265 // is performed over the instruction that tried to read the memory.
266 // This is done to allow the instruction to read the original memory
267 // content.
268 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
269 }
270 else {
271 panic!("Unhandled memory access: {memory_access:?}");
272 }
273 }
274
275 #[tracing::instrument(skip_all, fields(pid, process))]
276 fn interrupt(
277 &mut self,
278 vmi: &VmiContext<WindowsOs<Driver>>,
279 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
280 let tag = match self.bpm.get_by_event(vmi.event(), ()) {
281 Some(breakpoints) => {
282 // Breakpoints can have multiple tags, but we have set only one
283 // tag for each breakpoint.
284 let first_breakpoint = breakpoints.into_iter().next().expect("breakpoint");
285 first_breakpoint.tag()
286 }
287 None => {
288 if BreakpointController::is_breakpoint(vmi, vmi.event())? {
289 // This breakpoint was not set by us. Reinject it.
290 tracing::warn!("Unknown breakpoint, reinjecting");
291 return Ok(VmiEventResponse::reinject_interrupt());
292 }
293 else {
294 // We have received a breakpoint event, but there is no
295 // breakpoint instruction at the current memory location.
296 // This can happen if the event was triggered by a breakpoint
297 // we just removed.
298 tracing::warn!("Ignoring old breakpoint event");
299 return Ok(VmiEventResponse::fast_singlestep(vmi.default_view()));
300 }
301 }
302 };
303
304 let process = vmi.os().current_process()?;
305 let process_id = process.id()?;
306 let process_name = process.name()?;
307 tracing::Span::current()
308 .record("pid", process_id.0)
309 .record("process", process_name);
310
311 match tag {
312 "NtCreateFile" => self.NtCreateFile(vmi)?,
313 "NtWriteFile" => self.NtWriteFile(vmi)?,
314 "PspInsertProcess" => self.PspInsertProcess(vmi)?,
315 "MmCleanProcessAddressSpace" => self.MmCleanProcessAddressSpace(vmi)?,
316 _ => panic!("Unhandled tag: {tag}"),
317 }
318
319 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
320 }
321
322 #[tracing::instrument(skip_all)]
323 fn singlestep(
324 &mut self,
325 vmi: &VmiContext<WindowsOs<Driver>>,
326 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
327 // Get the page table modifications by processing the dirty page table
328 // entries.
329 let ptm_events = self.ptm.process_dirty_entries(vmi, vmi.event().vcpu_id())?;
330
331 // Let the breakpoint controller handle the page table modifications.
332 self.bpm.handle_ptm_events(vmi, ptm_events)?;
333
334 // Disable singlestep and switch back to our view.
335 Ok(VmiEventResponse::default().with_view(self.view))
336 }Sourcepub fn with_registers(
self,
registers: <<Arch as Architecture>::Registers as Registers>::GpRegisters,
) -> VmiEventResponse<Arch>
Available on crate features utils and injector only.
pub fn with_registers( self, registers: <<Arch as Architecture>::Registers as Registers>::GpRegisters, ) -> VmiEventResponse<Arch>
utils and injector 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,
impl<Arch> Default for VmiEventResponse<Arch>where
Arch: Architecture,
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> UnsafeUnpin for VmiEventResponse<Arch>
impl<Arch> UnwindSafe for VmiEventResponse<Arch>
Blanket Implementations§
Source§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
Source§type ArchivedMetadata = ()
type ArchivedMetadata = ()
The archived version of the pointer metadata for this type.
Source§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Converts some archived metadata to the pointer metadata for itself.
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
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
Source§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
Returns the layout of the type.
Source§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
Source§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
Returns whether the given value has been niched. Read more
Source§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
Writes data to
out indicating that a T is niched.