1mod mem_map;
2
3use crate::{
4 offsets::{Win32ArchOffsets, Win32Offsets},
5 prelude::{VirtualReadUnicodeString, Win32ExitStatus, EXIT_STATUS_STILL_ACTIVE},
6};
7
8use super::{
9 process::IMAGE_FILE_NAME_LENGTH, Win32KernelBuilder, Win32KernelInfo, Win32Keyboard,
10 Win32ModuleListInfo, Win32Process, Win32ProcessInfo, Win32VirtualTranslate,
11};
12
13use memflow::mem::virt_translate::*;
14use memflow::prelude::v1::{Result, *};
15
16#[cfg(feature = "plugins")]
17use memflow::cglue;
18#[cfg(feature = "plugins")]
19use memflow::mem::{memory_view::*, phys_mem::*};
20#[cfg(feature = "plugins")]
21use memflow::os::keyboard::*;
22
23use log::{info, trace};
24use std::convert::TryInto;
25use std::fmt;
26use std::prelude::v1::*;
27
28use pelite::{self, pe64::exports::Export, PeView};
29
30const MAX_ITER_COUNT: usize = 65536;
31
32#[cfg(feature = "plugins")]
33cglue_impl_group!(Win32Kernel<T, V>, OsInstance<'a>, { PhysicalMemory, MemoryView, VirtualTranslate, OsKeyboard });
34
35#[derive(Clone)]
36pub struct Win32Kernel<T, V> {
37 pub virt_mem: VirtualDma<T, V, Win32VirtualTranslate>,
38 pub offsets: Win32Offsets,
39
40 pub kernel_info: Win32KernelInfo,
41 pub sysproc_dtb: Address,
42
43 pub kernel_modules: Option<Win32ModuleListInfo>,
44}
45
46impl<T: 'static + PhysicalMemory + Clone, V: 'static + VirtualTranslate2 + Clone>
47 Win32Kernel<T, V>
48{
49 pub fn new(phys_mem: T, vat: V, offsets: Win32Offsets, kernel_info: Win32KernelInfo) -> Self {
50 let mut virt_mem = VirtualDma::with_vat(
51 phys_mem,
52 kernel_info.os_info.arch,
53 Win32VirtualTranslate::new(kernel_info.os_info.arch, kernel_info.dtb),
54 vat,
55 );
56
57 if offsets.phys_mem_block() != 0 {
58 match kernel_info.os_info.arch.into_obj().bits() {
59 32 => {
60 if let Some(mem_map) = mem_map::parse::<_, u32>(
61 &mut virt_mem,
62 kernel_info.os_info.base + offsets.phys_mem_block(),
63 ) {
64 info!("updating connector mem_map={:?}", mem_map);
66 let (mut phys_mem, vat) = virt_mem.into_inner();
67 phys_mem.set_mem_map(mem_map.into_vec().as_slice());
68 virt_mem = VirtualDma::with_vat(
69 phys_mem,
70 kernel_info.os_info.arch,
71 Win32VirtualTranslate::new(kernel_info.os_info.arch, kernel_info.dtb),
72 vat,
73 );
74 }
75 }
76 64 => {
77 if let Some(mem_map) = mem_map::parse::<_, u64>(
78 &mut virt_mem,
79 kernel_info.os_info.base + offsets.phys_mem_block(),
80 ) {
81 info!("updating connector mem_map={:?}", mem_map);
83 let (mut phys_mem, vat) = virt_mem.into_inner();
84 phys_mem.set_mem_map(mem_map.into_vec().as_slice());
85 virt_mem = VirtualDma::with_vat(
86 phys_mem,
87 kernel_info.os_info.arch,
88 Win32VirtualTranslate::new(kernel_info.os_info.arch, kernel_info.dtb),
89 vat,
90 );
91 }
92 }
93 _ => {}
94 }
95 }
96
97 let sysproc_dtb = if let Some(Some(dtb)) = virt_mem
102 .read_addr_arch(
103 kernel_info.os_info.arch.into(),
104 kernel_info.eprocess_base + offsets.kproc_dtb(),
105 )
106 .ok()
107 .map(|a| a.as_page_aligned(4096).non_null())
108 {
109 info!("updating sysproc_dtb={:x}", dtb);
110 let (phys_mem, vat) = virt_mem.into_inner();
111 virt_mem = VirtualDma::with_vat(
112 phys_mem,
113 kernel_info.os_info.arch,
114 Win32VirtualTranslate::new(kernel_info.os_info.arch, dtb),
115 vat,
116 );
117 dtb
118 } else {
119 kernel_info.dtb
120 };
121
122 Self {
123 virt_mem,
124 offsets,
125
126 kernel_info,
127 sysproc_dtb,
128 kernel_modules: None,
129 }
130 }
131
132 pub fn kernel_modules(&mut self) -> Result<Win32ModuleListInfo> {
133 if let Some(info) = self.kernel_modules {
134 Ok(info)
135 } else {
136 let image = self.virt_mem.read_raw(
137 self.kernel_info.os_info.base,
138 self.kernel_info.os_info.size.try_into().unwrap(),
139 )?;
140 let pe = PeView::from_bytes(&image).map_err(|err| {
141 Error(ErrorOrigin::OsLayer, ErrorKind::InvalidExeFile).log_info(err)
142 })?;
143 let addr = match pe.get_export_by_name("PsLoadedModuleList").map_err(|err| {
144 Error(ErrorOrigin::OsLayer, ErrorKind::ExportNotFound).log_info(err)
145 })? {
146 Export::Symbol(s) => self.kernel_info.os_info.base + *s as umem,
147 Export::Forward(_) => {
148 return Err(Error(ErrorOrigin::OsLayer, ErrorKind::ExportNotFound)
149 .log_info("PsLoadedModuleList found but it was a forwarded export"))
150 }
151 };
152
153 let addr = self
154 .virt_mem
155 .read_addr_arch(self.kernel_info.os_info.arch.into(), addr)?;
156
157 let info = Win32ModuleListInfo::with_base(addr, self.kernel_info.os_info.arch)?;
158
159 self.kernel_modules = Some(info);
160 Ok(info)
161 }
162 }
163
164 pub fn into_inner(self) -> (T, V) {
166 self.virt_mem.into_inner()
167 }
168
169 pub fn kernel_process_info(&mut self) -> Result<Win32ProcessInfo> {
170 let kernel_modules = self.kernel_modules()?;
171
172 let vad_root = self.read_addr_arch(
173 self.kernel_info.os_info.arch.into(),
174 self.kernel_info.os_info.base + self.offsets.eproc_vad_root(),
175 )?;
176
177 Ok(Win32ProcessInfo {
178 base_info: ProcessInfo {
179 address: self.kernel_info.os_info.base,
180 pid: 0,
181 state: ProcessState::Alive,
182 name: "ntoskrnl.exe".into(),
183 path: "".into(),
184 command_line: "".into(),
185 sys_arch: self.kernel_info.os_info.arch,
186 proc_arch: self.kernel_info.os_info.arch,
187 dtb1: self.sysproc_dtb,
188 dtb2: Address::invalid(),
189 },
190 section_base: Address::NULL, ethread: Address::NULL, wow64: Address::NULL,
193
194 teb: None,
195 teb_wow64: None,
196
197 peb_native: None,
198 peb_wow64: None,
199
200 module_info_native: Some(kernel_modules),
201 module_info_wow64: None,
202
203 vad_root,
204 })
205 }
206
207 pub fn process_info_from_base_info(
208 &mut self,
209 base_info: ProcessInfo,
210 ) -> Result<Win32ProcessInfo> {
211 let section_base = self.virt_mem.read_addr_arch(
212 self.kernel_info.os_info.arch.into(),
213 base_info.address + self.offsets.eproc_section_base(),
214 )?;
215 trace!("section_base={:x}", section_base);
216
217 let ethread = self.virt_mem.read_addr_arch(
219 self.kernel_info.os_info.arch.into(),
220 base_info.address + self.offsets.eproc_thread_list(),
221 )? - self.offsets.ethread_list_entry();
222 trace!("ethread={:x}", ethread);
223
224 let peb_native = self
225 .virt_mem
226 .read_addr_arch(
227 self.kernel_info.os_info.arch.into(),
228 base_info.address + self.offsets.eproc_peb(),
229 )?
230 .non_null();
231
232 let wow64 = if self.offsets.eproc_wow64() == 0 {
234 trace!("eproc_wow64=null; skipping wow64 detection");
235 Address::null()
236 } else {
237 trace!(
238 "eproc_wow64={:x}; trying to read wow64 pointer",
239 self.offsets.eproc_wow64()
240 );
241 self.virt_mem.read_addr_arch(
242 self.kernel_info.os_info.arch.into(),
243 base_info.address + self.offsets.eproc_wow64(),
244 )?
245 };
246 trace!("wow64={:x}", wow64);
247
248 let mut peb_wow64 = None;
249
250 let (teb, teb_wow64) = if self.kernel_info.kernel_winver >= (6, 2).into() {
252 let teb = self.virt_mem.read_addr_arch(
253 self.kernel_info.os_info.arch.into(),
254 ethread + self.offsets.kthread_teb(),
255 )?;
256
257 trace!("teb={:x}", teb);
258
259 if !teb.is_null() {
260 (
261 Some(teb),
262 if base_info.proc_arch == base_info.sys_arch {
263 None
264 } else {
265 Some(teb + 0x2000)
266 },
267 )
268 } else {
269 (None, None)
270 }
271 } else {
272 (None, None)
273 };
274
275 let vad_root = self.virt_mem.read_addr_arch(
276 self.kernel_info.os_info.arch.into(),
277 base_info.address + self.offsets.eproc_vad_root(),
278 )?;
279
280 let (phys_mem, vat) = self.virt_mem.mem_vat_pair();
283 let mut proc_reader = VirtualDma::with_vat(
284 phys_mem.forward_mut(),
285 base_info.proc_arch,
286 Win32VirtualTranslate::new(self.kernel_info.os_info.arch, base_info.dtb1),
287 vat,
288 );
289
290 if let Some(teb) = teb_wow64 {
291 peb_wow64 = proc_reader
294 .read_addr_arch(
295 self.kernel_info.os_info.arch.into(),
296 teb + self.offsets.teb_peb_x86(),
297 )?
298 .non_null();
299
300 trace!("peb_wow64={:?}", peb_wow64);
301 }
302
303 trace!("peb_native={:?}", peb_native);
304
305 let module_info_native = peb_native
306 .map(|peb| Win32ModuleListInfo::with_peb(&mut proc_reader, peb, base_info.sys_arch))
307 .transpose()?;
308
309 let module_info_wow64 = peb_wow64
310 .map(|peb| Win32ModuleListInfo::with_peb(&mut proc_reader, peb, base_info.proc_arch))
311 .transpose()?;
312
313 Ok(Win32ProcessInfo {
314 base_info,
315
316 section_base,
317 ethread,
318 wow64,
319
320 teb,
321 teb_wow64,
322
323 peb_native,
324 peb_wow64,
325
326 module_info_native,
327 module_info_wow64,
328
329 vad_root,
330 })
331 }
332
333 fn process_info_fill(&mut self, info: Win32ProcessInfo) -> Result<Win32ProcessInfo> {
334 let cloned_base = info.base_info.clone();
336 let mut name = info.base_info.name.clone();
337 let callback = &mut |m: ModuleInfo| {
338 if m.name.as_ref().starts_with(name.as_ref()) {
339 name = m.name;
340 false
341 } else {
342 true
343 }
344 };
345 let sys_arch = info.base_info.sys_arch;
346 let mut process = self.process_by_info(cloned_base)?;
347 process.module_list_callback(Some(&sys_arch), callback.into())?;
348
349 let offsets = Win32ArchOffsets::from(info.base_info.proc_arch);
351 let (path, command_line) = if let Some(Ok(peb_process_params)) = info.peb().map(|peb| {
352 process.read_addr_arch(
353 info.base_info.proc_arch.into(),
354 peb + offsets.peb_process_params,
355 )
356 }) {
357 trace!("peb_process_params={:x}", peb_process_params);
358 let image_path_name = process
359 .read_unicode_string(
360 info.base_info.proc_arch.into(),
361 peb_process_params + offsets.ppm_image_path_name,
362 )
363 .unwrap_or_default();
364
365 let command_line = process
366 .read_unicode_string(
367 info.base_info.proc_arch.into(),
368 peb_process_params + offsets.ppm_command_line,
369 )
370 .unwrap_or_default();
371
372 (image_path_name.into(), command_line.into())
373 } else {
374 ("".into(), "".into())
375 };
376
377 Ok(Win32ProcessInfo {
378 base_info: ProcessInfo {
379 name,
380 path,
381 command_line,
382 ..info.base_info
383 },
384 ..info
385 })
386 }
387
388 fn process_info_base_by_address(&mut self, address: Address) -> Result<ProcessInfo> {
389 let dtb = self.virt_mem.read_addr_arch(
390 self.kernel_info.os_info.arch.into(),
391 address + self.offsets.kproc_dtb(),
392 )?;
393 trace!("dtb={:x}", dtb);
394
395 let pid: Pid = self.virt_mem.read(address + self.offsets.eproc_pid())?;
396 trace!("pid={}", pid);
397
398 let state = if let Ok(exit_status) = self
399 .virt_mem
400 .read::<Win32ExitStatus>(address + self.offsets.eproc_exit_status())
401 {
402 if exit_status == EXIT_STATUS_STILL_ACTIVE {
403 ProcessState::Alive
404 } else {
405 ProcessState::Dead(exit_status)
406 }
407 } else {
408 ProcessState::Unknown
409 };
410
411 let name: ReprCString = self
412 .virt_mem
413 .read_char_array(address + self.offsets.eproc_name(), IMAGE_FILE_NAME_LENGTH)?
414 .into();
415 trace!("name={}", name);
416
417 let wow64 = if self.offsets.eproc_wow64() == 0 {
418 trace!("eproc_wow64=null; skipping wow64 detection");
419 Address::null()
420 } else {
421 trace!(
422 "eproc_wow64={:x}; trying to read wow64 pointer",
423 self.offsets.eproc_wow64()
424 );
425 self.virt_mem.read_addr_arch(
426 self.kernel_info.os_info.arch.into(),
427 address + self.offsets.eproc_wow64(),
428 )?
429 };
430 trace!("wow64={:x}", wow64);
431
432 let sys_arch = self.kernel_info.os_info.arch;
434 trace!("sys_arch={:?}", sys_arch);
435 let proc_arch = match ArchitectureObj::from(sys_arch).bits() {
436 64 => {
437 if wow64.is_null() {
438 sys_arch
439 } else {
440 ArchitectureIdent::X86(32, true)
441 }
442 }
443 32 => sys_arch,
444 _ => return Err(Error(ErrorOrigin::OsLayer, ErrorKind::InvalidArchitecture)),
445 };
446 trace!("proc_arch={:?}", proc_arch);
447
448 Ok(ProcessInfo {
449 address,
450 pid,
451 state,
452 name,
453 path: "".into(),
454 command_line: "".into(),
455 sys_arch,
456 proc_arch,
457 dtb1: dtb,
458 dtb2: Address::invalid(),
459 })
460 }
461}
462
463impl<T: PhysicalMemory> Win32Kernel<T, DirectTranslate> {
464 pub fn builder(connector: T) -> Win32KernelBuilder<T, T, DirectTranslate> {
465 Win32KernelBuilder::<T, T, DirectTranslate>::new(connector)
466 }
467}
468
469impl<T: PhysicalMemory, V: VirtualTranslate2> AsMut<T> for Win32Kernel<T, V> {
470 fn as_mut(&mut self) -> &mut T {
471 self.virt_mem.phys_mem()
472 }
473}
474
475impl<T: PhysicalMemory, V: VirtualTranslate2> AsMut<VirtualDma<T, V, Win32VirtualTranslate>>
476 for Win32Kernel<T, V>
477{
478 fn as_mut(&mut self) -> &mut VirtualDma<T, V, Win32VirtualTranslate> {
479 &mut self.virt_mem
480 }
481}
482
483impl<T: PhysicalMemory, V: VirtualTranslate2> PhysicalMemory for Win32Kernel<T, V> {
484 fn phys_read_raw_iter(&mut self, data: PhysicalReadMemOps) -> Result<()> {
485 self.virt_mem.phys_mem().phys_read_raw_iter(data)
486 }
487
488 fn phys_write_raw_iter(&mut self, data: PhysicalWriteMemOps) -> Result<()> {
489 self.virt_mem.phys_mem().phys_write_raw_iter(data)
490 }
491
492 fn metadata(&self) -> PhysicalMemoryMetadata {
493 self.virt_mem.phys_mem_ref().metadata()
494 }
495
496 fn set_mem_map(&mut self, mem_map: &[PhysicalMemoryMapping]) {
497 self.virt_mem.phys_mem().set_mem_map(mem_map)
498 }
499}
500
501impl<T: PhysicalMemory, V: VirtualTranslate2> MemoryView for Win32Kernel<T, V> {
502 fn read_raw_iter(&mut self, data: ReadRawMemOps) -> Result<()> {
503 self.virt_mem.read_raw_iter(data)
504 }
505
506 fn write_raw_iter(&mut self, data: WriteRawMemOps) -> Result<()> {
507 self.virt_mem.write_raw_iter(data)
508 }
509
510 fn metadata(&self) -> MemoryViewMetadata {
511 self.virt_mem.metadata()
512 }
513}
514
515impl<T: PhysicalMemory, V: VirtualTranslate2> VirtualTranslate for Win32Kernel<T, V> {
516 fn virt_to_phys_list(
517 &mut self,
518 addrs: &[VtopRange],
519 out: VirtualTranslationCallback,
520 out_fail: VirtualTranslationFailCallback,
521 ) {
522 self.virt_mem.virt_to_phys_list(addrs, out, out_fail)
523 }
524}
525
526impl<T: 'static + PhysicalMemory + Clone, V: 'static + VirtualTranslate2 + Clone> Os
527 for Win32Kernel<T, V>
528{
529 type ProcessType<'a> = Win32Process<Fwd<&'a mut T>, Fwd<&'a mut V>, Win32VirtualTranslate>;
530 type IntoProcessType = Win32Process<T, V, Win32VirtualTranslate>;
531
532 fn process_address_list_callback(
536 &mut self,
537 mut callback: AddressCallback,
538 ) -> memflow::error::Result<()> {
539 let list_start = self.kernel_info.eprocess_base + self.offsets.eproc_link();
540 let mut list_entry = list_start;
541
542 for _ in 0..MAX_ITER_COUNT {
543 let eprocess = list_entry - self.offsets.eproc_link();
544 trace!("eprocess={}", eprocess);
545
546 let flink_entry = self
548 .virt_mem
549 .read_addr_arch(self.kernel_info.os_info.arch.into(), list_entry)?;
550 trace!("flink_entry={}", flink_entry);
551 let blink_entry = self.virt_mem.read_addr_arch(
552 self.kernel_info.os_info.arch.into(),
553 list_entry + self.offsets.list_blink(),
554 )?;
555 trace!("blink_entry={}", blink_entry);
556
557 if flink_entry.is_null()
558 || blink_entry.is_null()
559 || flink_entry == list_start
560 || flink_entry == list_entry
561 {
562 break;
563 }
564
565 trace!("found eprocess {:x}", eprocess);
566 if !callback.call(eprocess) {
567 break;
568 }
569 trace!("Continuing {:x} -> {:x}", list_entry, flink_entry);
570
571 list_entry = flink_entry;
573 }
574
575 Ok(())
576 }
577
578 fn process_info_by_address(&mut self, address: Address) -> memflow::error::Result<ProcessInfo> {
580 let base_info = self.process_info_base_by_address(address)?;
581 if let Ok(info) = self.process_info_from_base_info(base_info.clone()) {
582 Ok(self.process_info_fill(info)?.base_info)
583 } else {
584 Ok(base_info)
585 }
586 }
587
588 fn process_by_info(
592 &mut self,
593 info: ProcessInfo,
594 ) -> memflow::error::Result<Self::ProcessType<'_>> {
595 let proc_info = self.process_info_from_base_info(info)?;
596 Ok(Win32Process::with_kernel_ref(self, proc_info))
597 }
598
599 fn into_process_by_info(
607 mut self,
608 info: ProcessInfo,
609 ) -> memflow::error::Result<Self::IntoProcessType> {
610 let proc_info = self.process_info_from_base_info(info)?;
611 Ok(Win32Process::with_kernel(self, proc_info))
612 }
613
614 fn module_address_list_callback(
620 &mut self,
621 callback: AddressCallback,
622 ) -> memflow::error::Result<()> {
623 self.kernel_modules()?
624 .module_entry_list_callback::<Self, VirtualDma<T, V, Win32VirtualTranslate>>(
625 self,
626 self.kernel_info.os_info.arch,
627 callback,
628 )
629 .map_err(From::from)
630 }
631
632 fn module_by_address(&mut self, address: Address) -> memflow::error::Result<ModuleInfo> {
637 self.kernel_modules()?
638 .module_info_from_entry(
639 address,
640 self.kernel_info.eprocess_base,
641 &mut self.virt_mem,
642 self.kernel_info.os_info.arch,
643 )
644 .map_err(From::from)
645 }
646
647 fn primary_module_address(&mut self) -> Result<Address> {
651 Ok(self.module_by_name("ntoskrnl.exe")?.address)
652 }
653
654 fn primary_module(&mut self) -> Result<ModuleInfo> {
658 self.module_by_name("ntoskrnl.exe")
659 }
660
661 fn module_import_list_callback(
663 &mut self,
664 info: &ModuleInfo,
665 callback: ImportCallback,
666 ) -> Result<()> {
667 memflow::os::util::module_import_list_callback(&mut self.virt_mem, info, callback)
668 }
669
670 fn module_export_list_callback(
672 &mut self,
673 info: &ModuleInfo,
674 callback: ExportCallback,
675 ) -> Result<()> {
676 memflow::os::util::module_export_list_callback(&mut self.virt_mem, info, callback)
677 }
678
679 fn module_section_list_callback(
681 &mut self,
682 info: &ModuleInfo,
683 callback: SectionCallback,
684 ) -> Result<()> {
685 memflow::os::util::module_section_list_callback(&mut self.virt_mem, info, callback)
686 }
687
688 fn info(&self) -> &OsInfo {
690 &self.kernel_info.os_info
691 }
692}
693
694impl<T: 'static + PhysicalMemory + Clone, V: 'static + VirtualTranslate2 + Clone> OsKeyboard
695 for Win32Kernel<T, V>
696{
697 type KeyboardType<'a> =
698 Win32Keyboard<VirtualDma<Fwd<&'a mut T>, Fwd<&'a mut V>, Win32VirtualTranslate>>;
699 type IntoKeyboardType = Win32Keyboard<VirtualDma<T, V, Win32VirtualTranslate>>;
700
701 fn keyboard(&mut self) -> memflow::error::Result<Self::KeyboardType<'_>> {
702 Win32Keyboard::with_kernel_ref(self)
703 }
704
705 fn into_keyboard(self) -> memflow::error::Result<Self::IntoKeyboardType> {
706 Win32Keyboard::with_kernel(self)
707 }
708}
709
710impl<T: PhysicalMemory, V: VirtualTranslate2> fmt::Debug for Win32Kernel<T, V> {
711 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
712 write!(f, "{:?}", self.kernel_info)
713 }
714}