vmi_os_windows/
lib.rs

1//! # Windows OS-specific VMI operations
2//!
3//! This crate provides functionality for introspecting Windows-based
4//! virtual machines, working in conjunction with the `vmi-core` crate.
5//! It offers abstractions and utilities for navigating Windows kernel
6//! structures, analyzing processes and memory, and performing Windows-specific
7//! VMI tasks.
8//!
9//! ## Features
10//!
11//! - Windows kernel structure parsing and navigation
12//! - Process and thread introspection
13//! - Memory management operations (VAD tree traversal, PFN database manipulation)
14//! - Windows object handling (files, sections, etc.)
15//! - PE file format parsing and analysis
16//!
17//! ## Safety Considerations
18//!
19//! Many operations in this crate require pausing the VM to ensure consistency.
20//! Always pause the VM when performing operations that could be affected by
21//! concurrent changes in the guest OS. Be aware of the Windows version you're
22//! introspecting, as kernel structures may vary between versions. Handle errors
23//! appropriately, as VMI operations can fail due to various reasons (e.g.,
24//! invalid memory access, incompatible Windows version).
25//!
26//! ## Example
27//!
28//! ```no_run
29//! # use vmi::{VmiCore, VmiDriver, os::windows::WindowsOs};
30//! #
31//! # fn example<Driver: VmiDriver>(
32//! #     vmi: &VmiCore<Driver>,
33//! #     _os: &WindowsOs<Driver>
34//! # ) -> Result<(), Box<dyn std::error::Error>> {
35//! let _guard = vmi.pause_guard()?;
36//! // Perform introspection operations here
37//! // VM automatically resumes when `_guard` goes out of scope
38//! # Ok(())
39//! # }
40//! ```
41//!
42//! Always consider the potential for race conditions and ensure you're
43//! working with a consistent state of the guest OS.
44
45// Allow Windows-specific naming conventions to be used throughout this module.
46#![allow(
47    non_snake_case,         // example: AlpcpSendMessage
48    non_upper_case_globals, // example: StandbyPageList
49)]
50
51use std::{cell::RefCell, collections::HashMap};
52
53use isr_core::Profile;
54use once_cell::unsync::OnceCell;
55use vmi_core::{
56    AccessContext, Architecture, Gfn, Hex, Registers as _, Va, VmiCore, VmiDriver, VmiError,
57    VmiState,
58    os::{ProcessObject, ThreadObject, VmiOs, VmiOsThread},
59};
60use vmi_macros::derive_trait_from_impl;
61use zerocopy::{FromBytes, IntoBytes};
62
63mod arch;
64use self::arch::ArchAdapter;
65
66mod error;
67pub use self::error::WindowsError;
68
69mod iter;
70pub use self::iter::{HandleTableEntryIterator, ListEntryIterator, TreeNodeIterator};
71
72pub mod pe;
73pub use self::pe::{CodeView, Pe, PeError};
74
75mod offsets;
76pub use self::offsets::{Offsets, OffsetsExt, Symbols}; // TODO: make private + remove offsets() & symbols() methods
77
78mod comps;
79pub use self::comps::{
80    ParseObjectTypeError, WindowsControlArea, WindowsDirectoryObject, WindowsFileObject,
81    WindowsHandleTable, WindowsHandleTableEntry, WindowsImage, WindowsModule, WindowsObject,
82    WindowsObjectAttributes, WindowsObjectHeaderNameInfo, WindowsObjectType, WindowsObjectTypeKind,
83    WindowsPeb, WindowsProcess, WindowsProcessParameters, WindowsRegion, WindowsSectionObject,
84    WindowsSession, WindowsThread, WindowsWow64Kind,
85};
86
87/// VMI operations for the Windows operating system.
88///
89/// `WindowsOs` provides methods and utilities for introspecting a Windows-based
90/// virtual machine. It encapsulates Windows-specific knowledge and operations,
91/// allowing for high-level interactions with the guest OS structures and processes.
92///
93/// # Usage
94///
95/// Create an instance of [`WindowsOs`] using a [`Profile`] that contains information
96/// about the specific Windows version being introspected:
97///
98/// ```no_run
99/// use isr::cache::{IsrCache, JsonCodec};
100/// use vmi::{VcpuId, VmiCore, VmiDriver, VmiError, os::windows::WindowsOs};
101///
102/// # fn example<Driver: VmiDriver>(
103/// #     driver: Driver
104/// # ) -> Result<(), Box<dyn std::error::Error>>
105/// # where
106/// #     Driver: VmiDriver<Architecture = vmi_arch_amd64::Amd64>,
107/// # {
108/// // Setup VMI.
109/// let core = VmiCore::new(driver)?;
110///
111/// // Try to find the kernel information.
112/// // This is necessary in order to load the profile.
113/// let kernel_info = {
114///     let _guard = core.pause_guard()?;
115///     let registers = core.registers(VcpuId(0))?;
116///
117///     WindowsOs::find_kernel(&core, &registers)?.expect("kernel information")
118/// };
119///
120/// // Load the profile using the ISR library.
121/// let isr = IsrCache::<JsonCodec>::new("cache")?;
122/// let entry = isr.entry_from_codeview(kernel_info.codeview)?;
123/// let profile = entry.profile()?;
124///
125/// // Create a new `WindowsOs` instance.
126/// let os = WindowsOs::<Driver>::new(&profile)?;
127/// # Ok(())
128/// # }
129/// ```
130///
131/// # Important Notes
132///
133/// - Many methods of this struct require pausing the VM to ensure consistency.
134///   Use [`pause_guard`] when performing operations that might be affected
135///   by concurrent changes in the guest OS.
136///
137/// - The behavior and accuracy of some methods may vary depending on the
138///   Windows version being introspected. Always ensure your [`Profile`] matches
139///   the guest OS version.
140///
141/// # Examples
142///
143/// Retrieving information about the current process:
144///
145/// ```no_run
146/// # use vmi::{VcpuId, VmiDriver, VmiState, os::windows::WindowsOs};
147/// #
148/// # fn example<Driver: VmiDriver>(
149/// #     vmi: &VmiState<Driver, WindowsOs<Driver>>,
150/// # ) -> Result<(), Box<dyn std::error::Error>>
151/// # where
152/// #     Driver: VmiDriver<Architecture = vmi_arch_amd64::Amd64>,
153/// # {
154/// let process = vmi.os().current_process()?;
155/// let process_id = process.id()?;
156/// let process_name = process.name()?;
157/// println!("Current process: {} (PID: {})", process_name, process_id);
158/// # Ok(())
159/// # }
160/// ```
161///
162/// Enumerating all processes:
163///
164/// ```no_run
165/// # use vmi::{VcpuId, VmiDriver, VmiState, os::windows::WindowsOs};
166/// #
167/// # fn example<Driver: VmiDriver>(
168/// #     vmi: &VmiState<Driver, WindowsOs<Driver>>,
169/// # ) -> Result<(), Box<dyn std::error::Error>>
170/// # where
171/// #     Driver: VmiDriver<Architecture = vmi_arch_amd64::Amd64>,
172/// # {
173/// for process in vmi.os().processes()? {
174///     println!("Process: {} (PID: {})", process.name()?, process.id()?);
175/// }
176/// # Ok(())
177/// # }
178/// ```
179///
180/// # Safety
181///
182/// While this struct doesn't use unsafe code directly, many of its methods
183/// interact with raw memory of the guest OS. Incorrect usage can lead to
184/// invalid memory access or misinterpretation of data. Always ensure you're
185/// working with the correct memory regions and OS structures.
186///
187/// [`pause_guard`]: VmiCore::pause_guard
188pub struct WindowsOs<Driver>
189where
190    Driver: VmiDriver,
191{
192    offsets: Offsets,
193    symbols: Symbols,
194
195    kernel_image_base: OnceCell<Va>,
196    highest_user_address: OnceCell<Va>,
197    object_root_directory: OnceCell<Va>, // _OBJECT_DIRECTORY*
198    object_header_cookie: OnceCell<u8>,
199    object_type_cache: RefCell<HashMap<WindowsObjectTypeKind, Va>>,
200    object_type_rcache: RefCell<HashMap<Va, WindowsObjectTypeKind>>,
201    object_type_name_cache: RefCell<HashMap<Va, String>>,
202
203    ki_kva_shadow: OnceCell<bool>,
204    mm_pfn_database: OnceCell<Va>, // _MMPFN*
205    nt_build_lab: OnceCell<String>,
206    nt_build_lab_ex: OnceCell<String>,
207
208    _marker: std::marker::PhantomData<Driver>,
209}
210
211/// Information about the Windows kernel image.
212#[derive(Debug)]
213pub struct WindowsKernelInformation {
214    /// Base virtual address where the kernel image is loaded.
215    pub base_address: Va,
216
217    /// Major version number of the Windows kernel.
218    pub version_major: u16,
219
220    /// Minor version number of the Windows kernel.
221    pub version_minor: u16,
222
223    /// CodeView debugging information for the kernel image.
224    pub codeview: CodeView,
225}
226
227/// Represents a `_EXCEPTION_RECORD` structure.
228#[derive(Debug)]
229pub struct WindowsExceptionRecord {
230    /// The `ExceptionCode` field of the exception record.
231    ///
232    /// The reason the exception occurred. This is the code generated by a
233    /// hardware exception, or the code specified in the `RaiseException`
234    /// function for a software-generated exception.
235    pub code: u32,
236
237    /// The `ExceptionFlags` field of the exception record.
238    ///
239    /// This member contains zero or more exception flags.
240    pub flags: u32,
241
242    /// The `ExceptionRecord` field of the exception record.
243    ///
244    /// A pointer to an associated `EXCEPTION_RECORD` structure.
245    /// Exception records can be chained together to provide additional
246    /// information when nested exceptions occur.
247    pub record: Va,
248
249    /// The `ExceptionAddress` field of the exception record.
250    ///
251    /// The address where the exception occurred.
252    pub address: Va,
253
254    /// The `ExceptionInformation` field of the exception record.
255    ///
256    /// An array of additional arguments that describe the exception.
257    /// The number of elements in the array is determined by the `NumberParameters`
258    /// field of the exception record.
259    pub information: Vec<u64>,
260}
261
262macro_rules! offset {
263    ($vmi:expr, $field:ident) => {
264        &this!($vmi).offsets.$field
265    };
266}
267
268macro_rules! symbol {
269    ($vmi:expr, $field:ident) => {
270        this!($vmi).symbols.$field
271    };
272}
273
274macro_rules! this {
275    ($vmi:expr) => {
276        $vmi.underlying_os()
277    };
278}
279
280#[derive_trait_from_impl(WindowsOsExt)]
281#[expect(non_snake_case, non_upper_case_globals)]
282impl<Driver> WindowsOs<Driver>
283where
284    Driver: VmiDriver,
285    Driver::Architecture: Architecture + ArchAdapter<Driver>,
286{
287    /// 32-bit current process pseudo-handle (-1).
288    pub const NtCurrentProcess32: u64 = 0xffff_ffff;
289
290    /// 64-bit current process pseudo-handle (-1).
291    pub const NtCurrentProcess64: u64 = 0xffff_ffff_ffff_ffff;
292
293    /// 32-bit current thread pseudo-handle (-2).
294    pub const NtCurrentThread32: u64 = 0xffff_fffe;
295
296    /// 64-bit current thread pseudo-handle (-2).
297    pub const NtCurrentThread64: u64 = 0xffff_ffff_ffff_fffe;
298
299    /// Creates a new `WindowsOs` instance.
300    pub fn new(profile: &Profile) -> Result<Self, VmiError> {
301        Self::create(profile, OnceCell::new())
302    }
303
304    /// Creates a new `WindowsOs` instance with a known kernel base address.
305    pub fn with_kernel_base(profile: &Profile, kernel_base: Va) -> Result<Self, VmiError> {
306        Self::create(profile, OnceCell::with_value(kernel_base))
307    }
308
309    fn create(profile: &Profile, kernel_image_base: OnceCell<Va>) -> Result<Self, VmiError> {
310        Ok(Self {
311            offsets: Offsets::new(profile)?,
312            symbols: Symbols::new(profile)?,
313            kernel_image_base,
314            highest_user_address: OnceCell::new(),
315            object_root_directory: OnceCell::new(),
316            object_header_cookie: OnceCell::new(),
317            object_type_cache: RefCell::new(HashMap::new()),
318            object_type_rcache: RefCell::new(HashMap::new()),
319            object_type_name_cache: RefCell::new(HashMap::new()),
320            ki_kva_shadow: OnceCell::new(),
321            mm_pfn_database: OnceCell::new(),
322            nt_build_lab: OnceCell::new(),
323            nt_build_lab_ex: OnceCell::new(),
324            _marker: std::marker::PhantomData,
325        })
326    }
327
328    /// Returns a reference to the Windows-specific memory offsets.
329    pub fn offsets(vmi: VmiState<'_, Driver, Self>) -> &Offsets {
330        &this!(vmi).offsets
331    }
332
333    /// Returns a reference to the Windows-specific symbols.
334    pub fn symbols(vmi: VmiState<'_, Driver, Self>) -> &Symbols {
335        &this!(vmi).symbols
336    }
337
338    /// Locates the Windows kernel in memory based on the CPU registers.
339    /// This function is architecture-specific.
340    ///
341    /// On AMD64, the kernel is located by taking the `MSR_LSTAR` value and
342    /// reading the virtual memory page by page backwards until the `MZ` header
343    /// is found.
344    pub fn find_kernel(
345        vmi: &VmiCore<Driver>,
346        registers: &<Driver::Architecture as Architecture>::Registers,
347    ) -> Result<Option<WindowsKernelInformation>, VmiError> {
348        Driver::Architecture::find_kernel(vmi, registers)
349    }
350
351    /// Returns the kernel information string.
352    ///
353    /// # Notes
354    ///
355    /// The kernel information string is cached after the first read.
356    ///
357    /// # Implementation Details
358    ///
359    /// Corresponds to `NtBuildLab` symbol.
360    pub fn kernel_information_string_ex(
361        vmi: VmiState<Driver, Self>,
362    ) -> Result<Option<String>, VmiError> {
363        let NtBuildLabEx = match symbol!(vmi, NtBuildLabEx) {
364            Some(offset) => offset,
365            None => return Ok(None),
366        };
367
368        Ok(Some(
369            this!(vmi)
370                .nt_build_lab_ex
371                .get_or_try_init(|| {
372                    let kernel_image_base = Self::kernel_image_base(vmi)?;
373                    vmi.read_string(kernel_image_base + NtBuildLabEx)
374                })
375                .cloned()?,
376        ))
377    }
378
379    /// Checks if the given handle is a kernel handle.
380    ///
381    /// A kernel handle is a handle with the highest bit set.
382    pub fn is_kernel_handle(vmi: VmiState<Driver, Self>, handle: u64) -> Result<bool, VmiError> {
383        const KERNEL_HANDLE_MASK32: u64 = 0x8000_0000;
384        const KERNEL_HANDLE_MASK64: u64 = 0xffff_ffff_8000_0000;
385
386        match vmi.registers().address_width() {
387            4 => Ok(handle & KERNEL_HANDLE_MASK32 == KERNEL_HANDLE_MASK32),
388            8 => Ok(handle & KERNEL_HANDLE_MASK64 == KERNEL_HANDLE_MASK64),
389            _ => panic!("Unsupported address width"),
390        }
391    }
392
393    /// Returns the lowest user-mode address.
394    ///
395    /// This method returns a constant value (0x10000) representing the lowest
396    /// address that can be used by user-mode applications in Windows.
397    ///
398    /// # Notes
399    ///
400    /// * Windows creates a `NO_ACCESS` VAD (Virtual Address Descriptor) for the first 64KB
401    ///   of virtual memory. This means the VA range 0-0x10000 is off-limits for usage.
402    /// * This behavior is consistent across all Windows versions from XP through
403    ///   recent Windows 11, and applies to x86, x64, and ARM64 architectures.
404    /// * Many Windows APIs leverage this fact to determine whether an input argument
405    ///   is a pointer or not. Here are two notable examples:
406    ///
407    ///   1. The `FindResource()` function accepts an `lpName` parameter of type `LPCTSTR`,
408    ///      which can be either:
409    ///      - A pointer to a valid string
410    ///      - A value created by `MAKEINTRESOURCE(ID)`
411    ///
412    ///         This allows `FindResource()` to accept `WORD` values (unsigned shorts) with
413    ///         a maximum value of 0xFFFF, distinguishing them from valid memory addresses.
414    ///
415    ///   2. The `AddAtom()` function similarly accepts an `lpString` parameter of type `LPCTSTR`.
416    ///      This parameter can be:
417    ///      - A pointer to a null-terminated string (max 255 bytes)
418    ///      - An integer atom converted using the `MAKEINTATOM(ID)` macro
419    ///
420    ///   In both cases, the API can distinguish between valid pointers (which will be
421    ///   above 0x10000) and integer values (which will be below 0x10000), allowing
422    ///   for flexible parameter usage without ambiguity.
423    pub fn lowest_user_address(_vmi: VmiState<Driver, Self>) -> Result<Va, VmiError> {
424        Ok(Va(0x10000))
425    }
426
427    /// Returns the highest user-mode address.
428    ///
429    /// This method reads the highest user-mode address from the Windows kernel.
430    /// The value is cached after the first read for performance.
431    ///
432    /// # Notes
433    ///
434    /// This value is cached after the first read.
435    ///
436    /// # Implementation Details
437    ///
438    /// Corresponds to `MmHighestUserAddress` symbol.
439    pub fn highest_user_address(vmi: VmiState<Driver, Self>) -> Result<Va, VmiError> {
440        this!(vmi)
441            .highest_user_address
442            .get_or_try_init(|| {
443                let MmHighestUserAddress =
444                    Self::kernel_image_base(vmi)? + symbol!(vmi, MmHighestUserAddress);
445
446                vmi.read_va_native(MmHighestUserAddress)
447            })
448            .copied()
449    }
450
451    /// Checks if a given address is a valid user-mode address.
452    ///
453    /// This method determines whether the provided address falls within
454    /// the range of valid user-mode addresses in Windows.
455    pub fn is_valid_user_address(
456        vmi: VmiState<Driver, Self>,
457        address: Va,
458    ) -> Result<bool, VmiError> {
459        let lowest_user_address = Self::lowest_user_address(vmi)?;
460        let highest_user_address = Self::highest_user_address(vmi)?;
461
462        Ok(address >= lowest_user_address && address <= highest_user_address)
463    }
464
465    /// Returns the virtual address of the current Kernel Processor Control
466    /// Region (KPCR).
467    ///
468    /// The KPCR is a per-processor data structure in Windows that contains
469    /// critical information about the current processor state. This method
470    /// returns the virtual address of the KPCR for the current processor.
471    pub fn current_kpcr(vmi: VmiState<Driver, Self>) -> Va {
472        Driver::Architecture::current_kpcr(vmi)
473    }
474
475    /// Returns information from an exception record at the specified address.
476    ///
477    /// This method reads and parses an `EXCEPTION_RECORD` structure from
478    /// memory, providing detailed information about an exception that has
479    /// occurred in the system. The returned [`WindowsExceptionRecord`]
480    /// contains data such as the exception code, flags, and related memory
481    /// addresses.
482    pub fn exception_record(
483        vmi: VmiState<Driver, Self>,
484        address: Va,
485    ) -> Result<WindowsExceptionRecord, VmiError> {
486        #[repr(C)]
487        #[derive(Debug, Copy, Clone, FromBytes, IntoBytes)]
488        #[allow(non_camel_case_types, non_snake_case)]
489        struct _EXCEPTION_RECORD {
490            ExceptionCode: u32,
491            ExceptionFlags: u32,
492            ExceptionRecord: u64,
493            ExceptionAddress: u64,
494            NumberParameters: u64,
495            ExceptionInformation: [u64; 15],
496        }
497
498        let record = vmi.read_struct::<_EXCEPTION_RECORD>(address)?;
499
500        Ok(WindowsExceptionRecord {
501            code: record.ExceptionCode,
502            flags: record.ExceptionFlags,
503            record: record.ExceptionRecord.into(),
504            address: record.ExceptionAddress.into(),
505            information: record.ExceptionInformation
506                [..u64::min(record.NumberParameters, 15) as usize]
507                .to_vec(),
508        })
509    }
510
511    /// Returns the last status value for the current thread.
512    ///
513    /// In Windows, the last status value is typically used to store error codes
514    /// or success indicators from system calls. This method reads this value
515    /// from the Thread Environment Block (TEB) of the current thread, providing
516    /// insight into the outcome of recent operations performed by the thread.
517    ///
518    /// Returns `None` if the TEB is not available.
519    ///
520    /// # Notes
521    ///
522    /// `LastStatusValue` is a `NTSTATUS` value, whereas `LastError` is a Win32
523    /// error code. The two values are related but not identical. You can obtain
524    /// the Win32 error code by calling
525    /// [`VmiOs::last_error`](crate::VmiOs::last_error).
526    ///
527    /// # Implementation Details
528    ///
529    /// Corresponds to `NtCurrentTeb()->LastStatusValue`.
530    pub fn last_status(vmi: VmiState<Driver, Self>) -> Result<Option<u32>, VmiError> {
531        let KTHREAD = offset!(vmi, _KTHREAD);
532        let TEB = offset!(vmi, _TEB);
533
534        let current_thread = Self::current_thread(vmi)?.object()?;
535        let teb = vmi.read_va_native(current_thread.0 + KTHREAD.Teb.offset())?;
536
537        if teb.is_null() {
538            return Ok(None);
539        }
540
541        let result = vmi.read_u32(teb + TEB.LastStatusValue.offset())?;
542        Ok(Some(result))
543    }
544
545    /// Returns the virtual address of the Page Frame Number (PFN) database.
546    ///
547    /// The PFN database is a critical data structure in Windows memory management,
548    /// containing information about each physical page in the system.
549    ///
550    /// # Notes
551    ///
552    /// This value is cached after the first read.
553    ///
554    /// # Implementation Details
555    ///
556    /// Corresponds to `MmPfnDatabase` symbol.
557    fn pfn_database(vmi: VmiState<Driver, Self>) -> Result<Va, VmiError> {
558        let MmPfnDatabase = symbol!(vmi, MmPfnDatabase);
559
560        this!(vmi)
561            .mm_pfn_database
562            .get_or_try_init(|| {
563                let kernel_image_base = Self::kernel_image_base(vmi)?;
564                vmi.read_va_native(kernel_image_base + MmPfnDatabase)
565            })
566            .copied()
567    }
568
569    fn modify_pfn_reference_count(
570        vmi: VmiState<Driver, Self>,
571        pfn: Gfn,
572        increment: i16,
573    ) -> Result<Option<u16>, VmiError> {
574        let MMPFN = offset!(vmi, _MMPFN);
575
576        // const ZeroedPageList: u16 = 0;
577        // const FreePageList: u16 = 1;
578        const StandbyPageList: u16 = 2; //this list and before make up available pages.
579        const ModifiedPageList: u16 = 3;
580        const ModifiedNoWritePageList: u16 = 4;
581        // const BadPageList: u16 = 5;
582        const ActiveAndValid: u16 = 6;
583        // const TransitionPage: u16 = 7;
584
585        let pfn = Self::pfn_database(vmi)? + u64::from(pfn) * MMPFN.len() as u64;
586
587        //
588        // In the _MMPFN structure, the fields are like this:
589        //
590        // ```c
591        // struct _MMPFN {
592        //     ...
593        //     union {
594        //         USHORT ReferenceCount;
595        //         struct {
596        //             UCHAR PageLocation : 3;
597        //             ...
598        //         } e1;
599        //         ...
600        //     } u3;
601        // };
602        // ```
603        //
604        // On the systems tested (Win7 - Win11), the `PageLocation` is right
605        // after `ReferenceCount`. We can read the value of both fields at once.
606        //
607
608        debug_assert_eq!(MMPFN.ReferenceCount.size(), 2);
609        debug_assert_eq!(
610            MMPFN.ReferenceCount.offset() + MMPFN.ReferenceCount.size(),
611            MMPFN.PageLocation.offset()
612        );
613        debug_assert_eq!(MMPFN.PageLocation.bit_position(), 0);
614        debug_assert_eq!(MMPFN.PageLocation.bit_length(), 3);
615
616        let pfn_value = vmi.read_u32(pfn + MMPFN.ReferenceCount.offset())?;
617        let flags = (pfn_value >> 16) as u16;
618        let ref_count = (pfn_value & 0xFFFF) as u16;
619
620        let page_location = flags & 7;
621
622        tracing::debug!(
623            %pfn,
624            ref_count,
625            flags = %Hex(flags),
626            page_location,
627            increment,
628            "Modifying PFN reference count"
629        );
630
631        //
632        // Make sure the page is good (when coming from hibernate/standby pages
633        // can be in modified state).
634        //
635
636        if !matches!(
637            page_location,
638            StandbyPageList | ModifiedPageList | ModifiedNoWritePageList | ActiveAndValid
639        ) {
640            tracing::warn!(
641                %pfn,
642                ref_count,
643                flags = %Hex(flags),
644                page_location,
645                increment,
646                "Page is not active and valid"
647            );
648            return Ok(None);
649        }
650
651        if ref_count == 0 {
652            tracing::warn!(
653                %pfn,
654                ref_count,
655                flags = %Hex(flags),
656                page_location,
657                increment,
658                "Page is not initialized"
659            );
660            return Ok(None);
661        }
662
663        let new_ref_count = match ref_count.checked_add_signed(increment) {
664            Some(new_ref_count) => new_ref_count,
665            None => {
666                tracing::warn!(
667                    %pfn,
668                    ref_count,
669                    flags = %Hex(flags),
670                    page_location,
671                    increment,
672                    "Page is at maximum reference count"
673                );
674                return Ok(None);
675            }
676        };
677
678        vmi.write_u16(pfn + MMPFN.ReferenceCount.offset(), new_ref_count)?;
679
680        Ok(Some(new_ref_count))
681    }
682
683    /// Increments the reference count of a Page Frame Number (PFN).
684    ///
685    /// This method is used to "lock" a physical page by increasing its
686    /// reference count, preventing it from being paged out or reallocated.
687    ///
688    /// Returns the new reference count if successful, or `None` if the
689    /// operation failed (e.g., if the page is not in a valid state).
690    ///
691    /// # Implementation Details
692    ///
693    /// The method works by:
694    /// 1. Locating the `_MMPFN` structure for the given PFN within the `MmPfnDatabase`.
695    /// 2. Incrementing the `ReferenceCount` member of the `_MMPFN` structure.
696    ///
697    /// # Warning
698    ///
699    /// This function can potentially cause race conditions if the virtual machine
700    /// is not paused during its execution. It is strongly recommended to pause
701    /// the virtual machine before calling this function and resume it afterwards.
702    ///
703    /// Failure to pause the VM may result in inconsistent state or potential
704    /// crashes if the page is concurrently modified by the guest OS.
705    ///
706    /// # Examples:
707    ///
708    /// ```no_run
709    /// # use vmi::{
710    /// #     arch::amd64::{Amd64, Registers},
711    /// #     os::windows::WindowsOs,
712    /// #     Architecture, Gfn, VmiCore, VmiDriver, VmiError,
713    /// # };
714    /// #
715    /// # fn example<Driver>(
716    /// #     vmi: &VmiCore<Driver>,
717    /// #     os: &WindowsOs<Driver>,
718    /// #     registers: &Registers,
719    /// #     pfn: Gfn,
720    /// # ) -> Result<(), VmiError>
721    /// # where
722    /// #   Driver: VmiDriver<Architecture = Amd64>,
723    /// # {
724    /// let _pause_guard = vmi.pause_guard()?;
725    /// os.lock_pfn(pfn)?;
726    /// // The VM will automatically resume when `_guard` goes out of scope
727    /// # Ok(())
728    /// # }
729    /// ```
730    pub fn lock_pfn(vmi: VmiState<Driver, Self>, pfn: Gfn) -> Result<Option<u16>, VmiError> {
731        Self::modify_pfn_reference_count(vmi, pfn, 1)
732    }
733
734    /// Decrements the reference count of a Page Frame Number (PFN).
735    ///
736    /// This method is used to "unlock" a physical page by decreasing its
737    /// reference count, potentially allowing it to be paged out or reallocated
738    /// if the count reaches zero.
739    ///
740    /// Returns the new reference count if successful, or `None` if the
741    /// operation failed (e.g., if the page is not in a valid state).
742    ///
743    /// # Implementation Details
744    ///
745    /// The method works by:
746    /// 1. Locating the `_MMPFN` structure for the given PFN within the `MmPfnDatabase`.
747    /// 2. Decrementing the `ReferenceCount` member of the `_MMPFN` structure.
748    ///
749    /// # Warning
750    ///
751    /// This function can potentially cause race conditions if the virtual machine
752    /// is not paused during its execution. It is strongly recommended to pause
753    /// the virtual machine before calling this function and resume it afterwards.
754    ///
755    /// Failure to pause the VM may result in inconsistent state or potential
756    /// crashes if the page is concurrently modified by the guest OS.
757    ///
758    /// # Examples
759    ///
760    /// ```no_run
761    /// # use vmi_arch_amd64::{Amd64, Registers};
762    /// # use vmi_core::{Architecture, Gfn, VmiCore, VmiDriver, VmiError, VmiOs};
763    /// # use vmi_os_windows::WindowsOs;
764    /// #
765    /// # fn example<Driver>(
766    /// #     vmi: &VmiCore<Driver>,
767    /// #     os: &WindowsOs<Driver>,
768    /// #     registers: &Registers,
769    /// #     pfn: Gfn,
770    /// # ) -> Result<(), VmiError>
771    /// # where
772    /// #     Driver: VmiDriver<Architecture = Amd64>,
773    /// # {
774    /// let _pause_guard = vmi.pause_guard()?;
775    /// os.unlock_pfn(pfn)?;
776    /// // The VM will automatically resume when `_guard` goes out of scope
777    /// # Ok(())
778    /// # }
779    /// ```
780    pub fn unlock_pfn(vmi: VmiState<Driver, Self>, pfn: Gfn) -> Result<Option<u16>, VmiError> {
781        Self::modify_pfn_reference_count(vmi, pfn, -1)
782    }
783
784    /// Returns the Windows object.
785    pub fn object<'a>(
786        vmi: VmiState<'a, Driver, Self>,
787        va: Va,
788    ) -> Result<WindowsObject<'a, Driver>, VmiError> {
789        Ok(WindowsObject::new(vmi, va))
790    }
791
792    /// Returns a Windows object type for the given object kind.
793    ///
794    /// # Notes
795    ///
796    /// The object type is cached after the first read.
797    ///
798    /// # Implementation Details
799    ///
800    /// - `File` corresponds to `IoFileObjectType`.
801    /// - `Job` corresponds to `PsJobType`.
802    /// - `Key` corresponds to `CmKeyObjectType`.
803    /// - `Process` corresponds to `PsProcessType`.
804    /// - `Thread` corresponds to `PsThreadType`.
805    /// - `Token` corresponds to `SeTokenObjectType`.
806    /// - Other types are not supported.
807    pub fn object_type<'a>(
808        vmi: VmiState<'a, Driver, Self>,
809        kind: WindowsObjectTypeKind,
810    ) -> Result<WindowsObjectType<'a, Driver>, VmiError> {
811        if let Some(va) = this!(vmi).object_type_cache.borrow().get(&kind).copied() {
812            return Ok(WindowsObjectType::new(vmi, va));
813        }
814
815        let symbol = match kind {
816            WindowsObjectTypeKind::File => symbol!(vmi, IoFileObjectType),
817            WindowsObjectTypeKind::Job => symbol!(vmi, PsJobType),
818            WindowsObjectTypeKind::Key => symbol!(vmi, CmKeyObjectType),
819            WindowsObjectTypeKind::Process => symbol!(vmi, PsProcessType),
820            WindowsObjectTypeKind::Thread => symbol!(vmi, PsThreadType),
821            WindowsObjectTypeKind::Token => symbol!(vmi, SeTokenObjectType),
822            _ => return Err(VmiError::NotSupported),
823        };
824
825        let va = vmi.read_va(Self::kernel_image_base(vmi)? + symbol)?;
826        this!(vmi).object_type_cache.borrow_mut().insert(kind, va);
827
828        Ok(WindowsObjectType::new(vmi, va))
829    }
830
831    /// Returns the root directory object for the Windows kernel.
832    ///
833    /// # Notes
834    ///
835    /// The object root directory is cached after the first read.
836    ///
837    /// # Implementation Details
838    ///
839    /// Corresponds to `ObpRootDirectoryObject` symbol.
840    pub fn object_root_directory<'a>(
841        vmi: VmiState<'a, Driver, Self>,
842    ) -> Result<WindowsDirectoryObject<'a, Driver>, VmiError> {
843        let object_root_directory = this!(vmi)
844            .object_root_directory
845            .get_or_try_init(|| {
846                let ObpRootDirectoryObject =
847                    Self::kernel_image_base(vmi)? + symbol!(vmi, ObpRootDirectoryObject);
848
849                vmi.read_va_native(ObpRootDirectoryObject)
850            })
851            .copied()?;
852
853        Ok(WindowsDirectoryObject::new(vmi, object_root_directory))
854    }
855
856    /// Returns the object header cookie used for obfuscating object types.
857    /// Returns `None` if the cookie is not present in the kernel image.
858    ///
859    /// # Notes
860    ///
861    /// Windows 10 introduced a security feature that obfuscates the type
862    /// of kernel objects by XORing the `TypeIndex` field in the object header
863    /// with a random cookie value. This method fetches that cookie, which is
864    /// essential for correctly interpreting object headers in memory.
865    ///
866    /// The cookie is cached after the first read.
867    ///
868    /// # Implementation Details
869    ///
870    /// Corresponds to `ObHeaderCookie` symbol.
871    pub fn object_header_cookie(vmi: VmiState<Driver, Self>) -> Result<Option<u8>, VmiError> {
872        let ObHeaderCookie = match symbol!(vmi, ObHeaderCookie) {
873            Some(cookie) => cookie,
874            None => return Ok(None),
875        };
876
877        Ok(Some(
878            this!(vmi)
879                .object_header_cookie
880                .get_or_try_init(|| {
881                    let kernel_image_base = Self::kernel_image_base(vmi)?;
882                    vmi.read_u8(kernel_image_base + ObHeaderCookie)
883                })
884                .copied()?,
885        ))
886    }
887
888    /// Returns the Windows object attributes.
889    pub fn object_attributes<'a>(
890        vmi: VmiState<'a, Driver, Self>,
891        object_attributes: Va,
892    ) -> Result<WindowsObjectAttributes<'a, Driver>, VmiError> {
893        Ok(WindowsObjectAttributes::new(vmi, object_attributes))
894    }
895
896    /// Reads string of bytes from an `_ANSI_STRING` structure.
897    ///
898    /// This method reads a native `_ANSI_STRING` structure which contains
899    /// an ASCII/ANSI string. The structure is read according to the current
900    /// OS's architecture (32-bit or 64-bit).
901    pub fn read_ansi_string_bytes(
902        vmi: VmiState<Driver, Self>,
903        va: Va,
904    ) -> Result<Vec<u8>, VmiError> {
905        Self::read_ansi_string_bytes_in(vmi, vmi.access_context(va))
906    }
907
908    /// Reads string of bytes from a 32-bit version of `_ANSI_STRING` structure.
909    ///
910    /// This method is specifically for reading `_ANSI_STRING` structures in
911    /// 32-bit processes or WoW64 processes where pointers are 32 bits.
912    pub fn read_ansi_string32_bytes(
913        vmi: VmiState<Driver, Self>,
914        va: Va,
915    ) -> Result<Vec<u8>, VmiError> {
916        Self::read_ansi_string32_bytes_in(vmi, vmi.access_context(va))
917    }
918
919    /// Reads string of bytes from a 64-bit version of `_ANSI_STRING` structure.
920    ///
921    /// This method is specifically for reading `_ANSI_STRING` structures in
922    /// 64-bit processes where pointers are 64 bits.
923    pub fn read_ansi_string64_bytes(
924        vmi: VmiState<Driver, Self>,
925        va: Va,
926    ) -> Result<Vec<u8>, VmiError> {
927        Self::read_ansi_string64_bytes_in(vmi, vmi.access_context(va))
928    }
929
930    /// Reads string from an `_ANSI_STRING` structure.
931    ///
932    /// This method reads a native `_ANSI_STRING` structure which contains
933    /// an ASCII/ANSI string. The structure is read according to the current
934    /// OS's architecture (32-bit or 64-bit).
935    pub fn read_ansi_string(vmi: VmiState<Driver, Self>, va: Va) -> Result<String, VmiError> {
936        Self::read_ansi_string_in(vmi, vmi.access_context(va))
937    }
938
939    /// Reads string from a 32-bit version of `_ANSI_STRING` structure.
940    ///
941    /// This method is specifically for reading `_ANSI_STRING` structures in
942    /// 32-bit processes or WoW64 processes where pointers are 32 bits.
943    pub fn read_ansi_string32(vmi: VmiState<Driver, Self>, va: Va) -> Result<String, VmiError> {
944        Self::read_ansi_string32_in(vmi, vmi.access_context(va))
945    }
946
947    /// Reads string from a 64-bit version of `_ANSI_STRING` structure.
948    ///
949    /// This method is specifically for reading `_ANSI_STRING` structures in
950    /// 64-bit processes where pointers are 64 bits.
951    pub fn read_ansi_string64(vmi: VmiState<Driver, Self>, va: Va) -> Result<String, VmiError> {
952        Self::read_ansi_string64_in(vmi, vmi.access_context(va))
953    }
954
955    /// Reads string from a `_UNICODE_STRING` structure.
956    ///
957    /// This method reads a native `_UNICODE_STRING` structure which contains
958    /// a UTF-16 string. The structure is read according to the current OS's
959    /// architecture (32-bit or 64-bit).
960    pub fn read_unicode_string_bytes(
961        vmi: VmiState<Driver, Self>,
962        va: Va,
963    ) -> Result<Vec<u16>, VmiError> {
964        Self::read_unicode_string_bytes_in(vmi, vmi.access_context(va))
965    }
966
967    /// Reads string from a 32-bit version of `_UNICODE_STRING` structure.
968    ///
969    /// This method is specifically for reading `_UNICODE_STRING` structures
970    /// in 32-bit processes or WoW64 processes where pointers are 32 bits.
971    pub fn read_unicode_string32_bytes(
972        vmi: VmiState<Driver, Self>,
973        va: Va,
974    ) -> Result<Vec<u16>, VmiError> {
975        Self::read_unicode_string32_bytes_in(vmi, vmi.access_context(va))
976    }
977
978    /// Reads string from a 64-bit version of `_UNICODE_STRING` structure.
979    ///
980    /// This method is specifically for reading `_UNICODE_STRING` structures
981    /// in 64-bit processes where pointers are 64 bits.
982    pub fn read_unicode_string64_bytes(
983        vmi: VmiState<Driver, Self>,
984        va: Va,
985    ) -> Result<Vec<u16>, VmiError> {
986        Self::read_unicode_string64_bytes_in(vmi, vmi.access_context(va))
987    }
988
989    /// Reads string from a `_UNICODE_STRING` structure.
990    ///
991    /// This method reads a native `_UNICODE_STRING` structure which contains
992    /// a UTF-16 string. The structure is read according to the current OS's
993    /// architecture (32-bit or 64-bit).
994    pub fn read_unicode_string(vmi: VmiState<Driver, Self>, va: Va) -> Result<String, VmiError> {
995        Self::read_unicode_string_in(vmi, vmi.access_context(va))
996    }
997
998    /// Reads string from a 32-bit version of `_UNICODE_STRING` structure.
999    ///
1000    /// This method is specifically for reading `_UNICODE_STRING` structures
1001    /// in 32-bit processes or WoW64 processes where pointers are 32 bits.
1002    pub fn read_unicode_string32(vmi: VmiState<Driver, Self>, va: Va) -> Result<String, VmiError> {
1003        Self::read_unicode_string32_in(vmi, vmi.access_context(va))
1004    }
1005
1006    /// Reads string from a 64-bit version of `_UNICODE_STRING` structure.
1007    ///
1008    /// This method is specifically for reading `_UNICODE_STRING` structures
1009    /// in 64-bit processes where pointers are 64 bits.
1010    pub fn read_unicode_string64(vmi: VmiState<Driver, Self>, va: Va) -> Result<String, VmiError> {
1011        Self::read_unicode_string64_in(vmi, vmi.access_context(va))
1012    }
1013
1014    /// Reads string of bytes from a 32-bit version of `_ANSI_STRING` or
1015    /// `_UNICODE_STRING` structure.
1016    ///
1017    /// This method is specifically for reading `_ANSI_STRING` or
1018    /// `_UNICODE_STRING` structures in 32-bit processes or WoW64 processes
1019    /// where pointers are 32 bits.
1020    fn read_string32_in(
1021        vmi: VmiState<Driver, Self>,
1022        ctx: impl Into<AccessContext>,
1023    ) -> Result<Vec<u8>, VmiError> {
1024        let mut ctx = ctx.into();
1025
1026        let mut buffer = [0u8; 8];
1027        vmi.read_in(ctx, &mut buffer)?;
1028
1029        let string_length = u16::from_le_bytes([buffer[0], buffer[1]]);
1030
1031        if string_length == 0 {
1032            return Ok(Vec::new());
1033        }
1034
1035        // let string_maximum_length = u16::from_le_bytes([buffer[2], buffer[3]]);
1036        let string_buffer = u32::from_le_bytes([buffer[4], buffer[5], buffer[6], buffer[7]]);
1037
1038        if string_buffer == 0 {
1039            tracing::warn!(
1040                addr = %Hex(ctx.address),
1041                len = string_length,
1042                "String buffer is NULL"
1043            );
1044
1045            return Ok(Vec::new());
1046        }
1047
1048        ctx.address = string_buffer as u64;
1049
1050        let mut buffer = vec![0u8; string_length as usize];
1051        vmi.read_in(ctx, &mut buffer)?;
1052
1053        Ok(buffer)
1054    }
1055
1056    /// Reads string of bytes from a 64-bit version of `_ANSI_STRING` or
1057    /// `_UNICODE_STRING` structure.
1058    ///
1059    /// This method is specifically for reading `_ANSI_STRING` or
1060    /// `_UNICODE_STRING` structures in 64-bit processes where pointers
1061    /// are 64 bits.
1062    fn read_string64_in(
1063        vmi: VmiState<Driver, Self>,
1064        ctx: impl Into<AccessContext>,
1065    ) -> Result<Vec<u8>, VmiError> {
1066        let mut ctx = ctx.into();
1067
1068        let mut buffer = [0u8; 16];
1069        vmi.read_in(ctx, &mut buffer)?;
1070
1071        let string_length = u16::from_le_bytes([buffer[0], buffer[1]]);
1072
1073        if string_length == 0 {
1074            return Ok(Vec::new());
1075        }
1076
1077        // let string_maximum_length = u16::from_le_bytes([buffer[2], buffer[3]]);
1078        let string_buffer = u64::from_le_bytes([
1079            buffer[8], buffer[9], buffer[10], buffer[11], buffer[12], buffer[13], buffer[14],
1080            buffer[15],
1081        ]);
1082
1083        if string_buffer == 0 {
1084            tracing::warn!(
1085                addr = %Hex(ctx.address),
1086                len = string_length,
1087                "String buffer is NULL"
1088            );
1089
1090            return Ok(Vec::new());
1091        }
1092
1093        ctx.address = string_buffer;
1094
1095        let mut buffer = vec![0u8; string_length as usize];
1096        vmi.read_in(ctx, &mut buffer)?;
1097
1098        Ok(buffer)
1099    }
1100
1101    /// Reads string of bytes from an `_ANSI_STRING` structure.
1102    ///
1103    /// This method reads a native `_ANSI_STRING` structure which contains
1104    /// an ASCII/ANSI string. The structure is read according to the current
1105    /// OS's architecture (32-bit or 64-bit).
1106    pub fn read_ansi_string_bytes_in(
1107        vmi: VmiState<Driver, Self>,
1108        ctx: impl Into<AccessContext>,
1109    ) -> Result<Vec<u8>, VmiError> {
1110        match vmi.registers().address_width() {
1111            4 => Self::read_ansi_string32_bytes_in(vmi, ctx),
1112            8 => Self::read_ansi_string64_bytes_in(vmi, ctx),
1113            _ => panic!("Unsupported address width"),
1114        }
1115    }
1116
1117    /// Reads string of bytes from a 32-bit version of `_ANSI_STRING` structure.
1118    ///
1119    /// This method is specifically for reading `_ANSI_STRING` structures in
1120    /// 32-bit processes or WoW64 processes where pointers are 32 bits.
1121    pub fn read_ansi_string32_bytes_in(
1122        vmi: VmiState<Driver, Self>,
1123        ctx: impl Into<AccessContext>,
1124    ) -> Result<Vec<u8>, VmiError> {
1125        Self::read_string32_in(vmi, ctx)
1126    }
1127
1128    /// Reads string of bytes from a 64-bit version of `_ANSI_STRING` structure.
1129    ///
1130    /// This method is specifically for reading `_ANSI_STRING` structures in
1131    /// 64-bit processes where pointers are 64 bits.
1132    pub fn read_ansi_string64_bytes_in(
1133        vmi: VmiState<Driver, Self>,
1134        ctx: impl Into<AccessContext>,
1135    ) -> Result<Vec<u8>, VmiError> {
1136        Self::read_string64_in(vmi, ctx)
1137    }
1138
1139    /// Reads string from an `_ANSI_STRING` structure.
1140    ///
1141    /// This method reads a native `_ANSI_STRING` structure which contains
1142    /// an ASCII/ANSI string. The structure is read according to the current
1143    /// OS's architecture (32-bit or 64-bit).
1144    pub fn read_ansi_string_in(
1145        vmi: VmiState<Driver, Self>,
1146        ctx: impl Into<AccessContext>,
1147    ) -> Result<String, VmiError> {
1148        match vmi.registers().address_width() {
1149            4 => Self::read_ansi_string32_in(vmi, ctx),
1150            8 => Self::read_ansi_string64_in(vmi, ctx),
1151            _ => panic!("Unsupported address width"),
1152        }
1153    }
1154
1155    /// Reads string from a 32-bit version of `_ANSI_STRING` structure.
1156    ///
1157    /// This method is specifically for reading `_ANSI_STRING` structures in
1158    /// 32-bit processes or WoW64 processes where pointers are 32 bits.
1159    pub fn read_ansi_string32_in(
1160        vmi: VmiState<Driver, Self>,
1161        ctx: impl Into<AccessContext>,
1162    ) -> Result<String, VmiError> {
1163        Ok(String::from_utf8_lossy(&Self::read_ansi_string32_bytes_in(vmi, ctx)?).into())
1164    }
1165
1166    /// Reads string from a 64-bit version of `_ANSI_STRING` structure.
1167    ///
1168    /// This method is specifically for reading `_ANSI_STRING` structures in
1169    /// 64-bit processes where pointers are 64 bits.
1170    pub fn read_ansi_string64_in(
1171        vmi: VmiState<Driver, Self>,
1172        ctx: impl Into<AccessContext>,
1173    ) -> Result<String, VmiError> {
1174        Ok(String::from_utf8_lossy(&Self::read_ansi_string64_bytes_in(vmi, ctx)?).into())
1175    }
1176
1177    /// Reads string from a `_UNICODE_STRING` structure.
1178    ///
1179    /// This method reads a native `_UNICODE_STRING` structure which contains
1180    /// a UTF-16 string. The structure is read according to the current OS's
1181    /// architecture (32-bit or 64-bit).
1182    pub fn read_unicode_string_bytes_in(
1183        vmi: VmiState<Driver, Self>,
1184        ctx: impl Into<AccessContext>,
1185    ) -> Result<Vec<u16>, VmiError> {
1186        match vmi.registers().address_width() {
1187            4 => Self::read_unicode_string32_bytes_in(vmi, ctx),
1188            8 => Self::read_unicode_string64_bytes_in(vmi, ctx),
1189            _ => panic!("Unsupported address width"),
1190        }
1191    }
1192
1193    /// Reads string from a 32-bit version of `_UNICODE_STRING` structure.
1194    ///
1195    /// This method is specifically for reading `_UNICODE_STRING` structures
1196    /// in 32-bit processes or WoW64 processes where pointers are 32 bits.
1197    pub fn read_unicode_string32_bytes_in(
1198        vmi: VmiState<Driver, Self>,
1199        ctx: impl Into<AccessContext>,
1200    ) -> Result<Vec<u16>, VmiError> {
1201        let buffer = Self::read_string32_in(vmi, ctx)?;
1202
1203        Ok(buffer
1204            .chunks_exact(2)
1205            .map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
1206            .collect::<Vec<_>>())
1207    }
1208
1209    /// Reads string from a 64-bit version of `_UNICODE_STRING` structure.
1210    ///
1211    /// This method is specifically for reading `_UNICODE_STRING` structures
1212    /// in 64-bit processes where pointers are 64 bits.
1213    pub fn read_unicode_string64_bytes_in(
1214        vmi: VmiState<Driver, Self>,
1215        ctx: impl Into<AccessContext>,
1216    ) -> Result<Vec<u16>, VmiError> {
1217        let buffer = Self::read_string64_in(vmi, ctx)?;
1218
1219        Ok(buffer
1220            .chunks_exact(2)
1221            .map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
1222            .collect::<Vec<_>>())
1223    }
1224
1225    /// Reads string from a `_UNICODE_STRING` structure.
1226    ///
1227    /// This method reads a native `_UNICODE_STRING` structure which contains
1228    /// a UTF-16 string. The structure is read according to the current OS's
1229    /// architecture (32-bit or 64-bit).
1230    pub fn read_unicode_string_in(
1231        vmi: VmiState<Driver, Self>,
1232        ctx: impl Into<AccessContext>,
1233    ) -> Result<String, VmiError> {
1234        match vmi.registers().address_width() {
1235            4 => Self::read_unicode_string32_in(vmi, ctx),
1236            8 => Self::read_unicode_string64_in(vmi, ctx),
1237            _ => panic!("Unsupported address width"),
1238        }
1239    }
1240
1241    /// Reads string from a 32-bit version of `_UNICODE_STRING` structure.
1242    ///
1243    /// This method is specifically for reading `_UNICODE_STRING` structures
1244    /// in 32-bit processes or WoW64 processes where pointers are 32 bits.
1245    pub fn read_unicode_string32_in(
1246        vmi: VmiState<Driver, Self>,
1247        ctx: impl Into<AccessContext>,
1248    ) -> Result<String, VmiError> {
1249        Ok(String::from_utf16_lossy(
1250            &Self::read_unicode_string32_bytes_in(vmi, ctx)?,
1251        ))
1252    }
1253
1254    /// Reads string from a 64-bit version of `_UNICODE_STRING` structure.
1255    ///
1256    /// This method is specifically for reading `_UNICODE_STRING` structures
1257    /// in 64-bit processes where pointers are 64 bits.
1258    pub fn read_unicode_string64_in(
1259        vmi: VmiState<Driver, Self>,
1260        ctx: impl Into<AccessContext>,
1261    ) -> Result<String, VmiError> {
1262        Ok(String::from_utf16_lossy(
1263            &Self::read_unicode_string64_bytes_in(vmi, ctx)?,
1264        ))
1265    }
1266
1267    /// Returns an iterator over a doubly-linked list of `LIST_ENTRY` structures.
1268    ///
1269    /// This method is used to iterate over a doubly-linked list of `LIST_ENTRY`
1270    /// structures in memory. It returns an iterator that yields the virtual
1271    /// addresses of each `LIST_ENTRY` structure in the list.
1272    pub fn linked_list<'a>(
1273        vmi: VmiState<'a, Driver, Self>,
1274        list_head: Va,
1275        offset: u64,
1276    ) -> Result<impl Iterator<Item = Result<Va, VmiError>> + 'a, VmiError> {
1277        Ok(ListEntryIterator::new(vmi, list_head, offset))
1278    }
1279}
1280
1281#[expect(non_snake_case)]
1282impl<Driver> VmiOs<Driver> for WindowsOs<Driver>
1283where
1284    Driver: VmiDriver,
1285    Driver::Architecture: Architecture + ArchAdapter<Driver>,
1286{
1287    type Process<'a> = WindowsProcess<'a, Driver>;
1288    type Thread<'a> = WindowsThread<'a, Driver>;
1289    type Image<'a> = WindowsImage<'a, Driver>;
1290    type Module<'a> = WindowsModule<'a, Driver>;
1291    type Region<'a> = WindowsRegion<'a, Driver>;
1292    type Mapped<'a> = WindowsControlArea<'a, Driver>;
1293
1294    fn kernel_image_base(vmi: VmiState<Driver, Self>) -> Result<Va, VmiError> {
1295        Driver::Architecture::kernel_image_base(vmi)
1296    }
1297
1298    fn kernel_information_string(vmi: VmiState<Driver, Self>) -> Result<String, VmiError> {
1299        this!(vmi)
1300            .nt_build_lab
1301            .get_or_try_init(|| {
1302                let NtBuildLab = symbol!(vmi, NtBuildLab);
1303
1304                let kernel_image_base = Self::kernel_image_base(vmi)?;
1305                vmi.read_string(kernel_image_base + NtBuildLab)
1306            })
1307            .cloned()
1308    }
1309
1310    /// Checks if Kernel Virtual Address Shadow (KVA Shadow) is enabled.
1311    ///
1312    /// KVA Shadow is a security feature introduced in Windows 10 that
1313    /// mitigates Meltdown and Spectre vulnerabilities by isolating
1314    /// kernel memory from user-mode processes.
1315    ///
1316    /// # Notes
1317    ///
1318    /// This value is cached after the first read.
1319    ///
1320    /// # Implementation Details
1321    ///
1322    /// Corresponds to `KiKvaShadow` symbol.
1323    fn kpti_enabled(vmi: VmiState<Driver, Self>) -> Result<bool, VmiError> {
1324        this!(vmi)
1325            .ki_kva_shadow
1326            .get_or_try_init(|| {
1327                let KiKvaShadow = symbol!(vmi, KiKvaShadow);
1328
1329                let KiKvaShadow = match KiKvaShadow {
1330                    Some(KiKvaShadow) => KiKvaShadow,
1331                    None => return Ok(false),
1332                };
1333
1334                let kernel_image_base = Self::kernel_image_base(vmi)?;
1335                Ok(vmi.read_u8(kernel_image_base + KiKvaShadow)? != 0)
1336            })
1337            .copied()
1338    }
1339
1340    /// Returns an iterator over all loaded Windows Driver modules.
1341    ///
1342    /// This method returns an iterator over all loaded Windows Driver modules.
1343    /// It reads the `PsLoadedModuleList` symbol from the kernel image and
1344    /// iterates over the linked list of `KLDR_DATA_TABLE_ENTRY` structures
1345    /// representing each loaded module.
1346    fn modules(
1347        vmi: VmiState<'_, Driver, Self>,
1348    ) -> Result<impl Iterator<Item = Result<Self::Module<'_>, VmiError>> + '_, VmiError> {
1349        let PsLoadedModuleList = Self::kernel_image_base(vmi)? + symbol!(vmi, PsLoadedModuleList);
1350        let KLDR_DATA_TABLE_ENTRY = offset!(vmi, _KLDR_DATA_TABLE_ENTRY);
1351
1352        Ok(ListEntryIterator::new(
1353            vmi,
1354            PsLoadedModuleList,
1355            KLDR_DATA_TABLE_ENTRY.InLoadOrderLinks.offset(),
1356        )
1357        .map(move |result| result.map(|entry| WindowsModule::new(vmi, entry))))
1358    }
1359
1360    /// Returns an iterator over all Windows processes.
1361    ///
1362    /// This method returns an iterator over all Windows processes. It reads the
1363    /// `PsActiveProcessHead` symbol from the kernel image and iterates over the
1364    /// linked list of `EPROCESS` structures representing each process.
1365    fn processes(
1366        vmi: VmiState<'_, Driver, Self>,
1367    ) -> Result<impl Iterator<Item = Result<Self::Process<'_>, VmiError>> + '_, VmiError> {
1368        let PsActiveProcessHead = Self::kernel_image_base(vmi)? + symbol!(vmi, PsActiveProcessHead);
1369        let EPROCESS = offset!(vmi, _EPROCESS);
1370
1371        Ok(ListEntryIterator::new(
1372            vmi,
1373            PsActiveProcessHead,
1374            EPROCESS.ActiveProcessLinks.offset(),
1375        )
1376        .map(move |result| result.map(|entry| WindowsProcess::new(vmi, ProcessObject(entry)))))
1377    }
1378
1379    fn process(
1380        vmi: VmiState<'_, Driver, Self>,
1381        process: ProcessObject,
1382    ) -> Result<Self::Process<'_>, VmiError> {
1383        Ok(WindowsProcess::new(vmi, process))
1384    }
1385
1386    /// Returns the current process.
1387    fn current_process(vmi: VmiState<'_, Driver, Self>) -> Result<Self::Process<'_>, VmiError> {
1388        Self::current_thread(vmi)?.attached_process()
1389    }
1390
1391    /// Returns the system process.
1392    ///
1393    /// The system process is the first process created by the Windows kernel
1394    /// during system initialization. It is the parent process of all other
1395    /// processes in the system.
1396    fn system_process(vmi: VmiState<'_, Driver, Self>) -> Result<Self::Process<'_>, VmiError> {
1397        let PsInitialSystemProcess =
1398            Self::kernel_image_base(vmi)? + symbol!(vmi, PsInitialSystemProcess);
1399
1400        let process = vmi.read_va_native(PsInitialSystemProcess)?;
1401        Ok(WindowsProcess::new(vmi, ProcessObject(process)))
1402    }
1403
1404    fn thread(
1405        vmi: VmiState<'_, Driver, Self>,
1406        thread: ThreadObject,
1407    ) -> Result<Self::Thread<'_>, VmiError> {
1408        Ok(WindowsThread::new(vmi, thread))
1409    }
1410
1411    /// Returns the current thread.
1412    fn current_thread(vmi: VmiState<'_, Driver, Self>) -> Result<Self::Thread<'_>, VmiError> {
1413        let KPCR = offset!(vmi, _KPCR);
1414        let KPRCB = offset!(vmi, _KPRCB);
1415
1416        let kpcr = Self::current_kpcr(vmi);
1417
1418        if kpcr.is_null() {
1419            return Err(WindowsError::CorruptedStruct("KPCR").into());
1420        }
1421
1422        let addr = kpcr + KPCR.Prcb.offset() + KPRCB.CurrentThread.offset();
1423        let result = vmi.read_va_native(addr)?;
1424
1425        if result.is_null() {
1426            return Err(WindowsError::CorruptedStruct("KPCR.Prcb.CurrentThread").into());
1427        }
1428
1429        Ok(WindowsThread::new(vmi, ThreadObject(result)))
1430    }
1431
1432    fn image(vmi: VmiState<'_, Driver, Self>, image_base: Va) -> Result<Self::Image<'_>, VmiError> {
1433        Ok(WindowsImage::new(vmi, image_base))
1434    }
1435
1436    fn module(vmi: VmiState<'_, Driver, Self>, module: Va) -> Result<Self::Module<'_>, VmiError> {
1437        Ok(WindowsModule::new(vmi, module))
1438    }
1439
1440    fn region(vmi: VmiState<'_, Driver, Self>, region: Va) -> Result<Self::Region<'_>, VmiError> {
1441        Ok(WindowsRegion::new(vmi, region))
1442    }
1443
1444    fn syscall_argument(vmi: VmiState<Driver, Self>, index: u64) -> Result<u64, VmiError> {
1445        Driver::Architecture::syscall_argument(vmi, index)
1446    }
1447
1448    fn function_argument(vmi: VmiState<Driver, Self>, index: u64) -> Result<u64, VmiError> {
1449        Driver::Architecture::function_argument(vmi, index)
1450    }
1451
1452    fn function_return_value(vmi: VmiState<Driver, Self>) -> Result<u64, VmiError> {
1453        Driver::Architecture::function_return_value(vmi)
1454    }
1455
1456    fn last_error(vmi: VmiState<Driver, Self>) -> Result<Option<u32>, VmiError> {
1457        let KTHREAD = offset!(vmi, _KTHREAD);
1458        let TEB = offset!(vmi, _TEB);
1459
1460        let current_thread = Self::current_thread(vmi)?.object()?;
1461        let teb = vmi.read_va_native(current_thread.0 + KTHREAD.Teb.offset())?;
1462
1463        if teb.is_null() {
1464            return Ok(None);
1465        }
1466
1467        let result = vmi.read_u32(teb + TEB.LastErrorValue.offset())?;
1468
1469        Ok(Some(result))
1470    }
1471}