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