use crate::container; use crate::error; use crate::pe::data_directories; use scroll::{ctx, Endian, LE}; use scroll::{Pread, Pwrite, SizeWith}; /// standard COFF fields #[repr(C)] #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)] pub struct StandardFields32 { pub magic: u16, pub major_linker_version: u8, pub minor_linker_version: u8, pub size_of_code: u32, pub size_of_initialized_data: u32, pub size_of_uninitialized_data: u32, pub address_of_entry_point: u32, pub base_of_code: u32, /// absent in 64-bit PE32+ pub base_of_data: u32, } pub const SIZEOF_STANDARD_FIELDS_32: usize = 28; /// standard 64-bit COFF fields #[repr(C)] #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)] pub struct StandardFields64 { pub magic: u16, pub major_linker_version: u8, pub minor_linker_version: u8, pub size_of_code: u32, pub size_of_initialized_data: u32, pub size_of_uninitialized_data: u32, pub address_of_entry_point: u32, pub base_of_code: u32, } pub const SIZEOF_STANDARD_FIELDS_64: usize = 24; /// Unified 32/64-bit COFF fields #[derive(Debug, PartialEq, Copy, Clone, Default)] pub struct StandardFields { pub magic: u16, pub major_linker_version: u8, pub minor_linker_version: u8, pub size_of_code: u64, pub size_of_initialized_data: u64, pub size_of_uninitialized_data: u64, pub address_of_entry_point: u64, pub base_of_code: u64, /// absent in 64-bit PE32+ pub base_of_data: u32, } impl From for StandardFields { fn from(fields: StandardFields32) -> Self { StandardFields { magic: fields.magic, major_linker_version: fields.major_linker_version, minor_linker_version: fields.minor_linker_version, size_of_code: u64::from(fields.size_of_code), size_of_initialized_data: u64::from(fields.size_of_initialized_data), size_of_uninitialized_data: u64::from(fields.size_of_uninitialized_data), address_of_entry_point: u64::from(fields.address_of_entry_point), base_of_code: u64::from(fields.base_of_code), base_of_data: fields.base_of_data, } } } impl From for StandardFields { fn from(fields: StandardFields64) -> Self { StandardFields { magic: fields.magic, major_linker_version: fields.major_linker_version, minor_linker_version: fields.minor_linker_version, size_of_code: u64::from(fields.size_of_code), size_of_initialized_data: u64::from(fields.size_of_initialized_data), size_of_uninitialized_data: u64::from(fields.size_of_uninitialized_data), address_of_entry_point: u64::from(fields.address_of_entry_point), base_of_code: u64::from(fields.base_of_code), base_of_data: 0, } } } /// Standard fields magic number for 32-bit binary pub const MAGIC_32: u16 = 0x10b; /// Standard fields magic number for 64-bit binary pub const MAGIC_64: u16 = 0x20b; /// Windows specific fields #[repr(C)] #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)] pub struct WindowsFields32 { pub image_base: u32, pub section_alignment: u32, pub file_alignment: u32, pub major_operating_system_version: u16, pub minor_operating_system_version: u16, pub major_image_version: u16, pub minor_image_version: u16, pub major_subsystem_version: u16, pub minor_subsystem_version: u16, pub win32_version_value: u32, pub size_of_image: u32, pub size_of_headers: u32, pub check_sum: u32, pub subsystem: u16, pub dll_characteristics: u16, pub size_of_stack_reserve: u32, pub size_of_stack_commit: u32, pub size_of_heap_reserve: u32, pub size_of_heap_commit: u32, pub loader_flags: u32, pub number_of_rva_and_sizes: u32, } pub const SIZEOF_WINDOWS_FIELDS_32: usize = 68; /// 64-bit Windows specific fields #[repr(C)] #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)] pub struct WindowsFields64 { pub image_base: u64, pub section_alignment: u32, pub file_alignment: u32, pub major_operating_system_version: u16, pub minor_operating_system_version: u16, pub major_image_version: u16, pub minor_image_version: u16, pub major_subsystem_version: u16, pub minor_subsystem_version: u16, pub win32_version_value: u32, pub size_of_image: u32, pub size_of_headers: u32, pub check_sum: u32, pub subsystem: u16, pub dll_characteristics: u16, pub size_of_stack_reserve: u64, pub size_of_stack_commit: u64, pub size_of_heap_reserve: u64, pub size_of_heap_commit: u64, pub loader_flags: u32, pub number_of_rva_and_sizes: u32, } pub const SIZEOF_WINDOWS_FIELDS_64: usize = 88; // /// Generic 32/64-bit Windows specific fields // #[derive(Debug, PartialEq, Copy, Clone, Default)] // pub struct WindowsFields { // pub image_base: u64, // pub section_alignment: u32, // pub file_alignment: u32, // pub major_operating_system_version: u16, // pub minor_operating_system_version: u16, // pub major_image_version: u16, // pub minor_image_version: u16, // pub major_subsystem_version: u16, // pub minor_subsystem_version: u16, // pub win32_version_value: u32, // pub size_of_image: u32, // pub size_of_headers: u32, // pub check_sum: u32, // pub subsystem: u16, // pub dll_characteristics: u16, // pub size_of_stack_reserve: u64, // pub size_of_stack_commit: u64, // pub size_of_heap_reserve: u64, // pub size_of_heap_commit: u64, // pub loader_flags: u32, // pub number_of_rva_and_sizes: u32, // } impl From for WindowsFields { fn from(windows: WindowsFields32) -> Self { WindowsFields { image_base: u64::from(windows.image_base), section_alignment: windows.section_alignment, file_alignment: windows.file_alignment, major_operating_system_version: windows.major_operating_system_version, minor_operating_system_version: windows.minor_operating_system_version, major_image_version: windows.major_image_version, minor_image_version: windows.minor_image_version, major_subsystem_version: windows.major_subsystem_version, minor_subsystem_version: windows.minor_subsystem_version, win32_version_value: windows.win32_version_value, size_of_image: windows.size_of_image, size_of_headers: windows.size_of_headers, check_sum: windows.check_sum, subsystem: windows.subsystem, dll_characteristics: windows.dll_characteristics, size_of_stack_reserve: u64::from(windows.size_of_stack_reserve), size_of_stack_commit: u64::from(windows.size_of_stack_commit), size_of_heap_reserve: u64::from(windows.size_of_heap_reserve), size_of_heap_commit: u64::from(windows.size_of_heap_commit), loader_flags: windows.loader_flags, number_of_rva_and_sizes: windows.number_of_rva_and_sizes, } } } // impl From for WindowsFields { // fn from(windows: WindowsFields32) -> Self { // WindowsFields { // image_base: windows.image_base, // section_alignment: windows.section_alignment, // file_alignment: windows.file_alignment, // major_operating_system_version: windows.major_operating_system_version, // minor_operating_system_version: windows.minor_operating_system_version, // major_image_version: windows.major_image_version, // minor_image_version: windows.minor_image_version, // major_subsystem_version: windows.major_subsystem_version, // minor_subsystem_version: windows.minor_subsystem_version, // win32_version_value: windows.win32_version_value, // size_of_image: windows.size_of_image, // size_of_headers: windows.size_of_headers, // check_sum: windows.check_sum, // subsystem: windows.subsystem, // dll_characteristics: windows.dll_characteristics, // size_of_stack_reserve: windows.size_of_stack_reserve, // size_of_stack_commit: windows.size_of_stack_commit, // size_of_heap_reserve: windows.size_of_heap_reserve, // size_of_heap_commit: windows.size_of_heap_commit, // loader_flags: windows.loader_flags, // number_of_rva_and_sizes: windows.number_of_rva_and_sizes, // } // } // } pub type WindowsFields = WindowsFields64; #[derive(Debug, PartialEq, Copy, Clone)] pub struct OptionalHeader { pub standard_fields: StandardFields, pub windows_fields: WindowsFields, pub data_directories: data_directories::DataDirectories, } impl OptionalHeader { pub fn container(&self) -> error::Result { match self.standard_fields.magic { MAGIC_32 => Ok(container::Container::Little), MAGIC_64 => Ok(container::Container::Big), magic => Err(error::Error::BadMagic(u64::from(magic))), } } } impl<'a> ctx::TryFromCtx<'a, Endian> for OptionalHeader { type Error = crate::error::Error; fn try_from_ctx(bytes: &'a [u8], _: Endian) -> error::Result<(Self, usize)> { let magic = bytes.pread_with::(0, LE)?; let offset = &mut 0; let (standard_fields, windows_fields): (StandardFields, WindowsFields) = match magic { MAGIC_32 => { let standard_fields = bytes.gread_with::(offset, LE)?.into(); let windows_fields = bytes.gread_with::(offset, LE)?.into(); (standard_fields, windows_fields) } MAGIC_64 => { let standard_fields = bytes.gread_with::(offset, LE)?.into(); let windows_fields = bytes.gread_with::(offset, LE)?; (standard_fields, windows_fields) } _ => return Err(error::Error::BadMagic(u64::from(magic))), }; let data_directories = data_directories::DataDirectories::parse( &bytes, windows_fields.number_of_rva_and_sizes as usize, offset, )?; Ok(( OptionalHeader { standard_fields, windows_fields, data_directories, }, 0, )) // TODO: FIXME } } #[cfg(test)] mod tests { use super::*; #[test] fn sizeof_standards32() { assert_eq!( ::std::mem::size_of::(), SIZEOF_STANDARD_FIELDS_32 ); } #[test] fn sizeof_windows32() { assert_eq!( ::std::mem::size_of::(), SIZEOF_WINDOWS_FIELDS_32 ); } #[test] fn sizeof_standards64() { assert_eq!( ::std::mem::size_of::(), SIZEOF_STANDARD_FIELDS_64 ); } #[test] fn sizeof_windows64() { assert_eq!( ::std::mem::size_of::(), SIZEOF_WINDOWS_FIELDS_64 ); } }