Skip to main content

vmi_os_windows/arch/
mod.rs

1mod amd64;
2mod context;
3
4use vmi_core::{AccessContext, Architecture, Va, VmiCore, VmiError, VmiState, driver::VmiRead};
5
6pub use self::{
7    amd64::{WindowsExceptionVector, WindowsInterrupt, WindowsPageTableEntry},
8    context::{
9        CONTEXT_AMD64, CONTEXT_X86, FLOATING_SAVE_AREA, KDESCRIPTOR_AMD64, KDESCRIPTOR_X86,
10        KSPECIAL_REGISTERS_AMD64, KSPECIAL_REGISTERS_X86, M128A, MAXIMUM_SUPPORTED_EXTENSION,
11        SIZE_OF_80387_REGISTERS, WindowsContext, WindowsRegistersAdapter, WindowsSpecialRegisters,
12        XSAVE_FORMAT,
13    },
14};
15use crate::{WindowsKernelInformation, WindowsOs, WindowsOsExt};
16
17/// Architecture-specific Windows functionality.
18pub trait ArchAdapter<Driver>: Architecture
19where
20    Driver: VmiRead<Architecture = Self>,
21{
22    /// Reads a syscall argument by index from the current register state.
23    ///
24    /// Index 0 is the first argument.
25    ///
26    /// # Architecture-specific
27    ///
28    /// - **AMD64**: Arguments 0-3 come from registers (`R10`, `RDX`, `R8`,
29    ///   `R9`); subsequent arguments are read from the stack.
30    fn syscall_argument(vmi: VmiState<WindowsOs<Driver>>, index: u64) -> Result<u64, VmiError>;
31
32    /// Reads a function-call argument by index from the current register state.
33    ///
34    /// Unlike [`syscall_argument`](Self::syscall_argument), this follows the
35    /// standard calling convention.
36    ///
37    /// # Architecture-specific
38    ///
39    /// - **AMD64**: Microsoft x64 calling convention (`RCX`, `RDX`, `R8`,
40    ///   `R9`) in long mode, stdcall (stack-based) in compatibility mode.
41    fn function_argument(vmi: VmiState<WindowsOs<Driver>>, index: u64) -> Result<u64, VmiError>;
42
43    /// Reads the return value of the most recent function call.
44    ///
45    /// # Architecture-specific
46    ///
47    /// - **AMD64**: `RAX`
48    fn function_return_value(vmi: VmiState<WindowsOs<Driver>>) -> Result<u64, VmiError>;
49
50    /// Locates the Windows kernel image by scanning backward from the
51    /// syscall entry point.
52    ///
53    /// Returns the kernel's base address, OS version, and CodeView debug
54    /// information if found.
55    ///
56    /// # Architecture-specific
57    ///
58    /// - **AMD64**: Scans backward from `MSR_LSTAR` (up to 32 MB)
59    fn find_kernel(
60        vmi: &VmiCore<Driver>,
61        registers: &<Driver::Architecture as Architecture>::Registers,
62    ) -> Result<Option<WindowsKernelInformation>, VmiError>;
63
64    /// Returns the kernel image base address, caching the result for
65    /// subsequent calls.
66    ///
67    /// # Architecture-specific
68    ///
69    /// - **AMD64**: `MSR_LSTAR - KiSystemCall64`
70    fn kernel_image_base(vmi: VmiState<WindowsOs<Driver>>) -> Result<Va, VmiError>;
71
72    /// Checks whether a virtual address maps to a page that is either
73    /// present or in the Windows transition state (soft fault, still
74    /// resident in physical memory).
75    fn is_page_present_or_transition(
76        vmi: VmiState<WindowsOs<Driver>>,
77        address: Va,
78    ) -> Result<bool, VmiError>;
79
80    /// Returns the virtual address of the Kernel Processor Control Region
81    /// (KPCR) for the current CPU.
82    fn current_kpcr(vmi: VmiState<WindowsOs<Driver>>) -> Va;
83}
84
85/// Pointer-width-dependent operations for reading Windows structures.
86///
87/// Windows structures contain pointer-sized fields (`PVOID`, `UNICODE_STRING`,
88/// `LIST_ENTRY`, ...) whose layout differs between 32-bit and 64-bit processes.
89/// This trait abstracts over the pointer width so that structure accessors can
90/// be generic over both layouts.
91pub trait StructLayout {
92    /// The address width (i.e. pointer size) in bytes.
93    const ADDRESS_WIDTH: u64;
94
95    /// Reads a pointer-sized virtual address from guest memory.
96    fn read_va<Driver>(
97        vmi: VmiState<WindowsOs<Driver>>,
98        ctx: impl Into<AccessContext>,
99    ) -> Result<Va, VmiError>
100    where
101        Driver: VmiRead,
102        Driver::Architecture: ArchAdapter<Driver>;
103
104    /// Reads a `UNICODE_STRING` from guest memory.
105    fn read_unicode_string<Driver>(
106        vmi: VmiState<WindowsOs<Driver>>,
107        ctx: impl Into<AccessContext>,
108    ) -> Result<String, VmiError>
109    where
110        Driver: VmiRead,
111        Driver::Architecture: ArchAdapter<Driver>;
112}
113
114/// 32-bit structure layout.
115pub struct StructLayout32;
116
117impl StructLayout for StructLayout32 {
118    const ADDRESS_WIDTH: u64 = 4;
119
120    fn read_va<Driver>(
121        vmi: VmiState<WindowsOs<Driver>>,
122        ctx: impl Into<AccessContext>,
123    ) -> Result<Va, VmiError>
124    where
125        Driver: VmiRead,
126        Driver::Architecture: ArchAdapter<Driver>,
127    {
128        vmi.core().read_va32(ctx)
129    }
130
131    fn read_unicode_string<Driver>(
132        vmi: VmiState<WindowsOs<Driver>>,
133        ctx: impl Into<AccessContext>,
134    ) -> Result<String, VmiError>
135    where
136        Driver: VmiRead,
137        Driver::Architecture: ArchAdapter<Driver>,
138    {
139        vmi.os().read_unicode_string32_in(ctx)
140    }
141}
142
143/// 64-bit structure layout.
144pub struct StructLayout64;
145
146impl StructLayout for StructLayout64 {
147    const ADDRESS_WIDTH: u64 = 8;
148
149    fn read_va<Driver>(
150        vmi: VmiState<WindowsOs<Driver>>,
151        ctx: impl Into<AccessContext>,
152    ) -> Result<Va, VmiError>
153    where
154        Driver: VmiRead,
155        Driver::Architecture: ArchAdapter<Driver>,
156    {
157        vmi.core().read_va64(ctx)
158    }
159
160    fn read_unicode_string<Driver>(
161        vmi: VmiState<WindowsOs<Driver>>,
162        ctx: impl Into<AccessContext>,
163    ) -> Result<String, VmiError>
164    where
165        Driver: VmiRead,
166        Driver::Architecture: ArchAdapter<Driver>,
167    {
168        vmi.os().read_unicode_string64_in(ctx)
169    }
170}