wraith/navigation/
module_iter.rs1use super::module::Module;
4use crate::error::{Result, WraithError};
5use crate::structures::ldr::{
6 IN_INITIALIZATION_ORDER_LINKS_OFFSET, IN_LOAD_ORDER_LINKS_OFFSET, IN_MEMORY_ORDER_LINKS_OFFSET,
7};
8use crate::structures::{LdrDataTableEntry, ListEntry, Peb};
9
10pub use crate::error::ModuleListType;
12
13const MAX_MODULES: usize = 4096;
15
16pub struct ModuleIterator<'a> {
18 head: *const ListEntry,
19 current: *const ListEntry,
20 offset: usize,
21 list_type: ModuleListType,
22 iterations: usize,
23 _peb: &'a Peb, }
25
26impl<'a> ModuleIterator<'a> {
27 pub fn new(peb: &'a Peb, list_type: ModuleListType) -> Result<Self> {
29 let ldr = peb.ldr().ok_or(WraithError::NullPointer {
30 context: "PEB.Ldr",
31 })?;
32
33 let (head, offset) = match list_type {
34 ModuleListType::InLoadOrder => (
35 &ldr.in_load_order_module_list as *const ListEntry,
36 IN_LOAD_ORDER_LINKS_OFFSET,
37 ),
38 ModuleListType::InMemoryOrder => (
39 &ldr.in_memory_order_module_list as *const ListEntry,
40 IN_MEMORY_ORDER_LINKS_OFFSET,
41 ),
42 ModuleListType::InInitializationOrder => (
43 &ldr.in_initialization_order_module_list as *const ListEntry,
44 IN_INITIALIZATION_ORDER_LINKS_OFFSET,
45 ),
46 };
47
48 let current = unsafe { (*head).flink };
50
51 Ok(Self {
52 head,
53 current,
54 offset,
55 list_type,
56 iterations: 0,
57 _peb: peb,
58 })
59 }
60
61 pub fn list_type(&self) -> ModuleListType {
63 self.list_type
64 }
65}
66
67impl<'a> Iterator for ModuleIterator<'a> {
68 type Item = Module<'a>;
69
70 fn next(&mut self) -> Option<Self::Item> {
71 if core::ptr::eq(self.current, self.head) {
73 return None;
74 }
75
76 if self.iterations >= MAX_MODULES {
78 return None;
79 }
80 self.iterations += 1;
81
82 if self.current.is_null() {
84 return None;
85 }
86
87 let entry_addr = (self.current as usize) - self.offset;
89 let entry = unsafe { &*(entry_addr as *const LdrDataTableEntry) };
91
92 self.current = unsafe { (*self.current).flink };
94
95 Some(Module::from_entry(entry))
96 }
97}
98
99pub struct InLoadOrderIter<'a>(ModuleIterator<'a>);
101
102impl<'a> InLoadOrderIter<'a> {
103 pub fn new(peb: &'a Peb) -> Result<Self> {
104 Ok(Self(ModuleIterator::new(peb, ModuleListType::InLoadOrder)?))
105 }
106}
107
108impl<'a> Iterator for InLoadOrderIter<'a> {
109 type Item = Module<'a>;
110
111 fn next(&mut self) -> Option<Self::Item> {
112 self.0.next()
113 }
114}
115
116pub struct InMemoryOrderIter<'a>(ModuleIterator<'a>);
118
119impl<'a> InMemoryOrderIter<'a> {
120 pub fn new(peb: &'a Peb) -> Result<Self> {
121 Ok(Self(ModuleIterator::new(
122 peb,
123 ModuleListType::InMemoryOrder,
124 )?))
125 }
126}
127
128impl<'a> Iterator for InMemoryOrderIter<'a> {
129 type Item = Module<'a>;
130
131 fn next(&mut self) -> Option<Self::Item> {
132 self.0.next()
133 }
134}
135
136pub struct InInitializationOrderIter<'a>(ModuleIterator<'a>);
138
139impl<'a> InInitializationOrderIter<'a> {
140 pub fn new(peb: &'a Peb) -> Result<Self> {
141 Ok(Self(ModuleIterator::new(
142 peb,
143 ModuleListType::InInitializationOrder,
144 )?))
145 }
146}
147
148impl<'a> Iterator for InInitializationOrderIter<'a> {
149 type Item = Module<'a>;
150
151 fn next(&mut self) -> Option<Self::Item> {
152 self.0.next()
153 }
154}
155
156pub fn module_count(peb: &Peb) -> Result<usize> {
158 Ok(ModuleIterator::new(peb, ModuleListType::InLoadOrder)?.count())
159}
160
161pub fn collect_modules(peb: &Peb) -> Result<Vec<ModuleInfo>> {
163 let iter = ModuleIterator::new(peb, ModuleListType::InLoadOrder)?;
164 Ok(iter
165 .map(|m| ModuleInfo {
166 name: m.name(),
167 path: m.full_path(),
168 base: m.base(),
169 size: m.size(),
170 entry_point: m.entry_point(),
171 })
172 .collect())
173}
174
175#[derive(Debug, Clone)]
177pub struct ModuleInfo {
178 pub name: String,
179 pub path: String,
180 pub base: usize,
181 pub size: usize,
182 pub entry_point: usize,
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn test_module_count() {
191 let peb = Peb::current().expect("should get PEB");
192 let count = module_count(&peb).expect("should count modules");
193 assert!(count > 0, "should have at least one module");
194 }
195
196 #[test]
197 fn test_collect_modules() {
198 let peb = Peb::current().expect("should get PEB");
199 let modules = collect_modules(&peb).expect("should collect modules");
200 assert!(!modules.is_empty(), "should have modules");
201
202 let first = &modules[0];
204 assert!(first.base > 0, "first module should have valid base");
205 }
206
207 #[test]
208 fn test_all_three_lists() {
209 let peb = Peb::current().expect("should get PEB");
210
211 let load_order: Vec<_> = ModuleIterator::new(&peb, ModuleListType::InLoadOrder)
212 .expect("load order iter")
213 .collect();
214 let memory_order: Vec<_> = ModuleIterator::new(&peb, ModuleListType::InMemoryOrder)
215 .expect("memory order iter")
216 .collect();
217 let init_order: Vec<_> = ModuleIterator::new(&peb, ModuleListType::InInitializationOrder)
218 .expect("init order iter")
219 .collect();
220
221 assert_eq!(
223 load_order.len(),
224 memory_order.len(),
225 "load and memory order should have same count"
226 );
227 assert!(
229 init_order.len() <= load_order.len(),
230 "init order should have <= load order count"
231 );
232 }
233}