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 292)
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(breakpoints) => {
283 // Breakpoints can have multiple tags, but we have set only one
284 // tag for each breakpoint.
285 let first_breakpoint = breakpoints.into_iter().next().expect("breakpoint");
286 first_breakpoint.tag()
287 }
288 None => {
289 if BreakpointController::is_breakpoint(vmi, vmi.event())? {
290 // This breakpoint was not set by us. Reinject it.
291 tracing::warn!("Unknown breakpoint, reinjecting");
292 return Ok(VmiEventResponse::reinject_interrupt());
293 }
294 else {
295 // We have received a breakpoint event, but there is no
296 // breakpoint instruction at the current memory location.
297 // This can happen if the event was triggered by a breakpoint
298 // we just removed.
299 tracing::warn!("Ignoring old breakpoint event");
300 return Ok(VmiEventResponse::fast_singlestep(vmi.default_view()));
301 }
302 }
303 };
304
305 let process = vmi.os().current_process()?;
306 let process_id = process.id()?;
307 let process_name = process.name()?;
308 tracing::Span::current()
309 .record("pid", process_id.0)
310 .record("process", process_name);
311
312 match tag {
313 "NtCreateFile" => self.NtCreateFile(vmi)?,
314 "NtWriteFile" => self.NtWriteFile(vmi)?,
315 "PspInsertProcess" => self.PspInsertProcess(vmi)?,
316 "MmCleanProcessAddressSpace" => self.MmCleanProcessAddressSpace(vmi)?,
317 _ => panic!("Unhandled tag: {tag}"),
318 }
319
320 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
321 }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(breakpoints) => {
283 // Breakpoints can have multiple tags, but we have set only one
284 // tag for each breakpoint.
285 let first_breakpoint = breakpoints.into_iter().next().expect("breakpoint");
286 first_breakpoint.tag()
287 }
288 None => {
289 if BreakpointController::is_breakpoint(vmi, vmi.event())? {
290 // This breakpoint was not set by us. Reinject it.
291 tracing::warn!("Unknown breakpoint, reinjecting");
292 return Ok(VmiEventResponse::reinject_interrupt());
293 }
294 else {
295 // We have received a breakpoint event, but there is no
296 // breakpoint instruction at the current memory location.
297 // This can happen if the event was triggered by a breakpoint
298 // we just removed.
299 tracing::warn!("Ignoring old breakpoint event");
300 return Ok(VmiEventResponse::fast_singlestep(vmi.default_view()));
301 }
302 }
303 };
304
305 let process = vmi.os().current_process()?;
306 let process_id = process.id()?;
307 let process_name = process.name()?;
308 tracing::Span::current()
309 .record("pid", process_id.0)
310 .record("process", process_name);
311
312 match tag {
313 "NtCreateFile" => self.NtCreateFile(vmi)?,
314 "NtWriteFile" => self.NtWriteFile(vmi)?,
315 "PspInsertProcess" => self.PspInsertProcess(vmi)?,
316 "MmCleanProcessAddressSpace" => self.MmCleanProcessAddressSpace(vmi)?,
317 _ => panic!("Unhandled tag: {tag}"),
318 }
319
320 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
321 }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(breakpoints) => {
283 // Breakpoints can have multiple tags, but we have set only one
284 // tag for each breakpoint.
285 let first_breakpoint = breakpoints.into_iter().next().expect("breakpoint");
286 first_breakpoint.tag()
287 }
288 None => {
289 if BreakpointController::is_breakpoint(vmi, vmi.event())? {
290 // This breakpoint was not set by us. Reinject it.
291 tracing::warn!("Unknown breakpoint, reinjecting");
292 return Ok(VmiEventResponse::reinject_interrupt());
293 }
294 else {
295 // We have received a breakpoint event, but there is no
296 // breakpoint instruction at the current memory location.
297 // This can happen if the event was triggered by a breakpoint
298 // we just removed.
299 tracing::warn!("Ignoring old breakpoint event");
300 return Ok(VmiEventResponse::fast_singlestep(vmi.default_view()));
301 }
302 }
303 };
304
305 let process = vmi.os().current_process()?;
306 let process_id = process.id()?;
307 let process_name = process.name()?;
308 tracing::Span::current()
309 .record("pid", process_id.0)
310 .record("process", process_name);
311
312 match tag {
313 "NtCreateFile" => self.NtCreateFile(vmi)?,
314 "NtWriteFile" => self.NtWriteFile(vmi)?,
315 "PspInsertProcess" => self.PspInsertProcess(vmi)?,
316 "MmCleanProcessAddressSpace" => self.MmCleanProcessAddressSpace(vmi)?,
317 _ => panic!("Unhandled tag: {tag}"),
318 }
319
320 Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
321 }
322
323 #[tracing::instrument(skip_all)]
324 fn singlestep(
325 &mut self,
326 vmi: &VmiContext<WindowsOs<Driver>>,
327 ) -> Result<VmiEventResponse<Amd64>, VmiError> {
328 // Get the page table modifications by processing the dirty page table
329 // entries.
330 let ptm_events = self.ptm.process_dirty_entries(vmi, vmi.event().vcpu_id())?;
331
332 // Let the breakpoint controller handle the page table modifications.
333 self.bpm.handle_ptm_events(vmi, ptm_events)?;
334
335 // Disable singlestep and switch back to our view.
336 Ok(VmiEventResponse::default().with_view(self.view))
337 }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 564)
524pub fn KfdIsLayerEmpty<Driver>(
525 vmi: &VmiContext<WindowsOs<Driver>>,
526) -> Result<Action<<WindowsOs<Driver> as VmiOs>::Architecture>, VmiError>
527where
528 Driver: VmiRead,
529 Driver::Architecture: ArchAdapter<Driver>,
530{
531 //
532 // BOOLEAN
533 // NTAPI
534 // KfdIsLayerEmpty (
535 // _In_ UINT16 layerId
536 // );
537 //
538
539 let layerId = FwpsLayer(vmi.os().function_argument(0)? as u16);
540
541 if !matches!(
542 layerId,
543 FwpsLayer::ALE_AUTH_CONNECT_V4
544 | FwpsLayer::ALE_AUTH_CONNECT_V6
545 | FwpsLayer::ALE_FLOW_ESTABLISHED_V4
546 | FwpsLayer::ALE_FLOW_ESTABLISHED_V6
547 ) {
548 tracing::trace!(?layerId, "passing through");
549 return Ok(Action::default());
550 }
551
552 tracing::trace!(?layerId, "overriding");
553
554 let return_address = vmi.return_address()?;
555 let stack_pointer = vmi.registers().stack_pointer();
556 let address_width = vmi.registers().address_width() as u64;
557
558 let mut registers = vmi.registers().gp_registers();
559 registers.set_result(0); // Return FALSE
560 registers.set_instruction_pointer(return_address.into());
561 registers.set_stack_pointer(stack_pointer + address_width);
562
563 Ok(Action::Response(
564 VmiEventResponse::default().with_registers(registers),
565 ))
566}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.