blob: 56523c53bb141362ee0ed135f16384ba64420afa [file] [log] [blame]
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<StandardFields32> 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<StandardFields64> 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<WindowsFields32> 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<WindowsFields32> 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<container::Container> {
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::<u16>(0, LE)?;
let offset = &mut 0;
let (standard_fields, windows_fields): (StandardFields, WindowsFields) = match magic {
MAGIC_32 => {
let standard_fields = bytes.gread_with::<StandardFields32>(offset, LE)?.into();
let windows_fields = bytes.gread_with::<WindowsFields32>(offset, LE)?.into();
(standard_fields, windows_fields)
}
MAGIC_64 => {
let standard_fields = bytes.gread_with::<StandardFields64>(offset, LE)?.into();
let windows_fields = bytes.gread_with::<WindowsFields64>(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::<StandardFields32>(),
SIZEOF_STANDARD_FIELDS_32
);
}
#[test]
fn sizeof_windows32() {
assert_eq!(
::std::mem::size_of::<WindowsFields32>(),
SIZEOF_WINDOWS_FIELDS_32
);
}
#[test]
fn sizeof_standards64() {
assert_eq!(
::std::mem::size_of::<StandardFields64>(),
SIZEOF_STANDARD_FIELDS_64
);
}
#[test]
fn sizeof_windows64() {
assert_eq!(
::std::mem::size_of::<WindowsFields64>(),
SIZEOF_WINDOWS_FIELDS_64
);
}
}