use super::full_memory_dump::*;
use super::*;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::mem::size_of;
use std::mem::MaybeUninit;
use log::info;
use memflow::prelude::v1::*;
pub const DUMP_VALID_DUMP32: u32 = 0x504d5544;
pub const IMAGE_FILE_MACHINE_I386: u32 = 0x014c;
#[repr(C)]
#[derive(Copy, Clone, ByteSwap)]
pub struct CoreDumpHeader32 {
pub signature: u32, pub valid_dump: u32, pub major_version: u32, pub minor_version: u32, pub directory_table_base: u32, pub pfn_data_base: u32, pub ps_loaded_module_list: u32, pub ps_active_process_head: u32, pub machine_image_type: u32, pub number_processors: u32, pub bug_check_code: u32, pub bug_check_parameter1: u32, pub bug_check_parameter2: u32, pub bug_check_parameter3: u32, pub bug_check_parameter4: u32, pub version_user: [u8; 32], pub pae_enabled: u8, pub kd_secondary_version: u8, pub spare: [u8; 2], pub kd_debugger_data_block: u32, pub physical_memory_block: PhysicalMemoryDescriptor<u32>, pub pad0: [u8; 436], pub context_record: [u8; 1200], pub exception_record: [u8; 80], pub comment: [u8; 128], pub reserved0: [u8; 1768], pub dump_type: u32, pub mini_dump_fields: u32, pub secondary_data_state: u32, pub product_type: u32, pub suite_mask: u32, pub reserved1: [u8; 4], pub required_dump_space: u64, pub reserved2: [u8; 16], pub system_up_time: u64, pub system_time: u64, pub reserved3: [u8; 56], }
const _: [(); std::mem::size_of::<CoreDumpHeader32>()] = [(); 0x1000];
#[allow(clippy::uninit_assumed_init)]
impl CoreDumpHeader32 {
pub fn uninit() -> Self {
unsafe { MaybeUninit::uninit().assume_init() }
}
}
unsafe impl Pod for CoreDumpHeader32 {}
pub fn parse_coredump32(file: &mut File) -> Result<MemoryMap<(Address, umem)>> {
let mut header = CoreDumpHeader32::uninit();
file.seek(SeekFrom::Start(0)).map_err(|_| {
Error(ErrorOrigin::Connector, ErrorKind::Unknown)
.log_error("unable to seek to coredump 64 header")
})?;
file.read_exact(header.as_bytes_mut()).map_err(|_| {
Error(ErrorOrigin::Connector, ErrorKind::Unknown)
.log_error("unable to read coredump 32 header")
})?;
if cfg!(target_endian = "big") {
header.byte_swap();
}
if header.signature != DUMP_SIGNATURE {
return Err(Error(ErrorOrigin::Connector, ErrorKind::Unknown)
.log_error("header signature is not valid"));
}
if header.valid_dump != DUMP_VALID_DUMP32 {
return Err(Error(ErrorOrigin::Connector, ErrorKind::Unknown)
.log_error("header dump flag is not valid"));
}
if header.machine_image_type != IMAGE_FILE_MACHINE_I386 {
return Err(Error(ErrorOrigin::Connector, ErrorKind::Unknown)
.log_error("invalid machine image type"));
}
info!("32-bit Microsoft Crash Dump verified");
match header.dump_type {
dump_type::FULL | DUMP_SIGNATURE => full_memory_dump::parse_full_dump(
header.physical_memory_block,
size_of::<CoreDumpHeader32>(),
),
dump_type::BIT_MAP => bitmap_dump::parse_bitmap_dump(file),
_ => Err(Error(ErrorOrigin::Connector, ErrorKind::Unknown)
.log_error("invalid dump type, only full and bitmap dumps are supported")),
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem::size_of;
#[test]
fn test_struct_sizes_x86() {
assert_eq!(size_of::<PhysicalMemoryRun<u32>>(), 0x8);
assert_eq!(size_of::<PhysicalMemoryDescriptor<u32>>(), 0x108);
assert_eq!(size_of::<CoreDumpHeader32>(), 0x1000);
}
#[test]
fn test_struct_members_x86() {
let header = CoreDumpHeader32::uninit();
assert_eq!(
&header.version_user as *const _ as usize - &header as *const _ as usize,
0x3c
);
assert_eq!(
&header.kd_debugger_data_block as *const _ as usize - &header as *const _ as usize,
0x60
);
assert_eq!(
&header.physical_memory_block as *const _ as usize - &header as *const _ as usize,
0x64
);
assert_eq!(
&header.context_record as *const _ as usize - &header as *const _ as usize,
0x320
);
assert_eq!(
&header.exception_record as *const _ as usize - &header as *const _ as usize,
0x7d0
);
assert_eq!(
&header.dump_type as *const _ as usize - &header as *const _ as usize,
0xf88
);
}
}