1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use pe::error;
use super::data_directories;

use scroll::{self, Gread};

/// standard COFF fields
#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default)]
#[derive(Pread, Pwrite)]
pub struct StandardFields {
    pub magic: u16,
    pub major_linker_version: u8,
    pub minor_linker_version: u8,
    pub size_of_code: u32, // no these are all the same u32, only base of data is absent seems: all below mabye 64-bit addr
    pub size_of_initialized_data: u32, // addr
    pub size_of_uninitialized_data: u32, // addr
    pub address_of_entry_point: u32, // addr
    pub base_of_code: u32, // addr
    /// absent in 64-bit PE32+
    pub base_of_data: u32,
}

pub const SIZEOF_STANDARD_FIELDS: usize = (3 * 8) + 4;

pub const MAGIC_32: u16 = 0x10b;
// TODO: verify this
pub const MAGIC_64: u16 = 0x20b;

impl StandardFields {
    pub fn parse<B: AsRef<[u8]>> (bytes: &B, offset: &mut usize) -> error::Result<Self> {
        let mut standard_fields = StandardFields::default();
        standard_fields.magic = bytes.gread_with(offset, scroll::LE)?;
        standard_fields.major_linker_version = bytes.gread_with(offset, scroll::LE)?;
        standard_fields.minor_linker_version = bytes.gread_with(offset, scroll::LE)?;
        standard_fields.size_of_code = bytes.gread_with(offset, scroll::LE)?;
        standard_fields.size_of_initialized_data = bytes.gread_with(offset, scroll::LE)?;
        standard_fields.size_of_uninitialized_data = bytes.gread_with(offset, scroll::LE)?;
        standard_fields.address_of_entry_point = bytes.gread_with(offset, scroll::LE)?;
        standard_fields.base_of_code = bytes.gread_with(offset, scroll::LE)?;
        standard_fields.base_of_data = bytes.gread_with(offset, scroll::LE)?;
        Ok(standard_fields)
    }
}

/// Windows specific fields
#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default)]
pub struct WindowsFields {
    pub image_base: u32, // u64; 64-bit
    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, // u64
    pub size_of_stack_commit: u32, // u64
    pub size_of_heap_reserve: u32, // u64
    pub size_of_heap_commit: u32, // u64
    pub loader_flags: u32,
    pub number_of_rva_and_sizes: u32,
}

pub const SIZEOF_WINDOWS_FIELDS: usize = (8 * 8) + 4;

impl WindowsFields {
    pub fn parse<B: AsRef<[u8]>> (bytes: &B, offset: &mut usize) -> error::Result<Self> {
        let mut windows_fields = WindowsFields::default();
        windows_fields.image_base = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.section_alignment = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.file_alignment = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.major_operating_system_version = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.minor_operating_system_version = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.major_image_version = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.minor_image_version = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.major_subsystem_version = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.minor_subsystem_version = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.win32_version_value = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.size_of_image = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.size_of_headers = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.check_sum = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.subsystem = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.dll_characteristics = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.size_of_stack_reserve = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.size_of_stack_commit = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.size_of_heap_reserve = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.size_of_heap_commit = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.loader_flags = bytes.gread_with(offset, scroll::LE)?;
        windows_fields.number_of_rva_and_sizes = bytes.gread_with(offset, scroll::LE)?;
        Ok(windows_fields)
    }
}



#[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 parse<B: AsRef<[u8]>> (bytes: &B, offset: &mut usize) -> error::Result<Self> {
        let standard_fields = StandardFields::parse(bytes, offset)?;
        let windows_fields = WindowsFields::parse(bytes, offset)?;
        let data_directories = data_directories::DataDirectories::parse(bytes, windows_fields.number_of_rva_and_sizes as usize, offset)?;
        Ok (OptionalHeader {
            standard_fields: standard_fields,
            windows_fields: windows_fields, 
            data_directories: data_directories,
        })
    }
}