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 injector and utils only.
pub fn deny() -> VmiEventResponse<Arch>
injector and utils only.Creates a response to deny the event.
Sourcepub fn reinject_interrupt() -> VmiEventResponse<Arch>
Available on crate features injector and utils only.
pub fn reinject_interrupt() -> VmiEventResponse<Arch>
injector and utils only.Creates a response to reinject an interrupt.
Examples found in repository?
examples/windows-breakpoint-manager.rs (line 287)
277 fn interrupt(
278 &mut self,
279 vmi: &VmiContext<WindowsOs<Driver>>,
280 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
281 let tag = match self.bpm.get_by_event(vmi.event(), ()) {
282 Some(breakpoint) => breakpoint.tag(),
283 None => {
284 if BreakpointController::is_breakpoint(vmi, vmi.event())? {
285 // This breakpoint was not set by us. Reinject it.
286 tracing::warn!("Unknown breakpoint, reinjecting");
287 return Ok(VmiEventResponse::reinject_interrupt());
288 }
289 else {
290 // We have received a breakpoint event, but there is no
291 // breakpoint instruction at the current memory location.
292 // This can happen if the event was triggered by a breakpoint
293 // we just removed.
294 tracing::warn!("Ignoring old breakpoint event");
295 return Ok(VmiEventResponse::fast_singlestep(vmi.default_view()));
296 }
297 }
298 };
299
300 let process = vmi.os().current_process()?;
301 let process_id = process.id()?;
302 let process_name = process.name()?;
303 tracing::Span::current()
304 .record("pid", process_id.0)
305 .record("process", process_name);
306
307 match tag {
308 "NtCreateFile" => self.NtCreateFile(vmi)?,
309 "NtWriteFile" => self.NtWriteFile(vmi)?,
310 "PspInsertProcess" => self.PspInsertProcess(vmi)?,
311 "MmCleanProcessAddressSpace" => self.MmCleanProcessAddressSpace(vmi)?,
312 _ => panic!("Unhandled tag: {tag}"),
313 }
314
315 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
316 }Sourcepub fn singlestep() -> VmiEventResponse<Arch>
Available on crate features injector and utils only.
pub fn singlestep() -> VmiEventResponse<Arch>
injector and utils only.Creates a response to single-step one instruction.
Examples found in repository?
examples/windows-breakpoint-manager.rs (line 262)
241 fn memory_access(
242 &mut self,
243 vmi: &VmiContext<WindowsOs<Driver>>,
244 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
245 let memory_access = vmi.event().reason().as_memory_access();
246
247 tracing::trace!(
248 pa = %memory_access.pa,
249 va = %memory_access.va,
250 access = %memory_access.access,
251 );
252
253 if memory_access.access.contains(MemoryAccess::W) {
254 // It is assumed that a write memory access event is caused by a
255 // page table modification.
256 //
257 // The page table entry is marked as dirty in the page table monitor
258 // and a singlestep is performed to process the dirty entries.
259 self.ptm
260 .mark_dirty_entry(memory_access.pa, self.view, vmi.event().vcpu_id());
261
262 Ok(VmiEventResponse::singlestep().with_view(vmi.default_view()))
263 }
264 else if memory_access.access.contains(MemoryAccess::R) {
265 // When the guest tries to read from the memory, a fast-singlestep
266 // is performed over the instruction that tried to read the memory.
267 // This is done to allow the instruction to read the original memory
268 // content.
269 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
270 }
271 else {
272 panic!("Unhandled memory access: {memory_access:?}");
273 }
274 }Sourcepub fn fast_singlestep(view: View) -> VmiEventResponse<Arch>
Available on crate features injector and utils only.
pub fn fast_singlestep(view: View) -> VmiEventResponse<Arch>
injector and utils 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 269)
241 fn memory_access(
242 &mut self,
243 vmi: &VmiContext<WindowsOs<Driver>>,
244 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
245 let memory_access = vmi.event().reason().as_memory_access();
246
247 tracing::trace!(
248 pa = %memory_access.pa,
249 va = %memory_access.va,
250 access = %memory_access.access,
251 );
252
253 if memory_access.access.contains(MemoryAccess::W) {
254 // It is assumed that a write memory access event is caused by a
255 // page table modification.
256 //
257 // The page table entry is marked as dirty in the page table monitor
258 // and a singlestep is performed to process the dirty entries.
259 self.ptm
260 .mark_dirty_entry(memory_access.pa, self.view, vmi.event().vcpu_id());
261
262 Ok(VmiEventResponse::singlestep().with_view(vmi.default_view()))
263 }
264 else if memory_access.access.contains(MemoryAccess::R) {
265 // When the guest tries to read from the memory, a fast-singlestep
266 // is performed over the instruction that tried to read the memory.
267 // This is done to allow the instruction to read the original memory
268 // content.
269 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
270 }
271 else {
272 panic!("Unhandled memory access: {memory_access:?}");
273 }
274 }
275
276 #[tracing::instrument(skip_all, fields(pid, process))]
277 fn interrupt(
278 &mut self,
279 vmi: &VmiContext<WindowsOs<Driver>>,
280 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
281 let tag = match self.bpm.get_by_event(vmi.event(), ()) {
282 Some(breakpoint) => breakpoint.tag(),
283 None => {
284 if BreakpointController::is_breakpoint(vmi, vmi.event())? {
285 // This breakpoint was not set by us. Reinject it.
286 tracing::warn!("Unknown breakpoint, reinjecting");
287 return Ok(VmiEventResponse::reinject_interrupt());
288 }
289 else {
290 // We have received a breakpoint event, but there is no
291 // breakpoint instruction at the current memory location.
292 // This can happen if the event was triggered by a breakpoint
293 // we just removed.
294 tracing::warn!("Ignoring old breakpoint event");
295 return Ok(VmiEventResponse::fast_singlestep(vmi.default_view()));
296 }
297 }
298 };
299
300 let process = vmi.os().current_process()?;
301 let process_id = process.id()?;
302 let process_name = process.name()?;
303 tracing::Span::current()
304 .record("pid", process_id.0)
305 .record("process", process_name);
306
307 match tag {
308 "NtCreateFile" => self.NtCreateFile(vmi)?,
309 "NtWriteFile" => self.NtWriteFile(vmi)?,
310 "PspInsertProcess" => self.PspInsertProcess(vmi)?,
311 "MmCleanProcessAddressSpace" => self.MmCleanProcessAddressSpace(vmi)?,
312 _ => panic!("Unhandled tag: {tag}"),
313 }
314
315 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
316 }Sourcepub fn emulate() -> VmiEventResponse<Arch>
Available on crate features injector and utils only.
pub fn emulate() -> VmiEventResponse<Arch>
injector and utils only.Creates a response to emulate the instruction.
Sourcepub fn with_view(self, view: View) -> VmiEventResponse<Arch>
Available on crate features injector and utils only.
pub fn with_view(self, view: View) -> VmiEventResponse<Arch>
injector and utils only.Sets a specific view for the response.
Examples found in repository?
examples/windows-breakpoint-manager.rs (line 262)
241 fn memory_access(
242 &mut self,
243 vmi: &VmiContext<WindowsOs<Driver>>,
244 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
245 let memory_access = vmi.event().reason().as_memory_access();
246
247 tracing::trace!(
248 pa = %memory_access.pa,
249 va = %memory_access.va,
250 access = %memory_access.access,
251 );
252
253 if memory_access.access.contains(MemoryAccess::W) {
254 // It is assumed that a write memory access event is caused by a
255 // page table modification.
256 //
257 // The page table entry is marked as dirty in the page table monitor
258 // and a singlestep is performed to process the dirty entries.
259 self.ptm
260 .mark_dirty_entry(memory_access.pa, self.view, vmi.event().vcpu_id());
261
262 Ok(VmiEventResponse::singlestep().with_view(vmi.default_view()))
263 }
264 else if memory_access.access.contains(MemoryAccess::R) {
265 // When the guest tries to read from the memory, a fast-singlestep
266 // is performed over the instruction that tried to read the memory.
267 // This is done to allow the instruction to read the original memory
268 // content.
269 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
270 }
271 else {
272 panic!("Unhandled memory access: {memory_access:?}");
273 }
274 }
275
276 #[tracing::instrument(skip_all, fields(pid, process))]
277 fn interrupt(
278 &mut self,
279 vmi: &VmiContext<WindowsOs<Driver>>,
280 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
281 let tag = match self.bpm.get_by_event(vmi.event(), ()) {
282 Some(breakpoint) => breakpoint.tag(),
283 None => {
284 if BreakpointController::is_breakpoint(vmi, vmi.event())? {
285 // This breakpoint was not set by us. Reinject it.
286 tracing::warn!("Unknown breakpoint, reinjecting");
287 return Ok(VmiEventResponse::reinject_interrupt());
288 }
289 else {
290 // We have received a breakpoint event, but there is no
291 // breakpoint instruction at the current memory location.
292 // This can happen if the event was triggered by a breakpoint
293 // we just removed.
294 tracing::warn!("Ignoring old breakpoint event");
295 return Ok(VmiEventResponse::fast_singlestep(vmi.default_view()));
296 }
297 }
298 };
299
300 let process = vmi.os().current_process()?;
301 let process_id = process.id()?;
302 let process_name = process.name()?;
303 tracing::Span::current()
304 .record("pid", process_id.0)
305 .record("process", process_name);
306
307 match tag {
308 "NtCreateFile" => self.NtCreateFile(vmi)?,
309 "NtWriteFile" => self.NtWriteFile(vmi)?,
310 "PspInsertProcess" => self.PspInsertProcess(vmi)?,
311 "MmCleanProcessAddressSpace" => self.MmCleanProcessAddressSpace(vmi)?,
312 _ => panic!("Unhandled tag: {tag}"),
313 }
314
315 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
316 }
317
318 #[tracing::instrument(skip_all)]
319 fn singlestep(
320 &mut self,
321 vmi: &VmiContext<WindowsOs<Driver>>,
322 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
323 // Get the page table modifications by processing the dirty page table
324 // entries.
325 let ptm_events = self.ptm.process_dirty_entries(vmi, vmi.event().vcpu_id())?;
326
327 // Let the breakpoint controller handle the page table modifications.
328 self.bpm.handle_ptm_events(vmi, ptm_events)?;
329
330 // Disable singlestep and switch back to our view.
331 Ok(VmiEventResponse::default().with_view(self.view))
332 }Sourcepub fn with_registers(
self,
registers: <<Arch as Architecture>::Registers as Registers>::GpRegisters,
) -> VmiEventResponse<Arch>
Available on crate features injector and utils only.
pub fn with_registers( self, registers: <<Arch as Architecture>::Registers as Registers>::GpRegisters, ) -> VmiEventResponse<Arch>
injector and utils only.Sets specific CPU registers for the response.
Examples found in repository?
examples/windows-reactor/netio.rs (line 556)
523pub fn KfdIsLayerEmpty<Driver>(
524 vmi: &VmiContext<WindowsOs<Driver>>,
525) -> Result<Action<<WindowsOs<Driver> as VmiOs>::Architecture>, VmiError>
526where
527 Driver: VmiRead,
528 Driver::Architecture: ArchAdapter<Driver>,
529{
530 //
531 // BOOLEAN
532 // NTAPI
533 // KfdIsLayerEmpty (
534 // _In_ UINT16 layerId
535 // );
536 //
537
538 let layerId = FwpsLayer(vmi.os().function_argument(0)? as u16);
539
540 if !matches!(
541 layerId,
542 FwpsLayer::ALE_AUTH_CONNECT_V4
543 | FwpsLayer::ALE_AUTH_CONNECT_V6
544 | FwpsLayer::ALE_FLOW_ESTABLISHED_V4
545 | FwpsLayer::ALE_FLOW_ESTABLISHED_V6
546 ) {
547 tracing::trace!(?layerId, "passing through");
548 return Ok(Action::default());
549 }
550
551 tracing::trace!(?layerId, "overriding");
552
553 let registers = vmi.return_from_function(0)?; // Return FALSE
554
555 Ok(Action::Response(
556 VmiEventResponse::default().with_registers(registers),
557 ))
558}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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
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.