wraith/structures/
ldr.rs

1//! LDR_DATA_TABLE_ENTRY and PEB_LDR_DATA structures
2
3use super::list_entry::ListEntry;
4use super::unicode_string::UnicodeString;
5use crate::arch::NativePtr;
6
7/// PEB_LDR_DATA - contains the module lists
8#[repr(C)]
9pub struct PebLdrData {
10    pub length: u32,
11    pub initialized: u8,
12    pub ss_handle: NativePtr,
13    pub in_load_order_module_list: ListEntry,
14    pub in_memory_order_module_list: ListEntry,
15    pub in_initialization_order_module_list: ListEntry,
16    pub entry_in_progress: NativePtr,
17    pub shutdown_in_progress: u8,
18    pub shutdown_thread_id: NativePtr,
19}
20
21/// LDR_DATA_TABLE_ENTRY - represents a loaded module
22///
23/// this is a simplified version; full structure has more fields
24/// that vary by Windows version
25#[repr(C)]
26pub struct LdrDataTableEntry {
27    pub in_load_order_links: ListEntry,
28    pub in_memory_order_links: ListEntry,
29    pub in_initialization_order_links: ListEntry,
30    pub dll_base: NativePtr,
31    pub entry_point: NativePtr,
32    pub size_of_image: u32,
33    pub full_dll_name: UnicodeString,
34    pub base_dll_name: UnicodeString,
35    // additional fields vary by Windows version
36    // these are accessed via offsets when needed
37}
38
39impl LdrDataTableEntry {
40    /// get module base address
41    pub fn base(&self) -> usize {
42        self.dll_base as usize
43    }
44
45    /// get module size
46    pub fn size(&self) -> usize {
47        self.size_of_image as usize
48    }
49
50    /// get entry point address
51    pub fn entry_point(&self) -> usize {
52        self.entry_point as usize
53    }
54
55    /// get full path as String
56    ///
57    /// # Safety
58    /// full_dll_name buffer must be valid
59    pub unsafe fn full_name(&self) -> String {
60        unsafe { self.full_dll_name.to_string() }
61    }
62
63    /// get base name (filename only) as String
64    ///
65    /// # Safety
66    /// base_dll_name buffer must be valid
67    pub unsafe fn base_name(&self) -> String {
68        unsafe { self.base_dll_name.to_string() }
69    }
70
71    /// check if address is within this module
72    pub fn contains_address(&self, addr: usize) -> bool {
73        let base = self.base();
74        addr >= base && addr < base + self.size()
75    }
76
77    /// check if this module matches a name (case-insensitive)
78    ///
79    /// # Safety
80    /// name buffers must be valid
81    pub unsafe fn matches_name(&self, name: &str) -> bool {
82        unsafe { self.base_dll_name.eq_ignore_case(name) }
83    }
84}
85
86/// offset of InLoadOrderLinks within LDR_DATA_TABLE_ENTRY
87pub const IN_LOAD_ORDER_LINKS_OFFSET: usize = 0;
88
89/// offset of InMemoryOrderLinks within LDR_DATA_TABLE_ENTRY
90#[cfg(target_arch = "x86_64")]
91pub const IN_MEMORY_ORDER_LINKS_OFFSET: usize = 0x10;
92
93#[cfg(target_arch = "x86")]
94pub const IN_MEMORY_ORDER_LINKS_OFFSET: usize = 0x08;
95
96/// offset of InInitializationOrderLinks within LDR_DATA_TABLE_ENTRY
97#[cfg(target_arch = "x86_64")]
98pub const IN_INITIALIZATION_ORDER_LINKS_OFFSET: usize = 0x20;
99
100#[cfg(target_arch = "x86")]
101pub const IN_INITIALIZATION_ORDER_LINKS_OFFSET: usize = 0x10;