vmi_os_windows/comps/object/
file.rs

1use vmi_core::{Architecture, Va, VmiDriver, VmiError, VmiState, VmiVa};
2
3use super::{super::macros::impl_offsets, WindowsObject};
4use crate::{ArchAdapter, WindowsOs, WindowsOsExt as _};
5
6/// A Windows file object.
7///
8/// A file object is a kernel structure that represents an open file or device
9/// in the Windows Object Manager. It contains metadata about the file, its access
10/// permissions, and associated device or volume.
11///
12/// # Implementation Details
13///
14/// Corresponds to `_FILE_OBJECT`.
15pub struct WindowsFileObject<'a, Driver>
16where
17    Driver: VmiDriver,
18    Driver::Architecture: Architecture + ArchAdapter<Driver>,
19{
20    /// The VMI state.
21    vmi: VmiState<'a, Driver, WindowsOs<Driver>>,
22
23    /// The virtual address of the `_FILE_OBJECT` structure.
24    va: Va,
25}
26
27impl<'a, Driver> From<WindowsFileObject<'a, Driver>> for WindowsObject<'a, Driver>
28where
29    Driver: VmiDriver,
30    Driver::Architecture: Architecture + ArchAdapter<Driver>,
31{
32    fn from(value: WindowsFileObject<'a, Driver>) -> Self {
33        Self::new(value.vmi, value.va)
34    }
35}
36
37impl<Driver> VmiVa for WindowsFileObject<'_, Driver>
38where
39    Driver: VmiDriver,
40    Driver::Architecture: Architecture + ArchAdapter<Driver>,
41{
42    fn va(&self) -> Va {
43        self.va
44    }
45}
46
47impl<'a, Driver> WindowsFileObject<'a, Driver>
48where
49    Driver: VmiDriver,
50    Driver::Architecture: Architecture + ArchAdapter<Driver>,
51{
52    impl_offsets!();
53
54    /// Creates a new Windows file object.
55    pub fn new(vmi: VmiState<'a, Driver, WindowsOs<Driver>>, va: Va) -> Self {
56        Self { vmi, va }
57    }
58
59    /// Returns the device object associated with the file object.
60    ///
61    /// # Implementation Details
62    ///
63    /// Corresponds to `_FILE_OBJECT.DeviceObject`.
64    pub fn device_object(&self) -> Result<WindowsObject<'a, Driver>, VmiError> {
65        let offsets = self.offsets();
66        let FILE_OBJECT = &offsets._FILE_OBJECT;
67
68        let device_object = self
69            .vmi
70            .read_va_native(self.va + FILE_OBJECT.DeviceObject.offset())?;
71
72        Ok(WindowsObject::new(self.vmi, device_object))
73    }
74
75    /// Returns the filename associated with the file object.
76    ///
77    /// # Implementation Details
78    ///
79    /// Corresponds to `_FILE_OBJECT.FileName`.
80    ///
81    /// # Notes
82    ///
83    /// This operation might fail as the filename is allocated from paged pool.
84    pub fn filename(&self) -> Result<String, VmiError> {
85        let offsets = self.offsets();
86        let FILE_OBJECT = &offsets._FILE_OBJECT;
87
88        // Note that filename is allocated from paged pool,
89        // so this read might fail.
90        self.vmi
91            .os()
92            .read_unicode_string(self.va + FILE_OBJECT.FileName.offset())
93    }
94
95    /// Constructs the full path of a file from its `FILE_OBJECT`.
96    ///
97    /// This function first reads the `DeviceObject` field of the `FILE_OBJECT`
98    /// structure. Then it reads the `ObjectNameInfo` of the `DeviceObject`
99    /// and its directory. Finally, it concatenates the device directory
100    /// name, device name, and file name.
101    ///
102    /// # Implementation Details
103    ///
104    /// Corresponds to `_FILE_OBJECT.DeviceObject.NameInfo.Name` concatenated
105    /// with `_FILE_OBJECT.FileName`.
106    pub fn full_path(&self) -> Result<String, VmiError> {
107        let device = self.device_object()?.name_info()?;
108        let directory = match &device {
109            Some(device) => match device.directory()? {
110                Some(directory) => directory.name_info()?,
111                None => None,
112            },
113            None => None,
114        };
115
116        let mut result = String::new();
117        if let Some(directory) = directory {
118            result.push('\\');
119            result.push_str(&directory.name()?);
120        }
121
122        if let Some(device) = device {
123            result.push('\\');
124            result.push_str(&device.name()?);
125        }
126
127        result.push_str(&self.filename()?);
128
129        Ok(result)
130    }
131}