udmp_parser/
structs.rs

1// Axel '0vercl0k' Souchet - July 29 2023
2//! This is where all the raw Windows user-dump structures are stored in.
3use std::fmt;
4
5pub const STREAM_TYPE_UNUSED: u32 = 0;
6pub const STREAM_TYPE_THREAD_LIST: u32 = 3;
7pub const STREAM_TYPE_MODULE_LIST: u32 = 4;
8pub const STREAM_TYPE_EXCEPTION: u32 = 6;
9pub const STREAM_TYPE_SYSTEM_INFO: u32 = 7;
10pub const STREAM_TYPE_MEMORY64_LIST: u32 = 9;
11pub const STREAM_TYPE_MEMORY_INFO_LIST: u32 = 16;
12
13pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
14
15pub const EXPECTED_DUMP_SIGNATURE: u32 = 0x504d_444d;
16
17pub const VALID_DUMP_FLAGS: u32 = 0x001f_ffff;
18
19pub const WOW64_MAXIMUM_SUPPORTED_EXTENSION: usize = 512;
20
21pub const WOW64_SIZE_OF_80387_REGISTERS: usize = 80;
22
23pub const ARCH_X86: u16 = 0;
24pub const ARCH_X64: u16 = 9;
25
26#[derive(Debug, Default)]
27#[repr(C)]
28pub struct Header {
29    pub signature: u32,
30    pub version: u16,
31    pub implementation_version: u16,
32    pub number_of_streams: u32,
33    pub stream_directory_rva: u32,
34    pub checksum: u32,
35    pub reserved: u32,
36    pub timedatestamp: u32,
37    pub flags: u32,
38}
39
40#[derive(Debug, Default, Clone, Copy)]
41#[repr(C)]
42pub struct LocationDescriptor32 {
43    pub data_size: u32,
44    pub rva: u32,
45}
46
47#[derive(Debug, Default)]
48#[repr(C)]
49pub struct Directory {
50    pub stream_type: u32,
51    pub location: LocationDescriptor32,
52}
53
54#[derive(Debug, Default)]
55#[repr(C)]
56pub struct SystemInfoStream {
57    pub processor_arch: u16,
58    pub processor_level: u16,
59    pub processor_revision: u16,
60    pub number_of_processors: u8,
61    pub product_type: u8,
62    pub major_version: u32,
63    pub minor_version: u32,
64    pub build_number: u32,
65    pub platform_id: u32,
66    pub csd_version_rva: u32,
67    pub suite_mask: u16,
68    pub reserverd2: u16,
69}
70
71#[derive(Default, Debug)]
72#[repr(C)]
73pub struct ExceptionRecord {
74    pub exception_code: u32,
75    pub exception_flags: u32,
76    pub exception_record: u64,
77    pub exception_address: u64,
78    pub number_parameters: u32,
79    pub unused_alignment: u32,
80    pub exception_information: [u64; EXCEPTION_MAXIMUM_PARAMETERS],
81}
82
83#[derive(Default, Debug)]
84#[repr(C)]
85pub struct ExceptionStream {
86    pub thread_id: u32,
87    pub alignment: u32,
88    pub exception_record: ExceptionRecord,
89    pub thread_context: LocationDescriptor32,
90}
91
92#[derive(Default, Debug)]
93#[repr(C)]
94pub struct MemoryInfo {
95    pub base_address: u64,
96    pub allocation_base: u64,
97    pub allocation_protect: u32,
98    pub alignment1: u32,
99    pub region_size: u64,
100    pub state: u32,
101    pub protect: u32,
102    pub type_: u32,
103    pub alignment2: u32,
104}
105
106#[derive(Default, Debug)]
107#[repr(C)]
108pub struct MemoryInfoListStream {
109    pub size_of_header: u32,
110    pub size_of_entry: u32,
111    pub number_of_entries: u64,
112}
113
114#[derive(Default, Debug)]
115#[repr(C)]
116pub struct Memory64ListStream {
117    pub number_of_memory_ranges: u64,
118    pub base_rva: u64,
119}
120
121#[derive(Default, Debug)]
122#[repr(C)]
123pub struct MemoryDescriptor64 {
124    pub start_of_memory_range: u64,
125    pub data_size: u64,
126}
127
128#[derive(Default, Debug)]
129#[repr(C)]
130pub struct ThreadList {
131    pub number_of_threads: u32,
132}
133
134#[derive(Default, Debug)]
135#[repr(C)]
136pub struct MemoryDescriptor {
137    pub start_of_memory_range: u64,
138    pub memory: LocationDescriptor32,
139}
140
141#[derive(Default, Debug)]
142#[repr(C)]
143pub struct ThreadEntry {
144    pub thread_id: u32,
145    pub suspend_count: u32,
146    pub priority_class: u32,
147    pub priority: u32,
148    pub teb: u64,
149    pub stack: MemoryDescriptor,
150    pub thread_context: LocationDescriptor32,
151}
152
153#[derive(Default, Debug)]
154#[repr(C)]
155pub struct ModuleList {
156    pub number_of_modules: u32,
157}
158
159#[derive(Default, Debug, Clone, Copy)]
160#[repr(C)]
161pub struct FixedFileInfo {
162    pub signature: u32,
163    pub struc_version: u32,
164    pub file_version_ms: u32,
165    pub file_version_ls: u32,
166    pub product_version_ms: u32,
167    pub product_version_ls: u32,
168    pub file_flags_mask: u32,
169    pub file_flags: u32,
170    pub file_os: u32,
171    pub file_type: u32,
172    pub file_subtype: u32,
173    pub file_date_ms: u32,
174    pub file_date_ls: u32,
175}
176
177#[derive(Default, Debug)]
178#[repr(packed(1))]
179pub struct ModuleEntry {
180    pub base_of_image: u64,
181    pub size_of_image: u32,
182    pub checksum: u32,
183    pub time_date_stamp: u32,
184    pub module_name_rva: u32,
185    pub version_info: FixedFileInfo,
186    pub cv_record: LocationDescriptor32,
187    pub misc_record: LocationDescriptor32,
188    _reserved0: u64,
189    _reserved1: u64,
190}
191
192#[derive(Debug, PartialEq)]
193#[repr(C)]
194pub struct FloatingSaveArea32 {
195    pub control_word: u32,
196    pub status_word: u32,
197    pub tag_word: u32,
198    pub error_offset: u32,
199    pub error_selector: u32,
200    pub data_offset: u32,
201    pub data_selector: u32,
202    pub register_area: [u8; WOW64_SIZE_OF_80387_REGISTERS],
203    pub cr0_npx_state: u32,
204}
205
206impl Default for FloatingSaveArea32 {
207    fn default() -> Self {
208        // SAFETY: All zero values are fine for every types used by
209        // [`FloatingSaveArea32`].
210        unsafe { std::mem::zeroed() }
211    }
212}
213
214/// The context of an Intel X86 thread.
215#[derive(Debug)]
216#[repr(C)]
217pub struct ThreadContextX86 {
218    pub context_flags: u32,
219    pub dr0: u32,
220    pub dr1: u32,
221    pub dr2: u32,
222    pub dr3: u32,
223    pub dr6: u32,
224    pub dr7: u32,
225    pub float_save: FloatingSaveArea32,
226    pub seg_gs: u32,
227    pub seg_fs: u32,
228    pub seg_es: u32,
229    pub seg_ds: u32,
230    pub edi: u32,
231    pub esi: u32,
232    pub ebx: u32,
233    pub edx: u32,
234    pub ecx: u32,
235    pub eax: u32,
236    pub ebp: u32,
237    pub eip: u32,
238    pub seg_cs: u32,
239    pub eflags: u32,
240    pub esp: u32,
241    pub seg_ss: u32,
242    pub extended_registers: [u8; WOW64_MAXIMUM_SUPPORTED_EXTENSION],
243}
244
245impl fmt::Display for ThreadContextX86 {
246    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247        writeln!(
248            f,
249            "eax={:08x} ebx={:08x} ecx={:08x} edx={:08x} esi={:08x} edi={:08x}",
250            self.eax, self.ebx, self.ecx, self.edx, self.esi, self.edi
251        )?;
252        writeln!(
253            f,
254            "eip={:08x} esp={:08x} ebp={:08x}",
255            self.eip, self.esp, self.ebp
256        )?;
257        write!(
258            f,
259            "cs={:04x}  ss={:04x}  ds={:04x}  es={:04x}  fs={:04x} gs={:04x}              efl={:08x}",
260            self.seg_cs,
261            self.seg_ss,
262            self.seg_ds,
263            self.seg_es,
264            self.seg_fs,
265            self.seg_gs,
266            self.eflags
267        )
268    }
269}
270
271impl Default for ThreadContextX86 {
272    fn default() -> Self {
273        // SAFETY: All zero values are fine for every types used by
274        // [`ThreadContextX86`].
275        unsafe { std::mem::zeroed() }
276    }
277}
278
279/// The context of an Intel X64 thread.
280#[derive(Debug)]
281#[repr(C)]
282pub struct ThreadContextX64 {
283    pub p1_home: u64,
284    pub p2_home: u64,
285    pub p3_home: u64,
286    pub p4_home: u64,
287    pub p5_home: u64,
288    pub p6_home: u64,
289    pub context_flags: u32,
290    pub mxcsr: u32,
291    pub seg_cs: u16,
292    pub seg_ds: u16,
293    pub seg_es: u16,
294    pub seg_fs: u16,
295    pub seg_gs: u16,
296    pub seg_ss: u16,
297    pub eflags: u32,
298    pub dr0: u64,
299    pub dr1: u64,
300    pub dr2: u64,
301    pub dr3: u64,
302    pub dr6: u64,
303    pub dr7: u64,
304    pub rax: u64,
305    pub rcx: u64,
306    pub rdx: u64,
307    pub rbx: u64,
308    pub rsp: u64,
309    pub rbp: u64,
310    pub rsi: u64,
311    pub rdi: u64,
312    pub r8: u64,
313    pub r9: u64,
314    pub r10: u64,
315    pub r11: u64,
316    pub r12: u64,
317    pub r13: u64,
318    pub r14: u64,
319    pub r15: u64,
320    pub rip: u64,
321    pub control_word: u16,
322    pub status_word: u16,
323    pub tag_word: u8,
324    pub reserved1: u8,
325    pub error_opcode: u16,
326    pub error_offset: u32,
327    pub error_selector: u16,
328    pub reserved2: u16,
329    pub data_offset: u32,
330    pub data_selector: u16,
331    pub reserved3: u16,
332    pub mxcsr2: u32,
333    pub mxcsr_mask: u32,
334    pub float_registers: [u128; 8],
335    pub xmm0: u128,
336    pub xmm1: u128,
337    pub xmm2: u128,
338    pub xmm3: u128,
339    pub xmm4: u128,
340    pub xmm5: u128,
341    pub xmm6: u128,
342    pub xmm7: u128,
343    pub xmm8: u128,
344    pub xmm9: u128,
345    pub xmm10: u128,
346    pub xmm11: u128,
347    pub xmm12: u128,
348    pub xmm13: u128,
349    pub xmm14: u128,
350    pub xmm15: u128,
351    pub padding: [u8; 0x60],
352    pub vector_registers: [u128; 26],
353    pub vector_control: u64,
354    pub debug_control: u64,
355    pub last_branch_to_rip: u64,
356    pub last_branch_from_rip: u64,
357    pub last_exception_to_rip: u64,
358    pub last_exception_from_rip: u64,
359}
360
361impl fmt::Display for ThreadContextX64 {
362    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
363        writeln!(
364            f,
365            "rax={:016x} rbx={:016x} rcx={:016x}",
366            self.rax, self.rbx, self.rcx
367        )?;
368        writeln!(
369            f,
370            "rdx={:016x} rsi={:016x} rdi={:016x}",
371            self.rdx, self.rsi, self.rdi
372        )?;
373        writeln!(
374            f,
375            "rip={:016x} rsp={:016x} rbp={:016x}",
376            self.rip, self.rsp, self.rbp
377        )?;
378        writeln!(
379            f,
380            " r8={:016x}  r9={:016x} r10={:016x}",
381            self.r8, self.r9, self.r10
382        )?;
383        writeln!(
384            f,
385            "r11={:016x} r12={:016x} r13={:016x}",
386            self.r11, self.r12, self.r13
387        )?;
388        writeln!(f, "r14={:016x} r15={:016x}", self.r14, self.r15)?;
389        writeln!(f, "cs={:04x}  ss={:04x}  ds={:04x}  es={:04x}  fs={:04x} gs={:04x}              efl={:08x}",
390        self.seg_cs, self.seg_ss, self.seg_ds, self.seg_es, self.seg_fs, self.seg_gs,
391        self.eflags)?;
392        writeln!(
393            f,
394            "fpcw={:04x}    fpsw={:04x}    fptw={:04x}",
395            self.control_word, self.status_word, self.tag_word
396        )?;
397        writeln!(
398            f,
399            "  st0={:032x}       st1={:032x}",
400            self.float_registers[0], self.float_registers[1]
401        )?;
402        writeln!(
403            f,
404            "  st2={:032x}       st3={:032x}",
405            self.float_registers[2], self.float_registers[3]
406        )?;
407        writeln!(
408            f,
409            "  st4={:032x}       st5={:032x}",
410            self.float_registers[4], self.float_registers[5]
411        )?;
412        writeln!(
413            f,
414            "  st6={:032x}       st7={:032x}",
415            self.float_registers[6], self.float_registers[7]
416        )?;
417        writeln!(f, " xmm0={:032x}      xmm1={:032x}", self.xmm0, self.xmm1)?;
418        writeln!(f, " xmm2={:032x}      xmm3={:032x}", self.xmm2, self.xmm3)?;
419        writeln!(f, " xmm4={:032x}      xmm5={:032x}", self.xmm4, self.xmm5)?;
420        writeln!(f, " xmm6={:032x}      xmm7={:032x}", self.xmm6, self.xmm7)?;
421        writeln!(f, " xmm8={:032x}      xmm9={:032x}", self.xmm8, self.xmm9)?;
422        writeln!(f, "xmm10={:032x}     xmm11={:032x}", self.xmm10, self.xmm11)?;
423        writeln!(f, "xmm12={:032x}     xmm13={:032x}", self.xmm12, self.xmm13)?;
424        write!(f, "xmm14={:032x}     xmm15={:032x}", self.xmm14, self.xmm15)
425    }
426}
427
428impl Default for ThreadContextX64 {
429    fn default() -> Self {
430        // SAFETY: All zero values are fine for every types used by
431        // [`ThreadContextX64`].
432        unsafe { std::mem::zeroed() }
433    }
434}
435
436#[cfg(test)]
437mod tests {
438    use std::mem;
439
440    use super::*;
441
442    /// Ensure that the sizes of key structures are right.
443    #[test]
444    fn sizeofs() {
445        assert_eq!(mem::size_of::<FloatingSaveArea32>(), 0x70);
446        assert_eq!(mem::size_of::<ThreadContextX86>(), 0x2cc);
447        // assert_eq!(mem::offset_of!(ThreadContextX64, Xmm0), 0x1a0);
448        // assert_eq!(mem::offset_of!(ThreadContextX64, VectorRegister), 0x300);
449        assert_eq!(mem::size_of::<ThreadContextX64>(), 0x4d0);
450        assert_eq!(mem::size_of::<Header>(), 0x20);
451        assert_eq!(mem::size_of::<LocationDescriptor32>(), 0x8);
452        assert_eq!(mem::size_of::<Directory>(), 0xC);
453        assert_eq!(mem::size_of::<Memory64ListStream>(), 0x10);
454        assert_eq!(mem::size_of::<MemoryDescriptor64>(), 0x10);
455        assert_eq!(mem::size_of::<FixedFileInfo>(), 0x34);
456        assert_eq!(mem::size_of::<ModuleEntry>(), 0x6c);
457        assert_eq!(mem::size_of::<MemoryInfoListStream>(), 0x10);
458        assert_eq!(mem::size_of::<MemoryInfo>(), 0x30);
459        assert_eq!(mem::size_of::<MemoryDescriptor>(), 0x10);
460        assert_eq!(mem::size_of::<ThreadEntry>(), 0x30);
461        assert_eq!(mem::size_of::<SystemInfoStream>(), 32);
462        assert_eq!(mem::size_of::<ExceptionRecord>(), 0x98);
463        assert_eq!(mem::size_of::<ExceptionStream>(), 0xa8);
464    }
465}