1 use crate::container; 2 use crate::error; 3 4 use crate::pe::data_directories; 5 6 use scroll::{ctx, Endian, LE}; 7 use scroll::{Pread, Pwrite, SizeWith}; 8 9 /// standard COFF fields 10 #[repr(C)] 11 #[derive(Debug, PartialEq, Copy, Clone, Default)] 12 #[derive(Pread, Pwrite, SizeWith)] 13 pub struct StandardFields32 { 14 pub magic: u16, 15 pub major_linker_version: u8, 16 pub minor_linker_version: u8, 17 pub size_of_code: u32, 18 pub size_of_initialized_data: u32, 19 pub size_of_uninitialized_data: u32, 20 pub address_of_entry_point: u32, 21 pub base_of_code: u32, 22 /// absent in 64-bit PE32+ 23 pub base_of_data: u32, 24 } 25 26 pub const SIZEOF_STANDARD_FIELDS_32: usize = 28; 27 28 /// standard 64-bit COFF fields 29 #[repr(C)] 30 #[derive(Debug, PartialEq, Copy, Clone, Default)] 31 #[derive(Pread, Pwrite, SizeWith)] 32 pub struct StandardFields64 { 33 pub magic: u16, 34 pub major_linker_version: u8, 35 pub minor_linker_version: u8, 36 pub size_of_code: u32, 37 pub size_of_initialized_data: u32, 38 pub size_of_uninitialized_data: u32, 39 pub address_of_entry_point: u32, 40 pub base_of_code: u32, 41 } 42 43 pub const SIZEOF_STANDARD_FIELDS_64: usize = 24; 44 45 /// Unified 32/64-bit COFF fields 46 #[derive(Debug, PartialEq, Copy, Clone, Default)] 47 pub struct StandardFields { 48 pub magic: u16, 49 pub major_linker_version: u8, 50 pub minor_linker_version: u8, 51 pub size_of_code: u64, 52 pub size_of_initialized_data: u64, 53 pub size_of_uninitialized_data: u64, 54 pub address_of_entry_point: u64, 55 pub base_of_code: u64, 56 /// absent in 64-bit PE32+ 57 pub base_of_data: u32, 58 } 59 60 impl From<StandardFields32> for StandardFields { from(fields: StandardFields32) -> Self61 fn from(fields: StandardFields32) -> Self { 62 StandardFields { 63 magic: fields.magic, 64 major_linker_version: fields.major_linker_version, 65 minor_linker_version: fields.minor_linker_version, 66 size_of_code: u64::from(fields.size_of_code), 67 size_of_initialized_data: u64::from(fields.size_of_initialized_data), 68 size_of_uninitialized_data: u64::from(fields.size_of_uninitialized_data), 69 address_of_entry_point: u64::from(fields.address_of_entry_point), 70 base_of_code: u64::from(fields.base_of_code), 71 base_of_data: fields.base_of_data, 72 } 73 } 74 } 75 76 impl From<StandardFields64> for StandardFields { from(fields: StandardFields64) -> Self77 fn from(fields: StandardFields64) -> Self { 78 StandardFields { 79 magic: fields.magic, 80 major_linker_version: fields.major_linker_version, 81 minor_linker_version: fields.minor_linker_version, 82 size_of_code: u64::from(fields.size_of_code), 83 size_of_initialized_data: u64::from(fields.size_of_initialized_data), 84 size_of_uninitialized_data: u64::from(fields.size_of_uninitialized_data), 85 address_of_entry_point: u64::from(fields.address_of_entry_point), 86 base_of_code: u64::from(fields.base_of_code), 87 base_of_data: 0, 88 } 89 } 90 } 91 92 /// Standard fields magic number for 32-bit binary 93 pub const MAGIC_32: u16 = 0x10b; 94 /// Standard fields magic number for 64-bit binary 95 pub const MAGIC_64: u16 = 0x20b; 96 97 /// Windows specific fields 98 #[repr(C)] 99 #[derive(Debug, PartialEq, Copy, Clone, Default)] 100 #[derive(Pread, Pwrite, SizeWith)] 101 pub struct WindowsFields32 { 102 pub image_base: u32, 103 pub section_alignment: u32, 104 pub file_alignment: u32, 105 pub major_operating_system_version: u16, 106 pub minor_operating_system_version: u16, 107 pub major_image_version: u16, 108 pub minor_image_version: u16, 109 pub major_subsystem_version: u16, 110 pub minor_subsystem_version: u16, 111 pub win32_version_value: u32, 112 pub size_of_image: u32, 113 pub size_of_headers: u32, 114 pub check_sum: u32, 115 pub subsystem: u16, 116 pub dll_characteristics: u16, 117 pub size_of_stack_reserve: u32, 118 pub size_of_stack_commit: u32, 119 pub size_of_heap_reserve: u32, 120 pub size_of_heap_commit: u32, 121 pub loader_flags: u32, 122 pub number_of_rva_and_sizes: u32, 123 } 124 125 pub const SIZEOF_WINDOWS_FIELDS_32: usize = 68; 126 127 /// 64-bit Windows specific fields 128 #[repr(C)] 129 #[derive(Debug, PartialEq, Copy, Clone, Default)] 130 #[derive(Pread, Pwrite, SizeWith)] 131 pub struct WindowsFields64 { 132 pub image_base: u64, 133 pub section_alignment: u32, 134 pub file_alignment: u32, 135 pub major_operating_system_version: u16, 136 pub minor_operating_system_version: u16, 137 pub major_image_version: u16, 138 pub minor_image_version: u16, 139 pub major_subsystem_version: u16, 140 pub minor_subsystem_version: u16, 141 pub win32_version_value: u32, 142 pub size_of_image: u32, 143 pub size_of_headers: u32, 144 pub check_sum: u32, 145 pub subsystem: u16, 146 pub dll_characteristics: u16, 147 pub size_of_stack_reserve: u64, 148 pub size_of_stack_commit: u64, 149 pub size_of_heap_reserve: u64, 150 pub size_of_heap_commit: u64, 151 pub loader_flags: u32, 152 pub number_of_rva_and_sizes: u32, 153 } 154 155 pub const SIZEOF_WINDOWS_FIELDS_64: usize = 88; 156 157 // /// Generic 32/64-bit Windows specific fields 158 // #[derive(Debug, PartialEq, Copy, Clone, Default)] 159 // pub struct WindowsFields { 160 // pub image_base: u64, 161 // pub section_alignment: u32, 162 // pub file_alignment: u32, 163 // pub major_operating_system_version: u16, 164 // pub minor_operating_system_version: u16, 165 // pub major_image_version: u16, 166 // pub minor_image_version: u16, 167 // pub major_subsystem_version: u16, 168 // pub minor_subsystem_version: u16, 169 // pub win32_version_value: u32, 170 // pub size_of_image: u32, 171 // pub size_of_headers: u32, 172 // pub check_sum: u32, 173 // pub subsystem: u16, 174 // pub dll_characteristics: u16, 175 // pub size_of_stack_reserve: u64, 176 // pub size_of_stack_commit: u64, 177 // pub size_of_heap_reserve: u64, 178 // pub size_of_heap_commit: u64, 179 // pub loader_flags: u32, 180 // pub number_of_rva_and_sizes: u32, 181 // } 182 183 impl From<WindowsFields32> for WindowsFields { from(windows: WindowsFields32) -> Self184 fn from(windows: WindowsFields32) -> Self { 185 WindowsFields { 186 image_base: u64::from(windows.image_base), 187 section_alignment: windows.section_alignment, 188 file_alignment: windows.file_alignment, 189 major_operating_system_version: windows.major_operating_system_version, 190 minor_operating_system_version: windows.minor_operating_system_version, 191 major_image_version: windows.major_image_version, 192 minor_image_version: windows.minor_image_version, 193 major_subsystem_version: windows.major_subsystem_version, 194 minor_subsystem_version: windows.minor_subsystem_version, 195 win32_version_value: windows.win32_version_value, 196 size_of_image: windows.size_of_image, 197 size_of_headers: windows.size_of_headers, 198 check_sum: windows.check_sum, 199 subsystem: windows.subsystem, 200 dll_characteristics: windows.dll_characteristics, 201 size_of_stack_reserve: u64::from(windows.size_of_stack_reserve), 202 size_of_stack_commit: u64::from(windows.size_of_stack_commit), 203 size_of_heap_reserve: u64::from(windows.size_of_heap_reserve), 204 size_of_heap_commit: u64::from(windows.size_of_heap_commit), 205 loader_flags: windows.loader_flags, 206 number_of_rva_and_sizes: windows.number_of_rva_and_sizes, 207 } 208 } 209 } 210 211 // impl From<WindowsFields32> for WindowsFields { 212 // fn from(windows: WindowsFields32) -> Self { 213 // WindowsFields { 214 // image_base: windows.image_base, 215 // section_alignment: windows.section_alignment, 216 // file_alignment: windows.file_alignment, 217 // major_operating_system_version: windows.major_operating_system_version, 218 // minor_operating_system_version: windows.minor_operating_system_version, 219 // major_image_version: windows.major_image_version, 220 // minor_image_version: windows.minor_image_version, 221 // major_subsystem_version: windows.major_subsystem_version, 222 // minor_subsystem_version: windows.minor_subsystem_version, 223 // win32_version_value: windows.win32_version_value, 224 // size_of_image: windows.size_of_image, 225 // size_of_headers: windows.size_of_headers, 226 // check_sum: windows.check_sum, 227 // subsystem: windows.subsystem, 228 // dll_characteristics: windows.dll_characteristics, 229 // size_of_stack_reserve: windows.size_of_stack_reserve, 230 // size_of_stack_commit: windows.size_of_stack_commit, 231 // size_of_heap_reserve: windows.size_of_heap_reserve, 232 // size_of_heap_commit: windows.size_of_heap_commit, 233 // loader_flags: windows.loader_flags, 234 // number_of_rva_and_sizes: windows.number_of_rva_and_sizes, 235 // } 236 // } 237 // } 238 239 pub type WindowsFields = WindowsFields64; 240 241 #[derive(Debug, PartialEq, Copy, Clone)] 242 pub struct OptionalHeader { 243 pub standard_fields: StandardFields, 244 pub windows_fields: WindowsFields, 245 pub data_directories: data_directories::DataDirectories 246 } 247 248 impl OptionalHeader { container(&self) -> error::Result<container::Container>249 pub fn container(&self) -> error::Result<container::Container> { 250 match self.standard_fields.magic { 251 MAGIC_32 => { 252 Ok(container::Container::Little) 253 }, 254 MAGIC_64 => { 255 Ok(container::Container::Big) 256 }, 257 magic => { 258 Err(error::Error::BadMagic(u64::from(magic))) 259 } 260 } 261 } 262 } 263 264 impl<'a> ctx::TryFromCtx<'a, Endian> for OptionalHeader { 265 type Error = crate::error::Error; try_from_ctx(bytes: &'a [u8], _: Endian) -> error::Result<(Self, usize)>266 fn try_from_ctx(bytes: &'a [u8], _: Endian) -> error::Result<(Self, usize)> { 267 let magic = bytes.pread_with::<u16>(0, LE)?; 268 let offset = &mut 0; 269 let (standard_fields, windows_fields): (StandardFields, WindowsFields) = match magic { 270 MAGIC_32 => { 271 let standard_fields = bytes.gread_with::<StandardFields32>(offset, LE)?.into(); 272 let windows_fields = bytes.gread_with::<WindowsFields32>(offset, LE)?.into(); 273 (standard_fields, windows_fields) 274 }, 275 MAGIC_64 => { 276 let standard_fields = bytes.gread_with::<StandardFields64>(offset, LE)?.into(); 277 let windows_fields = bytes.gread_with::<WindowsFields64>(offset, LE)?; 278 (standard_fields, windows_fields) 279 }, 280 _ => return Err(error::Error::BadMagic(u64::from(magic))) 281 }; 282 let data_directories = data_directories::DataDirectories::parse(&bytes, windows_fields.number_of_rva_and_sizes as usize, offset)?; 283 Ok ((OptionalHeader { 284 standard_fields, 285 windows_fields, 286 data_directories, 287 }, 0)) // TODO: FIXME 288 } 289 } 290 291 #[cfg(test)] 292 mod tests { 293 use super::*; 294 #[test] sizeof_standards32()295 fn sizeof_standards32() { 296 assert_eq!(::std::mem::size_of::<StandardFields32>(), SIZEOF_STANDARD_FIELDS_32); 297 } 298 #[test] sizeof_windows32()299 fn sizeof_windows32() { 300 assert_eq!(::std::mem::size_of::<WindowsFields32>(), SIZEOF_WINDOWS_FIELDS_32); 301 } 302 #[test] sizeof_standards64()303 fn sizeof_standards64() { 304 assert_eq!(::std::mem::size_of::<StandardFields64>(), SIZEOF_STANDARD_FIELDS_64); 305 } 306 #[test] sizeof_windows64()307 fn sizeof_windows64() { 308 assert_eq!(::std::mem::size_of::<WindowsFields64>(), SIZEOF_WINDOWS_FIELDS_64); 309 } 310 } 311