1use isr::cache::{IsrCache, JsonCodec};
80use vmi::{
81 VcpuId, VmiCore, VmiError, VmiSession, VmiState, VmiVa as _,
82 arch::amd64::Amd64,
83 driver::kdmp::VmiKdmpDriver,
84 os::{
85 VmiOsMapped as _, VmiOsModule as _, VmiOsProcess as _, VmiOsRegion as _, VmiOsRegionKind,
86 VmiOsThread as _,
87 windows::{WindowsDirectoryObject, WindowsOs, WindowsOsExt, WindowsProcess},
88 },
89};
90
91type Arch = Amd64;
92type Driver = VmiKdmpDriver<Arch>;
93
94fn handle_error(err: VmiError) -> Result<String, VmiError> {
95 match err {
96 VmiError::Translation(pf) => Ok(format!("PF({pf:?})")),
97 _ => Err(err),
98 }
99}
100
101fn enumerate_kernel_modules(vmi: &VmiState<Driver, WindowsOs<Driver>>) -> Result<(), VmiError> {
103 for module in vmi.os().modules()? {
104 let module = module?;
105
106 let module_va = module.va();
107 let base_address = module.base_address()?; let size = module.size()?; let name = module.name()?; let full_name = match module.full_name() {
111 Ok(full_name) => full_name,
113 Err(err) => handle_error(err)?,
114 };
115
116 println!("Module @ {module_va}");
117 println!(" Base Address: {base_address}");
118 println!(" Size: {size}");
119 println!(" Name: {name}");
120 println!(" Full Name: {full_name}");
121 }
122
123 Ok(())
124}
125
126fn enumerate_directory_object(
128 directory_object: &WindowsDirectoryObject<Driver>,
129 level: usize,
130) -> Result<(), VmiError> {
131 for object in directory_object.iter()? {
132 for _ in 0..level {
134 print!(" ");
135 }
136
137 let object = match object {
139 Ok(object) => object,
140 Err(err) => {
141 println!("{}", handle_error(err)?);
142 continue;
143 }
144 };
145
146 let object_va = object.va();
147
148 let type_kind = match object.type_kind() {
150 Ok(Some(typ)) => format!("{typ:?}"),
151 Ok(None) => String::from("<unknown>"),
152 Err(err) => handle_error(err)?,
153 };
154
155 print!("{type_kind}: ");
156
157 let name = match object.full_path() {
159 Ok(Some(name)) => name,
160 Ok(None) => String::from("<unnamed>"),
161 Err(err) => handle_error(err)?,
162 };
163
164 println!("{name} (Object: {object_va})");
165
166 if let Ok(Some(next)) = object.as_directory() {
168 enumerate_directory_object(&next, level + 1)?;
169 }
170 }
171
172 Ok(())
173}
174
175fn enumerate_handle_table(process: &WindowsProcess<Driver>) -> Result<(), VmiError> {
177 const OBJ_PROTECT_CLOSE: u32 = 0x00000001;
178 const OBJ_INHERIT: u32 = 0x00000002;
179 const OBJ_AUDIT_OBJECT_CLOSE: u32 = 0x00000004;
180
181 static LABEL_PROTECTED: [&str; 2] = ["", " (Protected)"];
182 static LABEL_INHERIT: [&str; 2] = ["", " (Inherit)"];
183 static LABEL_AUDIT: [&str; 2] = ["", " (Audit)"];
184
185 let handle_table = match process.handle_table() {
187 Ok(Some(handle_table)) => handle_table,
188 Ok(None) => {
189 println!(" (No handle table)");
190 return Ok(());
191 }
192 Err(err) => {
193 tracing::error!(?err, "Failed to get handle table");
194 return Ok(());
195 }
196 };
197
198 for handle_entry in handle_table.iter()? {
200 let (handle, entry) = match handle_entry {
201 Ok(entry) => entry,
202 Err(err) => {
203 println!("Failed to get handle entry: {}", handle_error(err)?);
204 continue;
205 }
206 };
207
208 let attributes = match entry.attributes() {
209 Ok(attributes) => attributes,
210 Err(err) => {
211 println!("Failed to get attributes: {}", handle_error(err)?);
212 continue;
213 }
214 };
215
216 let granted_access = match entry.granted_access() {
217 Ok(granted_access) => granted_access,
218 Err(err) => {
219 println!("Failed to get granted access: {}", handle_error(err)?);
220 continue;
221 }
222 };
223
224 let object = match entry.object() {
225 Ok(Some(object)) => object,
226 Ok(None) => {
227 println!("<NULL>");
230 continue;
231 }
232 Err(err) => {
233 println!("Failed to get object: {}", handle_error(err)?);
234 continue;
235 }
236 };
237
238 let type_name = match object.type_name() {
239 Ok(type_name) => type_name,
240 Err(err) => handle_error(err)?,
241 };
242
243 let full_path = match object.full_path() {
244 Ok(Some(path)) => path,
245 Ok(None) => String::from("<no-path>"),
246 Err(err) => handle_error(err)?,
247 };
248
249 println!(
250 " {:04x}: Object: {:x} GrantedAccess: {:08x}{}{}{} Entry: {}",
251 handle,
252 object.va().0,
253 granted_access,
254 LABEL_PROTECTED[((attributes & OBJ_PROTECT_CLOSE) != 0) as usize],
255 LABEL_INHERIT[((attributes & OBJ_INHERIT) != 0) as usize],
256 LABEL_AUDIT[((attributes & OBJ_AUDIT_OBJECT_CLOSE) != 0) as usize],
257 entry.va(),
258 );
259
260 println!(" Type: {type_name}, Path: {full_path}");
261 }
262
263 Ok(())
264}
265
266fn enumerate_regions(process: &WindowsProcess<Driver>) -> Result<(), VmiError> {
268 for region in process.regions()? {
269 let region = region?;
270
271 let region_va = region.va();
272 let start = region.start()?;
273 let end = region.end()?;
274 let protection = region.protection()?;
275 let kind = region.kind()?;
276
277 print!(" Region @ {region_va}: {start}-{end} {protection:?}");
278
279 match &kind {
280 VmiOsRegionKind::Private => println!(" Private"),
281 VmiOsRegionKind::MappedImage(mapped) => {
282 let path = match mapped.path() {
283 Ok(Some(path)) => path,
284 Ok(None) => String::from("<Pagefile>"),
285 Err(err) => handle_error(err)?,
286 };
287
288 println!(" Mapped (Exe): {path}");
289 }
290 VmiOsRegionKind::MappedData(mapped) => {
291 let path = match mapped.path() {
292 Ok(Some(path)) => path,
293 Ok(None) => String::from("<Pagefile>"),
294 Err(err) => handle_error(err)?,
295 };
296
297 println!(" Mapped: {path}");
298 }
299 }
300 }
301
302 Ok(())
303}
304
305fn enumerate_threads(process: &WindowsProcess<Driver>) -> Result<(), VmiError> {
307 for thread in process.threads()? {
308 let thread = thread?;
309
310 let tid = thread.id()?;
311 let object = thread.object()?;
312
313 println!(" Thread @ {object}, TID: {tid}");
314 }
315
316 Ok(())
317}
318
319fn print_process_parameters(process: &WindowsProcess<Driver>) -> Result<(), VmiError> {
321 let peb = match process.peb() {
322 Ok(Some(peb)) => peb,
323 Ok(None) => {
324 println!(" (No PEB)");
325 return Ok(());
326 }
327 Err(err) => {
328 println!("Failed to get PEB: {}", handle_error(err)?);
329 return Ok(());
330 }
331 };
332
333 let current_directory = match peb.current_directory() {
334 Ok(current_directory) => current_directory,
335 Err(err) => handle_error(err)?,
336 };
337
338 let dll_path = match peb.dll_path() {
339 Ok(dll_path) => dll_path,
340 Err(err) => handle_error(err)?,
341 };
342
343 let image_path_name = match peb.image_path_name() {
344 Ok(image_path_name) => image_path_name,
345 Err(err) => handle_error(err)?,
346 };
347
348 let command_line = match peb.command_line() {
349 Ok(command_line) => command_line,
350 Err(err) => handle_error(err)?,
351 };
352
353 println!(" Current Directory: {current_directory}");
354 println!(" DLL Path: {dll_path}");
355 println!(" Image Path Name: {image_path_name}");
356 println!(" Command Line: {command_line}");
357
358 Ok(())
359}
360
361fn enumerate_processes(vmi: &VmiState<Driver, WindowsOs<Driver>>) -> Result<(), VmiError> {
363 for process in vmi.os().processes()? {
364 let process = process?;
365
366 let pid = process.id()?; let object = process.object()?; let name = process.name()?; let session = process.session()?; println!("Process @ {object}, PID: {pid}");
372 println!(" Name: {name}");
373 if let Some(session) = session {
374 println!(" Session: {}", session.id()?); }
376
377 println!(" Threads:");
378 enumerate_threads(&process)?;
379
380 println!(" Regions:");
381 enumerate_regions(&process)?;
382
383 println!(" PEB:");
384 print_process_parameters(&process)?;
385
386 println!(" Handles:");
387 enumerate_handle_table(&process)?;
388 }
389
390 Ok(())
391}
392
393fn main() -> Result<(), Box<dyn std::error::Error>> {
394 tracing_subscriber::fmt()
395 .with_max_level(tracing::Level::DEBUG)
396 .with_ansi(false)
397 .init();
398
399 let args = std::env::args().collect::<Vec<_>>();
401 if args.len() != 2 {
402 eprintln!("Usage: {} <dump-file>", args[0]);
403 std::process::exit(1);
404 }
405
406 let dump_file = &args[1];
407
408 let driver = Driver::new(dump_file)?;
410 let core = VmiCore::new(driver)?;
411
412 let registers = core.registers(VcpuId(0))?;
413
414 let kernel_info = WindowsOs::find_kernel(&core, ®isters)?.expect("kernel information");
417 tracing::info!(?kernel_info, "Kernel information");
418
419 let isr = IsrCache::<JsonCodec>::new("cache")?;
422 let entry = isr.entry_from_codeview(kernel_info.codeview)?;
423 let profile = entry.profile()?;
424
425 tracing::info!("Creating VMI session");
427 let os = WindowsOs::<Driver>::with_kernel_base(&profile, kernel_info.base_address)?;
428 let session = VmiSession::new(&core, &os);
429
430 let vmi = session.with_registers(®isters);
431 let root_directory = vmi.os().object_root_directory()?;
432
433 println!("Kernel Modules:");
434 println!("=================================================");
435 enumerate_kernel_modules(&vmi)?;
436
437 println!("Object Tree (root directory: {}):", root_directory.va());
438 println!("=================================================");
439 enumerate_directory_object(&root_directory, 0)?;
440
441 println!("Processes:");
442 println!("=================================================");
443 enumerate_processes(&vmi)?;
444
445 Ok(())
446}