1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use vmi_core::{Va, VmiError, VmiState, VmiVa, driver::VmiRead, os::VmiOsModule};
use crate::{ArchAdapter, WindowsOs, WindowsOsExt as _, offset};
/// A Windows kernel module.
///
/// A module in Windows refers to a loaded executable or driver,
/// typically tracked in the kernel's module list.
///
/// # Implementation Details
///
/// Corresponds to `_KLDR_DATA_TABLE_ENTRY`.
pub struct WindowsModule<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
/// The VMI state.
vmi: VmiState<'a, WindowsOs<Driver>>,
/// Address of the `_KLDR_DATA_TABLE_ENTRY` structure.
va: Va,
}
impl<Driver> VmiVa for WindowsModule<'_, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn va(&self) -> Va {
self.va
}
}
impl<'a, Driver> WindowsModule<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
/// Creates a new Windows kernel module.
pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va) -> Self {
Self { vmi, va }
}
/// Returns the entry point of the module.
///
/// # Implementation Details
///
/// Corresponds to `_KLDR_DATA_TABLE_ENTRY.EntryPoint`.
pub fn entry_point(&self) -> Result<Va, VmiError> {
let KLDR_DATA_TABLE_ENTRY = offset!(self.vmi, _KLDR_DATA_TABLE_ENTRY);
self.vmi
.read_va_native(self.va + KLDR_DATA_TABLE_ENTRY.EntryPoint.offset())
}
/// Returns the full name of the module.
///
/// # Implementation Details
///
/// Corresponds to `_KLDR_DATA_TABLE_ENTRY.FullDllName`.
///
/// # Notes
///
/// This operation might fail as the filename is allocated from paged pool.
pub fn full_name(&self) -> Result<String, VmiError> {
let KLDR_DATA_TABLE_ENTRY = offset!(self.vmi, _KLDR_DATA_TABLE_ENTRY);
self.vmi
.os()
.read_unicode_string(self.va + KLDR_DATA_TABLE_ENTRY.FullDllName.offset())
}
/// Returns the timestamp of the module.
///
/// # Implementation Details
///
/// Corresponds to `_KLDR_DATA_TABLE_ENTRY.TimeDateStamp`.
pub fn time_date_stamp(&self) -> Result<u32, VmiError> {
let KLDR_DATA_TABLE_ENTRY = offset!(self.vmi, _KLDR_DATA_TABLE_ENTRY);
self.vmi
.read_u32(self.va + KLDR_DATA_TABLE_ENTRY.TimeDateStamp.offset())
}
}
impl<'a, Driver> VmiOsModule<'a, Driver> for WindowsModule<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
type Os = WindowsOs<Driver>;
/// Returns the base address of the module.
///
/// # Implementation Details
///
/// Corresponds to `_KLDR_DATA_TABLE_ENTRY.DllBase`.
fn base_address(&self) -> Result<Va, VmiError> {
let KLDR_DATA_TABLE_ENTRY = offset!(self.vmi, _KLDR_DATA_TABLE_ENTRY);
self.vmi
.read_va_native(self.va + KLDR_DATA_TABLE_ENTRY.DllBase.offset())
}
/// Returns the size of the module.
///
/// # Implementation Details
///
/// Corresponds to `_KLDR_DATA_TABLE_ENTRY.SizeOfImage`.
fn size(&self) -> Result<u64, VmiError> {
let KLDR_DATA_TABLE_ENTRY = offset!(self.vmi, _KLDR_DATA_TABLE_ENTRY);
Ok(self
.vmi
.read_u32(self.va + KLDR_DATA_TABLE_ENTRY.SizeOfImage.offset())? as u64)
}
/// Returns the name of the module.
///
/// # Implementation Details
///
/// Corresponds to `_KLDR_DATA_TABLE_ENTRY.BaseDllName`.
///
/// # Notes
///
/// This operation is expected to succeed as the name is allocated from
/// non-paged pool.
fn name(&self) -> Result<String, VmiError> {
let KLDR_DATA_TABLE_ENTRY = offset!(self.vmi, _KLDR_DATA_TABLE_ENTRY);
self.vmi
.os()
.read_unicode_string(self.va + KLDR_DATA_TABLE_ENTRY.BaseDllName.offset())
}
}