memflow_win32_defs/offsets/
mod.rs1pub mod builder;
2pub use builder::Win32OffsetBuilder;
3
4#[cfg(feature = "symstore")]
5pub mod pdb;
6#[cfg(feature = "symstore")]
7pub mod symstore;
8
9pub mod offset_table;
10#[doc(hidden)]
11pub use offset_table::{
12 MmVadOffsetTable, Win32OffsetFile, Win32OffsetHeader, Win32OffsetTable,
13 Win32OffsetsArchitecture,
14};
15
16#[cfg(feature = "symstore")]
17pub use {
18 self::pdb::{PdbStruct, PdbSymbols},
19 symstore::*,
20};
21
22use std::prelude::v1::*;
23
24use memflow::architecture::ArchitectureIdent;
25
26#[cfg(feature = "std")]
28use crate::kernel::Win32Guid;
29#[cfg(feature = "std")]
30use memflow::error::{Error, ErrorKind, ErrorOrigin, Result};
31#[cfg(feature = "std")]
32use std::{fs::File, io::Read, path::Path};
33
34#[derive(Debug, Copy, Clone)]
35#[repr(C)]
36#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
37pub struct Win32ArchOffsets {
38 pub peb_ldr: usize, pub peb_process_params: usize, pub ldr_list: usize, pub ldr_data_base: usize, pub ldr_data_size: usize, pub ldr_data_full_name: usize, pub ldr_data_base_name: usize, pub ppm_image_path_name: usize, pub ppm_command_line: usize, }
48
49pub const X86: Win32ArchOffsets = Win32ArchOffsets {
50 peb_ldr: 0xc,
51 peb_process_params: 0x10,
52 ldr_list: 0xc,
53 ldr_data_base: 0x18,
54 ldr_data_size: 0x20,
55 ldr_data_full_name: 0x24,
56 ldr_data_base_name: 0x2c,
57 ppm_image_path_name: 0x38,
58 ppm_command_line: 0x40,
59};
60
61pub const X64: Win32ArchOffsets = Win32ArchOffsets {
62 peb_ldr: 0x18,
63 peb_process_params: 0x20,
64 ldr_list: 0x10,
65 ldr_data_base: 0x30,
66 ldr_data_size: 0x40,
67 ldr_data_full_name: 0x48,
68 ldr_data_base_name: 0x58,
69 ppm_image_path_name: 0x60,
70 ppm_command_line: 0x70,
71};
72
73pub const AARCH64: Win32ArchOffsets = Win32ArchOffsets {
74 peb_ldr: 0x18,
75 peb_process_params: 0x20,
76 ldr_list: 0x10,
77 ldr_data_base: 0x30,
78 ldr_data_size: 0x40,
79 ldr_data_full_name: 0x48,
80 ldr_data_base_name: 0x58,
81 ppm_image_path_name: 0x60,
82 ppm_command_line: 0x70,
83};
84
85impl Win32OffsetsArchitecture {
86 #[inline]
87 fn offsets(&self) -> &'static Win32ArchOffsets {
88 match self {
89 Win32OffsetsArchitecture::X64 => &X64,
90 Win32OffsetsArchitecture::X86 => &X86,
91 Win32OffsetsArchitecture::AArch64 => &AARCH64,
92 }
93 }
94}
95
96impl From<ArchitectureIdent> for Win32ArchOffsets {
97 fn from(arch: ArchitectureIdent) -> Win32ArchOffsets {
98 *Win32OffsetsArchitecture::from(arch).offsets()
99 }
100}
101
102#[repr(transparent)]
103#[derive(Debug, Clone)]
104#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
105pub struct Win32Offsets(pub Win32OffsetTable);
106
107impl From<Win32OffsetTable> for Win32Offsets {
108 fn from(other: Win32OffsetTable) -> Self {
109 Self(other)
110 }
111}
112
113impl From<Win32Offsets> for Win32OffsetTable {
114 fn from(other: Win32Offsets) -> Self {
115 other.0
116 }
117}
118
119impl From<ArchitectureIdent> for Win32OffsetsArchitecture {
120 fn from(arch: ArchitectureIdent) -> Win32OffsetsArchitecture {
121 match arch {
122 ArchitectureIdent::X86(32, _) => Self::X86,
123 ArchitectureIdent::X86(64, _) => Self::X64,
124 ArchitectureIdent::AArch64(_) => Self::AArch64,
125 _ => panic!("Invalid architecture specified"),
126 }
127 }
128}
129
130impl Win32Offsets {
131 #[cfg(feature = "symstore")]
132 pub fn from_pdb<P: AsRef<Path>>(pdb_path: P) -> Result<Self> {
133 let mut file = File::open(pdb_path).map_err(|_| {
134 Error(ErrorOrigin::OsLayer, ErrorKind::Offset)
135 .log_warn("unable to open user-supplied pdb file")
136 })?;
137 let mut buffer = Vec::new();
138 file.read_to_end(&mut buffer).map_err(|_| {
139 Error(ErrorOrigin::OsLayer, ErrorKind::Offset)
140 .log_warn("unable to read user-supplied pdb file")
141 })?;
142 Self::from_pdb_slice(&buffer[..])
143 }
144
145 #[cfg(feature = "symstore")]
146 pub fn from_pdb_slice(pdb_slice: &[u8]) -> Result<Self> {
147 let symbols = PdbSymbols::new(pdb_slice).map_err(|_| {
148 Error(ErrorOrigin::OsLayer, ErrorKind::Offset).log_warn("Symbols not found")
149 })?;
150 let list = PdbStruct::new(pdb_slice, "_LIST_ENTRY").map_err(|_| {
151 Error(ErrorOrigin::OsLayer, ErrorKind::Offset).log_warn("_LIST_ENTRY not found")
152 })?;
153 let kproc = PdbStruct::new(pdb_slice, "_KPROCESS").map_err(|_| {
154 Error(ErrorOrigin::OsLayer, ErrorKind::Offset).log_warn("_KPROCESS not found")
155 })?;
156 let eproc = PdbStruct::new(pdb_slice, "_EPROCESS").map_err(|_| {
157 Error(ErrorOrigin::OsLayer, ErrorKind::Offset).log_warn("_EPROCESS not found")
158 })?;
159 let ethread = PdbStruct::new(pdb_slice, "_ETHREAD").map_err(|_| {
160 Error(ErrorOrigin::OsLayer, ErrorKind::Offset).log_warn("_ETHREAD not found")
161 })?;
162 let kthread = PdbStruct::new(pdb_slice, "_KTHREAD").map_err(|_| {
163 Error(ErrorOrigin::OsLayer, ErrorKind::Offset).log_warn("_KTHREAD not found")
164 })?;
165 let teb = PdbStruct::new(pdb_slice, "_TEB").map_err(|_| {
166 Error(ErrorOrigin::OsLayer, ErrorKind::Offset).log_warn("_TEB not found")
167 })?;
168 let mm_vad = PdbStruct::new(pdb_slice, "_MMVAD_SHORT").map_err(|_| {
169 Error(ErrorOrigin::OsLayer, ErrorKind::Offset).log_warn("_MMVAD_SHORT not found")
170 })?;
171 let mm_vad_flags = PdbStruct::new(pdb_slice, "_MMVAD_FLAGS").map_err(|_| {
172 Error(ErrorOrigin::OsLayer, ErrorKind::Offset).log_warn("_MMVAD_FLAGS not found")
173 })?;
174
175 let phys_mem_block = symbols
176 .find_symbol("MmPhysicalMemoryBlock")
177 .or_else(|| symbols.find_symbol("_MmPhysicalMemoryBlock"))
178 .copied()
179 .unwrap_or(0);
180
181 let list_blink = list
182 .find_field("Blink")
183 .ok_or_else(|| {
184 Error(ErrorOrigin::OsLayer, ErrorKind::Offset)
185 .log_warn("_LIST_ENTRY::Blink not found")
186 })?
187 .offset as _;
188
189 let eproc_link = eproc
190 .find_field("ActiveProcessLinks")
191 .ok_or_else(|| {
192 Error(ErrorOrigin::OsLayer, ErrorKind::Offset)
193 .log_warn("_EPROCESS::ActiveProcessLinks not found")
194 })?
195 .offset as _;
196
197 let kproc_dtb = kproc
198 .find_field("DirectoryTableBase")
199 .ok_or_else(|| {
200 Error(ErrorOrigin::OsLayer, ErrorKind::Offset)
201 .log_warn("_KPROCESS::DirectoryTableBase not found")
202 })?
203 .offset as _;
204 let eproc_pid = eproc
205 .find_field("UniqueProcessId")
206 .ok_or_else(|| {
207 Error(ErrorOrigin::OsLayer, ErrorKind::Offset)
208 .log_warn("_EPROCESS::UniqueProcessId not found")
209 })?
210 .offset as _;
211 let eproc_name = eproc
212 .find_field("ImageFileName")
213 .ok_or_else(|| {
214 Error(ErrorOrigin::OsLayer, ErrorKind::Offset)
215 .log_warn("_EPROCESS::ImageFileName not found")
216 })?
217 .offset as _;
218 let eproc_peb = eproc
219 .find_field("Peb")
220 .ok_or_else(|| {
221 Error(ErrorOrigin::OsLayer, ErrorKind::Offset).log_warn("_EPROCESS::Peb not found")
222 })?
223 .offset as _;
224 let eproc_section_base = eproc
225 .find_field("SectionBaseAddress")
226 .ok_or_else(|| {
227 Error(ErrorOrigin::OsLayer, ErrorKind::Offset)
228 .log_warn("_EPROCESS::SectionBaseAddress not found")
229 })?
230 .offset as _;
231 let eproc_exit_status = eproc
232 .find_field("ExitStatus")
233 .ok_or_else(|| {
234 Error(ErrorOrigin::OsLayer, ErrorKind::Offset)
235 .log_warn("_EPROCESS::ExitStatus not found")
236 })?
237 .offset as _;
238 let eproc_thread_list = eproc
239 .find_field("ThreadListHead")
240 .ok_or_else(|| {
241 Error(ErrorOrigin::OsLayer, ErrorKind::Offset)
242 .log_warn("_EPROCESS::ThreadListHead not found")
243 })?
244 .offset as _;
245
246 let eproc_wow64 = match eproc
248 .find_field("WoW64Process")
249 .or_else(|| eproc.find_field("Wow64Process"))
250 {
251 Some(f) => f.offset as _,
252 None => 0,
253 };
254
255 let kthread_teb = kthread
257 .find_field("Teb")
258 .ok_or_else(|| {
259 Error(ErrorOrigin::OsLayer, ErrorKind::Offset).log_warn("_KTHREAD::Teb not found")
260 })?
261 .offset as _;
262 let ethread_list_entry = ethread
263 .find_field("ThreadListEntry")
264 .ok_or_else(|| {
265 Error(ErrorOrigin::OsLayer, ErrorKind::Offset)
266 .log_warn("_ETHREAD::ThreadListEntry not found")
267 })?
268 .offset as _;
269 let teb_peb = teb
270 .find_field("ProcessEnvironmentBlock")
271 .ok_or_else(|| {
272 Error(ErrorOrigin::OsLayer, ErrorKind::Offset)
273 .log_warn("_TEB::ProcessEnvironmentBlock not found")
274 })?
275 .offset as _;
276 let teb_peb_x86 = if let Ok(teb32) = PdbStruct::new(pdb_slice, "_TEB32").map_err(|_| {
277 Error(ErrorOrigin::OsLayer, ErrorKind::Offset).log_warn("_TEB32 not found")
278 }) {
279 teb32
280 .find_field("ProcessEnvironmentBlock")
281 .ok_or_else(|| {
282 Error(ErrorOrigin::OsLayer, ErrorKind::Offset)
283 .log_warn("_TEB32::ProcessEnvironmentBlock not found")
284 })?
285 .offset as _
286 } else {
287 0
288 };
289
290 let eproc_vad_root = eproc
291 .find_field("VadRoot") .ok_or_else(|| {
293 Error(ErrorOrigin::OsLayer, ErrorKind::Offset)
294 .log_warn("_EPROCESS::VadRoot not found")
295 })?
296 .offset as _;
297
298 let vad_node = mm_vad
301 .find_field("VadNode")
302 .or_else(|| mm_vad.find_field("LeftChild"))
303 .map(|f| f.offset)
304 .unwrap_or(0) as _;
305
306 let starting_vpn = mm_vad
307 .find_field("StartingVpn")
308 .map(|f| f.offset)
309 .unwrap_or(0) as _;
310 let ending_vpn = mm_vad
311 .find_field("EndingVpn")
312 .map(|f| f.offset)
313 .unwrap_or(0) as _;
314 let starting_vpn_high = mm_vad
315 .find_field("StartingVpnHigh")
316 .map(|f| f.offset)
317 .unwrap_or(0) as _;
318 let ending_vpn_high = mm_vad
319 .find_field("EndingVpnHigh")
320 .map(|f| f.offset)
321 .unwrap_or(0) as _;
322 let u = mm_vad.find_field("u").map(|f| f.offset).unwrap_or(0) as _;
323
324 let protection_bit = mm_vad_flags
325 .find_field("Protection")
326 .map(|f| f.bit_offset)
327 .unwrap_or(0) as _;
328
329 Ok(Self(Win32OffsetTable {
330 list_blink,
331 eproc_link,
332
333 phys_mem_block,
334
335 kproc_dtb,
336
337 eproc_pid,
338 eproc_name,
339 eproc_peb,
340 eproc_section_base,
341 eproc_exit_status,
342 eproc_thread_list,
343 eproc_wow64,
344 eproc_vad_root,
345
346 kthread_teb,
347 ethread_list_entry,
348 teb_peb,
349 teb_peb_x86,
350
351 mmvad: MmVadOffsetTable {
352 vad_node,
353 starting_vpn,
354 ending_vpn,
355 starting_vpn_high,
356 ending_vpn_high,
357 u,
358 protection_bit,
359 },
360 }))
361 }
362
363 pub fn list_blink(&self) -> usize {
365 self.0.list_blink as usize
366 }
367 pub fn eproc_link(&self) -> usize {
369 self.0.eproc_link as usize
370 }
371
372 pub fn phys_mem_block(&self) -> usize {
374 self.0.phys_mem_block as usize
375 }
376
377 pub fn kproc_dtb(&self) -> usize {
380 self.0.kproc_dtb as usize
381 }
382 pub fn eproc_pid(&self) -> usize {
385 self.0.eproc_pid as usize
386 }
387 pub fn eproc_name(&self) -> usize {
390 self.0.eproc_name as usize
391 }
392 pub fn eproc_peb(&self) -> usize {
395 self.0.eproc_peb as usize
396 }
397 pub fn eproc_section_base(&self) -> usize {
400 self.0.eproc_section_base as usize
401 }
402 pub fn eproc_exit_status(&self) -> usize {
405 self.0.eproc_exit_status as usize
406 }
407 pub fn eproc_thread_list(&self) -> usize {
410 self.0.eproc_thread_list as usize
411 }
412 pub fn eproc_wow64(&self) -> usize {
415 self.0.eproc_wow64 as usize
416 }
417 pub fn eproc_vad_root(&self) -> usize {
420 self.0.eproc_vad_root as usize
421 }
422
423 pub fn kthread_teb(&self) -> usize {
426 self.0.kthread_teb as usize
427 }
428 pub fn ethread_list_entry(&self) -> usize {
431 self.0.ethread_list_entry as usize
432 }
433 pub fn teb_peb(&self) -> usize {
436 self.0.teb_peb as usize
437 }
438 pub fn teb_peb_x86(&self) -> usize {
441 self.0.teb_peb_x86 as usize
442 }
443
444 pub fn mm_vad(&self) -> MmVadOffsetTable {
446 self.0.mmvad
447 }
448
449 pub fn builder<'a>() -> Win32OffsetBuilder<'a> {
450 Win32OffsetBuilder::default()
451 }
452}
453
454#[cfg(test)]
455mod tests {
456 use super::*;
457
458 }