4 use crate::pe::data_directories;
6 use scroll::{ctx, Endian, LE};
7 use scroll::{Pread, Pwrite, SizeWith};
9 /// standard COFF fields
11 #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
12 pub struct StandardFields32 {
14 pub major_linker_version: u8,
15 pub minor_linker_version: u8,
16 pub size_of_code: u32,
17 pub size_of_initialized_data: u32,
18 pub size_of_uninitialized_data: u32,
19 pub address_of_entry_point: u32,
20 pub base_of_code: u32,
21 /// absent in 64-bit PE32+
22 pub base_of_data: u32,
25 pub const SIZEOF_STANDARD_FIELDS_32: usize = 28;
27 /// standard 64-bit COFF fields
29 #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
30 pub struct StandardFields64 {
32 pub major_linker_version: u8,
33 pub minor_linker_version: u8,
34 pub size_of_code: u32,
35 pub size_of_initialized_data: u32,
36 pub size_of_uninitialized_data: u32,
37 pub address_of_entry_point: u32,
38 pub base_of_code: u32,
41 pub const SIZEOF_STANDARD_FIELDS_64: usize = 24;
43 /// Unified 32/64-bit COFF fields
44 #[derive(Debug, PartialEq, Copy, Clone, Default)]
45 pub struct StandardFields {
47 pub major_linker_version: u8,
48 pub minor_linker_version: u8,
49 pub size_of_code: u64,
50 pub size_of_initialized_data: u64,
51 pub size_of_uninitialized_data: u64,
52 pub address_of_entry_point: u64,
53 pub base_of_code: u64,
54 /// absent in 64-bit PE32+
55 pub base_of_data: u32,
58 impl From<StandardFields32> for StandardFields {
59 fn from(fields: StandardFields32) -> Self {
62 major_linker_version: fields.major_linker_version,
63 minor_linker_version: fields.minor_linker_version,
64 size_of_code: u64::from(fields.size_of_code),
65 size_of_initialized_data: u64::from(fields.size_of_initialized_data),
66 size_of_uninitialized_data: u64::from(fields.size_of_uninitialized_data),
67 address_of_entry_point: u64::from(fields.address_of_entry_point),
68 base_of_code: u64::from(fields.base_of_code),
69 base_of_data: fields.base_of_data,
74 impl From<StandardFields64> for StandardFields {
75 fn from(fields: StandardFields64) -> Self {
78 major_linker_version: fields.major_linker_version,
79 minor_linker_version: fields.minor_linker_version,
80 size_of_code: u64::from(fields.size_of_code),
81 size_of_initialized_data: u64::from(fields.size_of_initialized_data),
82 size_of_uninitialized_data: u64::from(fields.size_of_uninitialized_data),
83 address_of_entry_point: u64::from(fields.address_of_entry_point),
84 base_of_code: u64::from(fields.base_of_code),
90 /// Standard fields magic number for 32-bit binary
91 pub const MAGIC_32: u16 = 0x10b;
92 /// Standard fields magic number for 64-bit binary
93 pub const MAGIC_64: u16 = 0x20b;
95 /// Windows specific fields
97 #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
98 pub struct WindowsFields32 {
100 pub section_alignment: u32,
101 pub file_alignment: u32,
102 pub major_operating_system_version: u16,
103 pub minor_operating_system_version: u16,
104 pub major_image_version: u16,
105 pub minor_image_version: u16,
106 pub major_subsystem_version: u16,
107 pub minor_subsystem_version: u16,
108 pub win32_version_value: u32,
109 pub size_of_image: u32,
110 pub size_of_headers: u32,
113 pub dll_characteristics: u16,
114 pub size_of_stack_reserve: u32,
115 pub size_of_stack_commit: u32,
116 pub size_of_heap_reserve: u32,
117 pub size_of_heap_commit: u32,
118 pub loader_flags: u32,
119 pub number_of_rva_and_sizes: u32,
122 pub const SIZEOF_WINDOWS_FIELDS_32: usize = 68;
123 /// Offset of the `check_sum` field in [`WindowsFields32`]
124 pub const OFFSET_WINDOWS_FIELDS_32_CHECKSUM: usize = 36;
126 /// 64-bit Windows specific fields
128 #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
129 pub struct WindowsFields64 {
131 pub section_alignment: u32,
132 pub file_alignment: u32,
133 pub major_operating_system_version: u16,
134 pub minor_operating_system_version: u16,
135 pub major_image_version: u16,
136 pub minor_image_version: u16,
137 pub major_subsystem_version: u16,
138 pub minor_subsystem_version: u16,
139 pub win32_version_value: u32,
140 pub size_of_image: u32,
141 pub size_of_headers: u32,
144 pub dll_characteristics: u16,
145 pub size_of_stack_reserve: u64,
146 pub size_of_stack_commit: u64,
147 pub size_of_heap_reserve: u64,
148 pub size_of_heap_commit: u64,
149 pub loader_flags: u32,
150 pub number_of_rva_and_sizes: u32,
153 pub const SIZEOF_WINDOWS_FIELDS_64: usize = 88;
154 /// Offset of the `check_sum` field in [`WindowsFields64`]
155 pub const OFFSET_WINDOWS_FIELDS_64_CHECKSUM: usize = 40;
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,
183 impl From<WindowsFields32> for WindowsFields {
184 fn from(windows: WindowsFields32) -> Self {
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,
211 // impl From<WindowsFields32> for WindowsFields {
212 // fn from(windows: WindowsFields32) -> Self {
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,
239 pub type WindowsFields = WindowsFields64;
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,
248 impl OptionalHeader {
249 pub fn container(&self) -> error::Result<container::Container> {
250 match self.standard_fields.magic {
251 MAGIC_32 => Ok(container::Container::Little),
252 MAGIC_64 => Ok(container::Container::Big),
253 magic => Err(error::Error::BadMagic(u64::from(magic))),
258 impl<'a> ctx::TryFromCtx<'a, Endian> for OptionalHeader {
259 type Error = crate::error::Error;
260 fn try_from_ctx(bytes: &'a [u8], _: Endian) -> error::Result<(Self, usize)> {
261 let magic = bytes.pread_with::<u16>(0, LE)?;
263 let (standard_fields, windows_fields): (StandardFields, WindowsFields) = match magic {
265 let standard_fields = bytes.gread_with::<StandardFields32>(offset, LE)?.into();
266 let windows_fields = bytes.gread_with::<WindowsFields32>(offset, LE)?.into();
267 (standard_fields, windows_fields)
270 let standard_fields = bytes.gread_with::<StandardFields64>(offset, LE)?.into();
271 let windows_fields = bytes.gread_with::<WindowsFields64>(offset, LE)?;
272 (standard_fields, windows_fields)
274 _ => return Err(error::Error::BadMagic(u64::from(magic))),
276 let data_directories = data_directories::DataDirectories::parse(
278 windows_fields.number_of_rva_and_sizes as usize,
296 fn sizeof_standards32() {
298 ::std::mem::size_of::<StandardFields32>(),
299 SIZEOF_STANDARD_FIELDS_32
303 fn sizeof_windows32() {
305 ::std::mem::size_of::<WindowsFields32>(),
306 SIZEOF_WINDOWS_FIELDS_32
310 fn sizeof_standards64() {
312 ::std::mem::size_of::<StandardFields64>(),
313 SIZEOF_STANDARD_FIELDS_64
317 fn sizeof_windows64() {
319 ::std::mem::size_of::<WindowsFields64>(),
320 SIZEOF_WINDOWS_FIELDS_64