Struct VmiSession

Source
pub struct VmiSession<'a, Driver, Os = NoOS>
where Driver: VmiDriver, Os: VmiOs<Driver>,
{ /* private fields */ }
Expand description

A VMI session.

The session combines a VmiCore with an OS-specific VmiOs implementation to provide unified access to both low-level VMI operations and higher-level OS abstractions.

Implementations§

Source§

impl<'a, Driver, Os> VmiSession<'a, Driver, Os>
where Driver: VmiDriver, Os: VmiOs<Driver>,

Source

pub fn new(core: &'a VmiCore<Driver>, os: &'a Os) -> Self

Creates a new VMI session.

Source

pub fn with_registers( &'a self, registers: &'a <Driver::Architecture as Architecture>::Registers, ) -> VmiState<'a, Driver, Os>

Creates a new VMI state with the specified registers.

Source

pub fn without_os(&self) -> VmiSession<'a, Driver, NoOS>

Creates a new VMI session without an OS-specific implementation.

Source

pub fn core(&self) -> &'a VmiCore<Driver>

Returns the VMI core.

Source

pub fn underlying_os(&self) -> &'a Os

Returns the underlying OS-specific implementation.

Source

pub fn wait_for_event( &self, timeout: Duration, handler: &mut impl VmiHandler<Driver, Os>, ) -> Result<(), VmiError>

Waits for an event to occur and processes it with the provided handler.

This method blocks until an event occurs or the specified timeout is reached. When an event occurs, it is passed to the provided callback function for processing.

Source

pub fn handle<Handler>( &self, handler_factory: impl FnOnce(&VmiSession<'_, Driver, Os>) -> Result<Handler, VmiError>, ) -> Result<Option<Handler::Output>, VmiError>
where Handler: VmiHandler<Driver, Os>,

Enters the main event handling loop that processes VMI events until finished.

Source

pub fn handle_with_timeout<Handler>( &self, timeout: Duration, handler_factory: impl FnOnce(&VmiSession<'_, Driver, Os>) -> Result<Handler, VmiError>, ) -> Result<Option<Handler::Output>, VmiError>
where Handler: VmiHandler<Driver, Os>,

Enters the main event handling loop that processes VMI events until finished, with a timeout for each event.

Methods from Deref<Target = VmiCore<Driver>>§

Source

pub fn flush_gfn_cache_entry(&self, gfn: Gfn) -> Option<VmiMappedPage>

Removes a specific entry from the GFN cache.

Returns the removed entry if it was present. This is useful for invalidating cached data that might have become stale.

Source

pub fn flush_gfn_cache(&self)

Clears the entire GFN cache.

Source

pub fn flush_v2p_cache_entry(&self, ctx: AccessContext) -> Option<Pa>

Removes a specific entry from the V2P cache.

Returns the removed entry if it was present. This can be used to invalidate cached translations that may have become stale due to changes in the guest’s memory mapping.

Source

pub fn flush_v2p_cache(&self)

Clears the entire V2P cache.

This method is crucial for maintaining consistency when handling events. The guest operating system can modify page tables or other structures related to address translation between events. Using stale translations can lead to incorrect memory access and unexpected behavior. It is recommended to call this method at the beginning of each VmiHandler::handle_event loop to ensure that you are working with the most up-to-date address mappings.

Source

pub fn read_string_length_limit(&self) -> Option<usize>

Returns the current limit on the length of strings read by the read_string methods.

Source

pub fn set_read_string_length_limit(&self, limit: usize)

Sets a limit on the length of strings read by the read_string methods.

This method allows you to set a maximum length (in bytes) for strings read from the virtual machine’s memory. When set, string reading operations will truncate their results to this limit. This can be useful for preventing excessively long string reads, which might impact performance or consume too much memory.

If the limit is reached during a string read operation, the resulting string will be truncated to the specified length.

To remove the limit, call this method with None.

Source

pub fn driver(&self) -> &Driver

Returns the driver used by this VmiCore instance.

Source

pub fn info(&self) -> Result<VmiInfo, VmiError>

Retrieves information about the virtual machine.

Source

pub fn pause(&self) -> Result<(), VmiError>

Pauses the virtual machine.

Source

pub fn resume(&self) -> Result<(), VmiError>

Resumes the virtual machine.

Source

pub fn pause_guard(&self) -> Result<VmiPauseGuard<'_, Driver>, VmiError>

Pauses the virtual machine and returns a guard that will resume it when dropped.

Source

pub fn registers( &self, vcpu: VcpuId, ) -> Result<<Driver::Architecture as Architecture>::Registers, VmiError>

Retrieves the current state of CPU registers for a specified virtual CPU.

This method allows you to access the current values of CPU registers, which is crucial for understanding the state of the virtual machine at a given point in time.

§Notes

The exact structure and content of the returned registers depend on the specific architecture of the VM being introspected. Refer to the documentation of your Architecture implementation for details on how to interpret the register values.

Source

pub fn set_registers( &self, vcpu: VcpuId, registers: <Driver::Architecture as Architecture>::Registers, ) -> Result<(), VmiError>

Sets the registers of a virtual CPU.

Source

pub fn memory_access( &self, gfn: Gfn, view: View, ) -> Result<MemoryAccess, VmiError>

Retrieves the memory access permissions for a specific guest frame number (GFN).

The returned MemoryAccess indicates the current read, write, and execute permissions for the specified memory page in the given view.

Source

pub fn set_memory_access( &self, gfn: Gfn, view: View, access: MemoryAccess, ) -> Result<(), VmiError>

Sets the memory access permissions for a specific guest frame number (GFN).

This method allows you to modify the read, write, and execute permissions for a given memory page in the specified view.

Source

pub fn set_memory_access_with_options( &self, gfn: Gfn, view: View, access: MemoryAccess, options: MemoryAccessOptions, ) -> Result<(), VmiError>

Sets the memory access permissions for a specific guest frame number (GFN) with additional options.

In addition to the basic read, write, and execute permissions, this method allows you to specify additional options for the memory access.

Source

pub fn allocate_next_available_gfn(&self) -> Result<Gfn, VmiError>

Allocates the next available guest frame number (GFN).

This method finds and allocates the next free GFN after the current maximum GFN. It’s useful when you need to allocate new memory pages for the VM.

Source

pub fn allocate_gfn(&self, gfn: Gfn) -> Result<(), VmiError>

Allocates a specific guest frame number (GFN).

This method allows you to allocate a particular GFN. It’s useful when you need to allocate a specific memory page for the VM.

Source

pub fn free_gfn(&self, gfn: Gfn) -> Result<(), VmiError>

Frees a previously allocated guest frame number (GFN).

This method deallocates a GFN that was previously allocated. It’s important to free GFNs when they’re no longer needed to prevent memory leaks in the VM.

Source

pub fn default_view(&self) -> View

Returns the default view for the virtual machine.

The default view typically represents the normal, unmodified state of the VM’s memory.

Source

pub fn create_view( &self, default_access: MemoryAccess, ) -> Result<View, VmiError>

Creates a new view with the specified default access permissions.

Views allow for creating different perspectives of the VM’s memory, which can be useful for analysis or isolation purposes. The default access permissions apply to memory pages not explicitly modified within this view.

Source

pub fn destroy_view(&self, view: View) -> Result<(), VmiError>

Destroys a previously created view.

This method removes a view and frees associated resources. It should be called when a view is no longer needed to prevent resource leaks.

Source

pub fn switch_to_view(&self, view: View) -> Result<(), VmiError>

Switches to a different view for all virtual CPUs.

This method changes the current active view for all vCPUs, affecting subsequent memory operations across the entire VM. It allows for quick transitions between different memory perspectives globally.

Note the difference between this method and VmiEventResponse::set_view():

  • switch_to_view() changes the view for all vCPUs immediately.
  • VmiEventResponse::set_view() sets the view only for the specific vCPU that received the event, and the change is applied when the event handler returns.

Use switch_to_view() for global view changes, and VmiEventResponse::set_view() for targeted, event-specific view modifications on individual vCPUs.

Source

pub fn change_view_gfn( &self, view: View, old_gfn: Gfn, new_gfn: Gfn, ) -> Result<(), VmiError>

Changes the mapping of a guest frame number (GFN) in a specific view.

This method allows for remapping a GFN to a different physical frame within a view, enabling fine-grained control over memory layout in different views.

A notable use case for this method is implementing “stealth hooks”:

  1. Create a new GFN and copy the contents of the original page to it.
  2. Modify the new page by installing a breakpoint (e.g., 0xcc on AMD64) at a strategic location.
  3. Use this method to change the mapping of the original GFN to the new one.
  4. Set the memory access of the new GFN to non-readable.

When a read access occurs:

  • The handler should enable single-stepping.
  • Switch to an unmodified view (e.g., default_view) to execute the read instruction, which will read the original non-breakpoint byte.
  • Re-enable single-stepping afterwards.

This technique allows for transparent breakpoints that are difficult to detect by the guest OS or applications.

Source

pub fn reset_view_gfn(&self, view: View, gfn: Gfn) -> Result<(), VmiError>

Resets the mapping of a guest frame number (GFN) in a specific view to its original state.

This method reverts any custom mapping for the specified GFN in the given view, restoring it to the default mapping.

Source

pub fn monitor_enable( &self, option: <Driver::Architecture as Architecture>::EventMonitor, ) -> Result<(), VmiError>

Enables monitoring of specific events.

This method allows you to enable monitoring of specific events, such as control register writes, interrupts, or single-step execution. Monitoring events can be useful for tracking specific guest behavior or for implementing custom analysis tools.

The type of event to monitor is defined by the architecture-specific Architecture::EventMonitor type.

When an event occurs, it will be passed to the event callback function for processing.

Source

pub fn monitor_disable( &self, option: <Driver::Architecture as Architecture>::EventMonitor, ) -> Result<(), VmiError>

Disables monitoring of specific events.

This method allows you to disable monitoring of specific events that were previously enabled. It can be used to stop tracking certain hardware events or to reduce the overhead of event processing.

The type of event to disable is defined by the architecture-specific Architecture::EventMonitor type.

Source

pub fn inject_interrupt( &self, vcpu: VcpuId, interrupt: <Driver::Architecture as Architecture>::Interrupt, ) -> Result<(), VmiError>

Injects an interrupt into a specific virtual CPU.

This method allows for the injection of architecture-specific interrupts into a given vCPU. It can be used to simulate hardware events or to manipulate the guest’s execution flow for analysis purposes.

The type of interrupt and its parameters are defined by the architecture-specific Architecture::Interrupt type.

Source

pub fn events_pending(&self) -> usize

Returns the number of pending events.

This method provides a count of events that have occurred but have not yet been processed.

Source

pub fn event_processing_overhead(&self) -> Duration

Returns the time spent processing events by the driver.

This method provides a measure of the overhead introduced by event processing. It can be useful for performance tuning and understanding the impact of VMI operations on overall system performance.

Source

pub fn wait_for_event( &self, timeout: Duration, handler: impl FnMut(&VmiEvent<Driver::Architecture>) -> VmiEventResponse<Driver::Architecture>, ) -> Result<(), VmiError>

Waits for an event to occur and processes it with the provided handler.

This method blocks until an event occurs or the specified timeout is reached. When an event occurs, it is passed to the provided callback function for processing.

Source

pub fn reset_state(&self) -> Result<(), VmiError>

Resets the state of the VMI system.

This method clears all event monitors, caches, and any other stateful data maintained by the VMI system. It’s useful for bringing the VMI system back to a known clean state, which can be necessary when switching between different analysis tasks or recovering from error conditions.

Source

pub fn read( &self, ctx: impl Into<AccessContext>, buffer: &mut [u8], ) -> Result<(), VmiError>

Reads memory from the virtual machine.

Source

pub fn write( &self, ctx: impl Into<AccessContext>, buffer: &[u8], ) -> Result<(), VmiError>

Writes memory to the virtual machine.

Source

pub fn read_u8(&self, ctx: impl Into<AccessContext>) -> Result<u8, VmiError>

Reads a single byte from the virtual machine.

Source

pub fn read_u16(&self, ctx: impl Into<AccessContext>) -> Result<u16, VmiError>

Reads a 16-bit unsigned integer from the virtual machine.

Source

pub fn read_u32(&self, ctx: impl Into<AccessContext>) -> Result<u32, VmiError>

Reads a 32-bit unsigned integer from the virtual machine.

Source

pub fn read_u64(&self, ctx: impl Into<AccessContext>) -> Result<u64, VmiError>

Reads a 64-bit unsigned integer from the virtual machine.

Source

pub fn read_uint( &self, ctx: impl Into<AccessContext>, size: usize, ) -> Result<u64, VmiError>

Reads an unsigned integer of the specified size from the virtual machine.

This method reads an unsigned integer of the specified size (in bytes) from the virtual machine. Note that the size must be 1, 2, 4, or 8.

The result is returned as a u64 to accommodate the widest possible integer size.

Source

pub fn read_field( &self, ctx: impl Into<AccessContext>, field: &Field, ) -> Result<u64, VmiError>

Reads a field of a structure from the virtual machine.

This method reads a field from the virtual machine. The field is defined by the provided Field structure, which specifies the offset and size of the field within the memory region.

The result is returned as a u64 to accommodate the widest possible integer size.

Source

pub fn read_address( &self, ctx: impl Into<AccessContext>, address_width: usize, ) -> Result<u64, VmiError>

Reads an address-sized unsigned integer from the virtual machine.

This method reads an address of the specified width (in bytes) from the given access context. It’s useful when dealing with architectures that can operate in different address modes.

Source

pub fn read_address32( &self, ctx: impl Into<AccessContext>, ) -> Result<u64, VmiError>

Reads a 32-bit address from the virtual machine.

Source

pub fn read_address64( &self, ctx: impl Into<AccessContext>, ) -> Result<u64, VmiError>

Reads a 64-bit address from the virtual machine.

Source

pub fn read_va( &self, ctx: impl Into<AccessContext>, address_width: usize, ) -> Result<Va, VmiError>

Reads a virtual address from the virtual machine.

Source

pub fn read_va32(&self, ctx: impl Into<AccessContext>) -> Result<Va, VmiError>

Reads a 32-bit virtual address from the virtual machine.

Source

pub fn read_va64(&self, ctx: impl Into<AccessContext>) -> Result<Va, VmiError>

Reads a 64-bit virtual address from the virtual machine.

Source

pub fn read_string_bytes_limited( &self, ctx: impl Into<AccessContext>, limit: usize, ) -> Result<Vec<u8>, VmiError>

Reads a null-terminated string of bytes from the virtual machine with a specified limit.

Source

pub fn read_string_bytes( &self, ctx: impl Into<AccessContext>, ) -> Result<Vec<u8>, VmiError>

Reads a null-terminated string of bytes from the virtual machine.

Source

pub fn read_wstring_bytes_limited( &self, ctx: impl Into<AccessContext>, limit: usize, ) -> Result<Vec<u16>, VmiError>

Reads a null-terminated wide string (UTF-16) from the virtual machine with a specified limit.

Source

pub fn read_wstring_bytes( &self, ctx: impl Into<AccessContext>, ) -> Result<Vec<u16>, VmiError>

Reads a null-terminated wide string (UTF-16) from the virtual machine.

Source

pub fn read_string_limited( &self, ctx: impl Into<AccessContext>, limit: usize, ) -> Result<String, VmiError>

Reads a null-terminated string from the virtual machine with a specified limit.

Source

pub fn read_string( &self, ctx: impl Into<AccessContext>, ) -> Result<String, VmiError>

Reads a null-terminated string from the virtual machine.

Source

pub fn read_wstring_limited( &self, ctx: impl Into<AccessContext>, limit: usize, ) -> Result<String, VmiError>

Reads a null-terminated wide string (UTF-16) from the virtual machine with a specified limit.

Source

pub fn read_wstring( &self, ctx: impl Into<AccessContext>, ) -> Result<String, VmiError>

Reads a null-terminated wide string (UTF-16) from the virtual machine.

Source

pub fn read_struct<T>( &self, ctx: impl Into<AccessContext>, ) -> Result<T, VmiError>
where T: FromBytes + IntoBytes,

Reads a struct from the virtual machine.

Source

pub fn write_u8( &self, ctx: impl Into<AccessContext>, value: u8, ) -> Result<(), VmiError>

Writes a single byte to the virtual machine.

Source

pub fn write_u16( &self, ctx: impl Into<AccessContext>, value: u16, ) -> Result<(), VmiError>

Writes a 16-bit unsigned integer to the virtual machine.

Source

pub fn write_u32( &self, ctx: impl Into<AccessContext>, value: u32, ) -> Result<(), VmiError>

Writes a 32-bit unsigned integer to the virtual machine.

Source

pub fn write_u64( &self, ctx: impl Into<AccessContext>, value: u64, ) -> Result<(), VmiError>

Writes a 64-bit unsigned integer to the virtual machine.

Source

pub fn write_struct<T>( &self, ctx: impl Into<AccessContext>, value: T, ) -> Result<(), VmiError>
where T: IntoBytes + Immutable,

Writes a struct to the virtual machine.

Source

pub fn translate_address( &self, ctx: impl Into<AddressContext>, ) -> Result<Pa, VmiError>

Translates a virtual address to a physical address.

Source

pub fn translate_access_context( &self, ctx: AccessContext, ) -> Result<Pa, VmiError>

Translates an access context to a physical address.

Source

pub fn read_page(&self, gfn: Gfn) -> Result<VmiMappedPage, VmiError>

Reads a page of memory from the virtual machine.

Trait Implementations§

Source§

impl<Driver, Os> Clone for VmiSession<'_, Driver, Os>
where Driver: VmiDriver, Os: VmiOs<Driver>,

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<Driver, Os> Deref for VmiSession<'_, Driver, Os>
where Driver: VmiDriver, Os: VmiOs<Driver>,

Source§

type Target = VmiCore<Driver>

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Self::Target

Dereferences the value.
Source§

impl<Driver, Os> Copy for VmiSession<'_, Driver, Os>
where Driver: VmiDriver, Os: VmiOs<Driver>,

Auto Trait Implementations§

§

impl<'a, Driver, Os> Freeze for VmiSession<'a, Driver, Os>

§

impl<'a, Driver, Os = NoOS> !RefUnwindSafe for VmiSession<'a, Driver, Os>

§

impl<'a, Driver, Os = NoOS> !Send for VmiSession<'a, Driver, Os>

§

impl<'a, Driver, Os = NoOS> !Sync for VmiSession<'a, Driver, Os>

§

impl<'a, Driver, Os> Unpin for VmiSession<'a, Driver, Os>

§

impl<'a, Driver, Os = NoOS> !UnwindSafe for VmiSession<'a, Driver, Os>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more