vmi_os_windows/comps/session.rs
1use vmi_core::{Va, VmiError, VmiState, VmiVa, driver::VmiRead, os::ProcessObject};
2
3use super::WindowsProcess;
4use crate::{ArchAdapter, ListEntryIterator, WindowsOs, offset};
5
6//
7// The `_MM_SESSION_SPACE` structure got replaced in Windows 11 24H2
8// with `_PSP_SESSION_SPACE`, however, its fields aren't included in
9// the PDB symbols anymore.
10//
11// Fortunately, the layout of the beginning of the structure (up to
12// and including the `ProcessList` field) appears to be unchanged so far,
13// so, with heavy heart, we'll just hardcode the offsets.
14//
15// ```ignore
16// typedef struct _MM_SESSION_SPACE {
17// /* 0x0000 */ volatile LONG ReferenceCount;
18// /* 0x0004 */ ULONG Flags;
19// /* 0x0008 */ ULONG SessionId;
20// /* 0x0010 */ LIST_ENTRY ProcessList;
21// ...
22// } MM_SESSION_SPACE, *PMM_SESSION_SPACE;
23// ```
24//
25
26struct Field {
27 offset: u64,
28}
29
30impl Field {
31 const fn offset(&self) -> u64 {
32 self.offset
33 }
34}
35
36#[expect(non_camel_case_types)]
37struct _MM_SESSION_SPACE {
38 SessionId: Field, // ULONG
39 ProcessList: Field, // _LIST_ENTRY
40}
41
42const MM_SESSION_SPACE: _MM_SESSION_SPACE = _MM_SESSION_SPACE {
43 SessionId: Field { offset: 0x0008 },
44 ProcessList: Field { offset: 0x0010 },
45};
46
47/// A Windows session space.
48///
49/// The session space is a kernel structure that contains the
50/// session-specific data for a process.
51///
52/// Each logon session (e.g., when a user connects via Remote Desktop) gets
53/// a separate instance of `_MM_SESSION_SPACE`.
54///
55/// # Implementation Details
56///
57/// Corresponds to `_MM_SESSION_SPACE`.
58pub struct WindowsSession<'a, Driver>
59where
60 Driver: VmiRead,
61 Driver::Architecture: ArchAdapter<Driver>,
62{
63 /// The VMI state.
64 vmi: VmiState<'a, WindowsOs<Driver>>,
65
66 /// Address of the `_MM_SESSION_SPACE` structure.
67 va: Va,
68}
69
70impl<Driver> VmiVa for WindowsSession<'_, Driver>
71where
72 Driver: VmiRead,
73 Driver::Architecture: ArchAdapter<Driver>,
74{
75 fn va(&self) -> Va {
76 self.va
77 }
78}
79
80impl<'a, Driver> WindowsSession<'a, Driver>
81where
82 Driver: VmiRead,
83 Driver::Architecture: ArchAdapter<Driver>,
84{
85 /// Creates a new Windows session space.
86 pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va) -> Self {
87 Self { vmi, va }
88 }
89
90 /// Returns the session ID.
91 ///
92 /// # Implementation Details
93 ///
94 /// Corresponds to `_MM_SESSION_SPACE.SessionId`.
95 pub fn id(&self) -> Result<u32, VmiError> {
96 //let MM_SESSION_SPACE = offset!(self.vmi, _MM_SESSION_SPACE);
97
98 self.vmi
99 .read_u32(self.va + MM_SESSION_SPACE.SessionId.offset())
100 }
101
102 /// Returns the list of processes in the session.
103 ///
104 /// # Implementation Details
105 ///
106 /// Corresponds to `_MM_SESSION_SPACE.ProcessList`.
107 pub fn processes(
108 &self,
109 ) -> Result<
110 impl Iterator<Item = Result<WindowsProcess<'a, Driver>, VmiError>> + use<'a, Driver>,
111 VmiError,
112 > {
113 //let MM_SESSION_SPACE = offset!(self.vmi, _MM_SESSION_SPACE);
114 let EPROCESS = offset!(self.vmi, _EPROCESS);
115
116 let vmi = self.vmi;
117 Ok(ListEntryIterator::new(
118 vmi,
119 self.va + MM_SESSION_SPACE.ProcessList.offset(),
120 EPROCESS.SessionProcessLinks.offset(),
121 )
122 .map(move |result| result.map(|entry| WindowsProcess::new(vmi, ProcessObject(entry)))))
123 }
124}