pelite\pe64/
pe.rs

1/*!
2Abstract over mapped images and file binaries.
3*/
4
5use std::{cmp, mem, ptr, slice};
6
7use crate::{Error, Result};
8use crate::{util::CStr, util::FromBytes, util::AlignTo, Pod};
9
10use super::{Ptr, image::*};
11
12//----------------------------------------------------------------
13
14pub use crate::wrap::Align;
15
16pub unsafe trait PeObject<'a> {
17	/// Returns the image as a byte slice.
18	fn image(&self) -> &'a [u8];
19
20	/// Returns whether this image uses file alignment or section alignment.
21	fn align(&self) -> Align;
22
23	// Give a struct name in Serialize implementation
24	#[cfg(feature = "serde")]
25	#[doc(hidden)]
26	fn serde_name(&self) -> &'static str;
27}
28
29pub unsafe trait Pe<'a>: PeObject<'a> + Copy {
30	/// Returns the DOS header.
31	fn dos_header(self) -> &'a IMAGE_DOS_HEADER {
32		unsafe { dos_header(self.image()) }
33	}
34	/// Returns the DOS image.
35	///
36	/// This includes the dos header and everything up to the start of the PE headers but is not guaranteed to actually contain anything valid.
37	fn dos_image(self) -> &'a [u8] {
38		unsafe { dos_image(self.image()) }
39	}
40	/// Returns the NT headers.
41	fn nt_headers(self) -> &'a IMAGE_NT_HEADERS {
42		unsafe { nt_headers(self.image()) }
43	}
44	/// Returns the file header.
45	fn file_header(self) -> &'a IMAGE_FILE_HEADER {
46		unsafe { file_header(self.image()) }
47	}
48	/// Returns the optional header.
49	fn optional_header(self) -> &'a IMAGE_OPTIONAL_HEADER {
50		unsafe { optional_header(self.image()) }
51	}
52	/// Returns the data directory.
53	fn data_directory(self) -> &'a [IMAGE_DATA_DIRECTORY] {
54		unsafe { data_directory(self.image()) }
55	}
56	/// Returns the section headers.
57	fn section_headers(self) -> &'a super::headers::SectionHeaders {
58		unsafe { section_headers(self.image()) }
59	}
60
61	/// Returns the pe headers together in a single struct.
62	fn headers(self) -> super::headers::Headers<Self> {
63		super::headers::Headers::new(self)
64	}
65
66	//----------------------------------------------------------------
67
68	/// Converts a relative virtual address to file offset.
69	///
70	/// # Errors
71	///
72	/// * [`Overflow`](../enum.Error.html#variant.Overflow):
73	///   The rva is contained within a corrupt section where the range bounds overflow.
74	///
75	/// * [`ZeroFill`](../enum.Error.html#variant.ZeroFill):
76	///   The rva points to part of a section zero filled and is not available on disk.
77	///
78	/// * [`Bounds`](../enum.Error.html#variant.Bounds):
79	///   The rva falls outside any valid section or the PE headers.
80	fn rva_to_file_offset(self, rva: Rva) -> Result<usize> {
81		// Consider rva inside headers to be valid
82		if rva < self.optional_header().SizeOfHeaders {
83			return Ok(rva as usize);
84		}
85		// This code has been carefully designed to avoid panicking on overflow
86		for it in self.section_headers() {
87			// Compare if rva is contained within the virtual address space of a section
88			// If the calculating the section end address overflows the corrupt section will be skipped
89			#[allow(non_snake_case)]
90			let VirtualEnd = it.VirtualAddress.wrapping_add(cmp::max(it.VirtualSize, it.SizeOfRawData));
91			if it.VirtualAddress <= rva && rva < VirtualEnd { // $1
92				// Check if the raw data reference is sane
93				if let None = it.PointerToRawData.checked_add(it.SizeOfRawData) { // $2
94					return Err(Error::Overflow);
95				}
96				// Calculate the offset in the section. cannot underflow, see $1
97				let section_offset = rva - it.VirtualAddress;
98				return if section_offset < it.SizeOfRawData { // $3
99					// Calculate the final offset in the file. cannot overflow, see $2 and $3
100					Ok((section_offset + it.PointerToRawData) as usize)
101				}
102				// Identify the reason the conversion fails
103				else if section_offset < it.VirtualSize {
104					Err(Error::ZeroFill)
105				}
106				else {
107					Err(Error::Bounds)
108				};
109			}
110		}
111		Err(Error::Bounds)
112	}
113	/// Converts a file offset to relative virtual address.
114	///
115	/// # Errors
116	///
117	/// * [`Overflow`](../enum.Error.html#variant.Overflow):
118	///   The file offset is contained within a corrupt section where the range bounds overflow.
119	///
120	/// * [`Unmapped`](../enum.Error.html#variant.Unmapped):
121	///   The file offset points to part of a section not mapped and is not available in virtual memory.
122	///
123	/// * [`Bounds`](../enum.Error.html#variant.Bounds):
124	///   The file offset falls outside any valid section or PE headers.
125	fn file_offset_to_rva(self, file_offset: usize) -> Result<Rva> {
126		// Consider rva inside headers to be valid
127		if file_offset < self.optional_header().SizeOfHeaders as usize {
128			return Ok(file_offset as Rva);
129		}
130		// This code has been carefully designed to avoid panicking on overflow
131		for it in self.section_headers() {
132			// Compare if file_offset is contained within the raw data of a section
133			// If the calculating the section end address overflows the corrupt section will be skipped
134			#[allow(non_snake_case)]
135			let EndOfRawData = it.PointerToRawData.wrapping_add(it.SizeOfRawData);
136			if it.PointerToRawData as usize <= file_offset && file_offset < EndOfRawData as usize { // $1
137				// Check if the virtual reference is sane
138				if let None = it.VirtualAddress.checked_add(it.VirtualSize) { // $2
139					return Err(Error::Overflow);
140				}
141				// Calculate the offset in the section. cannot underflow, see $1
142				let section_offset = file_offset as Rva - it.PointerToRawData;
143				return if section_offset < it.VirtualSize { // $3
144					// Calculate the final virtual address. cannot overflow, see $2 and $3
145					Ok(section_offset + it.VirtualAddress)
146				}
147				// Identify the reason the conversion fails
148				else if section_offset < it.SizeOfRawData {
149					Err(Error::Unmapped)
150				}
151				else {
152					Err(Error::Bounds)
153				};
154			}
155		}
156		Err(Error::Bounds)
157	}
158
159	/// Converts from relative virtual address to virtual address.
160	///
161	/// # Errors
162	///
163	/// * [`Null`](../enum.Error.html#variant.Null):
164	///   The rva is zero.
165	///
166	/// * [`Bounds`](../enum.Error.html#variant.Bounds):
167	///   The rva does not fall within the virtual image bounds.
168	fn rva_to_va(self, rva: Rva) -> Result<Va> {
169		if rva == 0 {
170			Err(Error::Null)
171		}
172		else {
173			let (image_base, size_of_image) = {
174				let optional_header = self.optional_header();
175				(optional_header.ImageBase, optional_header.SizeOfImage)
176			};
177			if rva < size_of_image {
178				Ok(image_base + rva as Va)
179			}
180			else {
181				Err(Error::Bounds)
182			}
183		}
184	}
185	/// Converts from virtual address to relative virtual address.
186	///
187	/// # Errors
188	///
189	/// * [`Null`](../enum.Error.html#variant.Null):
190	///   The va is zero.
191	///
192	/// * [`Bounds`](../enum.Error.html#variant.Bounds):
193	///   The va does not fall within the virtual image bounds.
194	fn va_to_rva(self, va: Va) -> Result<Rva> {
195		if va == 0 {
196			Err(Error::Null)
197		}
198		else {
199			let (image_base, size_of_image) = {
200				let optional_header = self.optional_header();
201				(optional_header.ImageBase, optional_header.SizeOfImage)
202			};
203			// Carefully avoid panicking overflow
204			if va < image_base || va - image_base > size_of_image as Va {
205				Err(Error::Bounds)
206			}
207			else {
208				Ok((va - image_base) as Rva)
209			}
210		}
211	}
212
213	//----------------------------------------------------------------
214
215	/// Slices the image at the specified rva.
216	///
217	/// If successful the returned slice's length will be at least the given size but often be quite larger.
218	/// This allows to access the image without knowing beforehand how large the structure being accessed will be.
219	///
220	/// The length is the largest consecutive number of bytes available until the end.
221	/// In case the of PE files on disk, this is limited to the section's size of raw data.
222	///
223	/// # Errors
224	///
225	/// * [`Null`](../enum.Error.html#variant.Null):
226	///   The rva is zero.
227	fn slice(&self, rva: Rva, min_size_of: usize, align: usize) -> Result<&'a [u8]> {
228		unsafe {
229			match (self.align(), self.image()) {
230				(Align::File, image) => slice_file(image, rva, min_size_of, align),
231				(Align::Section, image) => slice_section(image, rva, min_size_of, align),
232			}
233		}
234	}
235
236	/// Slices the image at the specified rva returning a byte slice with no alignment or minimum size.
237	///
238	/// Shorthand to invoke [`slice(rva, 0, 1)`](#tymethod.slice).
239	fn slice_bytes(self, rva: Rva) -> Result<&'a [u8]> where Self: Sized {
240		self.slice(rva, 0, 1)
241	}
242
243	/// Gets the bytes defined by a section header in this image.
244	///
245	/// # Errors
246	///
247	/// * [`Null`](../enum.Error.html#variant.Null):
248	///   The virtual address or pointer to raw data is zero.
249	///
250	/// * [`Bounds`](../enum.Error.html#variant.Bounds):
251	///   The data referenced by the section header is out of bounds.
252	fn get_section_bytes(self, section_header: &IMAGE_SECTION_HEADER) -> Result<&'a [u8]> {
253		crate::wrap::get_section_bytes(self.image(), section_header, self.align())
254	}
255
256	/// Reads the image at the specified va.
257	///
258	/// If successful the returned slice's length will be at least the given size but often be quite larger.
259	/// This allows to access the image without knowing beforehand how large the structure being accessed will be.
260	///
261	/// The length is the largest consecutive number of bytes available until the end.
262	/// In case the of PE files on disk, this is limited to the section's size of raw data.
263	///
264	/// # Errors
265	///
266	/// * [`Null`](../enum.Error.html#variant.Null):
267	///   The va is zero.
268	fn read(&self, va: Va, min_size_of: usize, align: usize) -> Result<&'a [u8]> {
269		unsafe {
270			match (self.align(), self.image()) {
271				(Align::File, image) => read_file(image, va, min_size_of, align),
272				(Align::Section, image) => read_section(image, va, min_size_of, align),
273			}
274		}
275	}
276
277	/// Reads the image at the specified va returning a byte slice with no alignment or minimum size.
278	///
279	/// Shorthand to invoke [`read(va, 0, 1)`](#tymethod.read).
280	fn read_bytes(self, va: Va) -> Result<&'a [u8]> where Self: Sized {
281		self.read(va, 0, 1)
282	}
283
284	//----------------------------------------------------------------
285
286	/// Reads an aligned pod `T`.
287	fn derva<T>(self, rva: Rva) -> Result<&'a T> where T: Pod {
288		let align = if cfg!(feature = "unsafe_alignment") { 1 } else { mem::align_of::<T>() };
289		let bytes = self.slice(rva, mem::size_of::<T>(), align)?;
290		// This is safe as per Pod bound, min_size_of and align
291		unsafe {
292			let p = &*(bytes.as_ptr() as *const T);
293			Ok(p)
294		}
295	}
296	/// Reads an unaligned pod `T`.
297	fn derva_copy<T>(self, rva: Rva) -> Result<T> where T: Copy + Pod {
298		let bytes = self.slice(rva, mem::size_of::<T>(), 1)?;
299		// This is safe as per Pod bound and min_size_of
300		unsafe {
301			let p = bytes.as_ptr() as *const T;
302			Ok(ptr::read_unaligned(p))
303		}
304	}
305	/// Reads and byte-wise copies the content to the given destination.
306	///
307	/// Allows reading of an unaligned array of data.
308	fn derva_into<T>(self, rva: Rva, dest: &mut T) -> Result<()> where T: ?Sized + Pod {
309		let len = mem::size_of_val(dest);
310		let bytes = self.slice(rva, len, 1)?;
311		dataview::bytes_mut(dest).copy_from_slice(&bytes[..len]);
312		Ok(())
313	}
314	/// Reads an array of pod `T` with given length.
315	fn derva_slice<T>(self, rva: Rva, len: usize) -> Result<&'a [T]> where T: Pod {
316		let min_size_of = mem::size_of::<T>().checked_mul(len).ok_or(Error::Overflow)?;
317		let align = if cfg!(feature = "unsafe_alignment") { 1 } else { mem::align_of::<T>() };
318		let bytes = self.slice(rva, min_size_of, align)?;
319		// This is safe as per Pod bound, min_size_of and align
320		unsafe {
321			Ok(slice::from_raw_parts(bytes.as_ptr() as *const T, len))
322		}
323	}
324	/// Reads an array of pod `T`.
325	///
326	/// For every element of the array, starting at the given `rva`, the callable `f` is called with that element.
327	/// The length of the array is the index when the callable `f` returns `true`.
328	///
329	/// The returned slice contains all `T` up to but not including the element for which the callable returned `true`.
330	fn derva_slice_f<T, F>(self, rva: Rva, mut f: F) -> Result<&'a [T]> where T: Pod, F: FnMut(&'a T) -> bool {
331		let align = if cfg!(feature = "unsafe_alignment") { 1 } else { mem::align_of::<T>() };
332		let bytes = self.slice(rva, 0, align)?;
333		let mut len = 0;
334		loop {
335			// Safety critical OOB check
336			// Overflows only if bytes.len() > USIZE_MAX - sizeof(T) which would be ridiculous
337			let offset = len * mem::size_of::<T>();
338			if offset + mem::size_of::<T>() > bytes.len() {
339				return Err(Error::Bounds);
340			}
341			// Safe because len is checked above and T is Pod
342			unsafe {
343				let s = bytes.as_ptr().offset(offset as isize) as *const T;
344				if f(&*s) {
345					let p = slice::from_raw_parts(bytes.as_ptr() as *const T, len);
346					return Ok(p);
347				}
348				len += 1;
349			}
350		}
351	}
352	/// Reads an array of pod `T`.
353	///
354	/// The length of the array is determined by a [sentinel value](https://en.wikipedia.org/wiki/Sentinel_value), a special value of `T` which marks the end of the array.
355	///
356	/// The returned slice contains all `T` up to but not including the sentinel value.
357	fn derva_slice_s<T>(self, rva: Rva, sentinel: T) -> Result<&'a [T]> where T: PartialEq + Pod {
358		self.derva_slice_f(rva, |tee| *tee == sentinel)
359	}
360	/// Reads a nul-terminated C string.
361	fn derva_c_str(self, rva: Rva) -> Result<&'a CStr> {
362		self.derva_string(rva)
363	}
364	/// Reads a string.
365	fn derva_string<T>(self, rva: Rva) -> Result<&'a T> where T: FromBytes + ?Sized {
366		let bytes = self.slice(rva, T::MIN_SIZE_OF, T::ALIGN_OF)?;
367		unsafe { T::from_bytes(bytes).ok_or(Error::Encoding) }
368	}
369
370	//----------------------------------------------------------------
371	// Deref impls for `Ptr`s
372
373	/// Dereferences the pointer to a pod `T`.
374	fn deref<T>(self, ptr: Ptr<T>) -> Result<&'a T> where T: Pod {
375		let align = if cfg!(feature = "unsafe_alignment") { 1 } else { mem::align_of::<T>() };
376		let bytes = self.read(ptr.into(), mem::size_of::<T>(), align)?;
377		// This is safe as per Pod bound, min_size_of and align
378		unsafe {
379			let p = &*(bytes.as_ptr() as *const T);
380			Ok(p)
381		}
382	}
383	/// Dereferences the pointer to an unaligned pod `T`.
384	fn deref_copy<T>(self, ptr: Ptr<T>) -> Result<T> where T: Copy + Pod {
385		let bytes = self.read(ptr.into(), mem::size_of::<T>(), 1)?;
386		// This is safe as per Pod bound and min_size_of
387		unsafe {
388			let p = bytes.as_ptr() as *const T;
389			Ok(ptr::read_unaligned(p))
390		}
391	}
392	/// Reads and byte-wise copies the content to the given destination.
393	///
394	/// Allows reading of an unaligned array of data.
395	fn deref_into<T>(self, ptr: Ptr<T>, dest: &mut T) -> Result<()> where T: ?Sized + Pod {
396		let len = mem::size_of_val(dest);
397		let bytes = self.read(ptr.into(), len, 1)?;
398		dataview::bytes_mut(dest).copy_from_slice(&bytes[..len]);
399		Ok(())
400	}
401	/// Reads an array of pod `T` with given length.
402	fn deref_slice<T>(self, ptr: Ptr<[T]>, len: usize) -> Result<&'a [T]> where T: Pod {
403		let min_size_of = mem::size_of::<T>().checked_mul(len).ok_or(Error::Overflow)?;
404		let align = if cfg!(feature = "unsafe_alignment") { 1 } else { mem::align_of::<T>() };
405		let bytes = self.read(ptr.into(), min_size_of, align)?;
406		// This is safe as per Pod bound, min_size_of and align
407		unsafe {
408			Ok(slice::from_raw_parts(bytes.as_ptr() as *const T, len))
409		}
410	}
411	/// Reads an array of pod `T`.
412	///
413	/// For every element of the array, starting at the given `ptr`, the callable `f` is called with that element.
414	/// The length of the array is the index when the callable `f` returns `true`.
415	///
416	/// The returned slice contains all `T` up to but not including the element for which the callable returned `true`.
417	fn deref_slice_f<T, F>(self, ptr: Ptr<[T]>, mut f: F) -> Result<&'a [T]> where T: Pod, F: FnMut(&'a T) -> bool {
418		let align = if cfg!(feature = "unsafe_alignment") { 1 } else { mem::align_of::<T>() };
419		let bytes = self.read(ptr.into(), 0, align)?;
420		let mut len = 0;
421		loop {
422			// Safety critical OOB check
423			// Overflows only if bytes.len() > USIZE_MAX - sizeof(T) which would be ridiculous
424			let offset = len * mem::size_of::<T>();
425			if offset + mem::size_of::<T>() > bytes.len() {
426				return Err(Error::Bounds);
427			}
428			// Safe because len is checked above and T is Pod
429			unsafe {
430				let s = bytes.as_ptr().offset(offset as isize) as *const T;
431				if f(&*s) {
432					let p = slice::from_raw_parts(bytes.as_ptr() as *const T, len);
433					return Ok(p);
434				}
435				len += 1;
436			}
437		}
438	}
439	/// Reads an array of pod `T`.
440	///
441	/// The length of the array is determined by a [sentinel value](https://en.wikipedia.org/wiki/Sentinel_value), a special value of `T` which marks the end of the array.
442	///
443	/// The returned slice contains all `T` up to but not including the sentinel value.
444	fn deref_slice_s<T>(self, ptr: Ptr<[T]>, sentinel: T) -> Result<&'a [T]> where T: PartialEq + Pod {
445		self.deref_slice_f(ptr, |tee| *tee == sentinel)
446	}
447	/// Dereferences the pointer to a nul-terminated C string.
448	fn deref_c_str(self, ptr: Ptr<CStr>) -> Result<&'a CStr> {
449		self.deref_string(ptr)
450	}
451	/// Dereferences the pointer to a string.
452	fn deref_string<T>(self, ptr: Ptr<T>) -> Result<&'a T> where T: FromBytes + ?Sized {
453		let bytes = self.read(ptr.into(), T::MIN_SIZE_OF, T::ALIGN_OF)?;
454		unsafe { T::from_bytes(bytes).ok_or(Error::Encoding) }
455	}
456
457	//----------------------------------------------------------------
458
459	/// Returns the Rich structure.
460	fn rich_structure(self) -> Result<crate::rich_structure::RichStructure<'a>> {
461		let image = self.image();
462		let image = unsafe { slice::from_raw_parts(image.as_ptr() as *const u32, image.len() / 4) };
463		crate::rich_structure::RichStructure::try_from(image)
464	}
465
466	/// Gets the Export Directory.
467	///
468	/// See the [exports](exports/index.html) module for more information.
469	///
470	/// Returns [`Err(Null)`](../enum.Error.html#variant.Null) if the image has no exports. Any other error indiciates some form of corruption.
471	fn exports(self) -> Result<super::exports::Exports<'a, Self>> {
472		super::exports::Exports::try_from(self)
473	}
474
475	/// Gets the Import Directory.
476	///
477	/// See the [imports](imports/index.html) module for more information.
478	///
479	/// Returns [`Err(Null)`](../enum.Error.html#variant.Null) if the image has no imports. Any other error indicates some form of corruption.
480	fn imports(self) -> Result<super::imports::Imports<'a, Self>> {
481		super::imports::Imports::try_from(self)
482	}
483
484	/// Gets the Import Address Table.
485	///
486	/// See the [imports](imports/index.html) module for more information.
487	///
488	/// Returns [`Err(Null)`](../enum.Error.html#variant.Null) if the image has no iat. Any other error indicates some form of corruption.
489	fn iat(self) -> Result<super::imports::IAT<'a, Self>> {
490		super::imports::IAT::try_from(self)
491	}
492
493	/// Gets the Base Relocations Directory.
494	///
495	/// See the [base relocations](base_relocs/index.html) module for more information.
496	///
497	/// Returns [`Err(Null)`](../enum.Error.html#variant.Null) if the image has no base relocations. Any other error indicates some form of corruption.
498	fn base_relocs(self) -> Result<crate::base_relocs::BaseRelocs<'a>> {
499		super::base_relocs::try_from(self)
500	}
501
502	/// Gets the Load Config Directory.
503	///
504	/// See the [load config](load_config/index.html) module for more information.
505	///
506	/// Returns [`Err(Null)`](../enum.Error.html#variant.Null) if the image has no load config. Any other error indicates some form of corruption.
507	fn load_config(self) -> Result<super::load_config::LoadConfig<'a, Self>> {
508		super::load_config::LoadConfig::try_from(self)
509	}
510
511	/// Gets the TLS Directory.
512	///
513	/// See the [tls](tls/index.html) module for more information.
514	///
515	/// Returns [`Err(Null)`](../enum.Error.html#variant.Null) if the image has no tls. Any other error indicates some form of corruption.
516	fn tls(self) -> Result<super::tls::Tls<'a, Self>> {
517		super::tls::Tls::try_from(self)
518	}
519
520	/// Gets the Security Directory.
521	///
522	/// See the [security](security/index.html) module for more information.
523	///
524	/// Returns [`Err(Null)`](../enum.Error.html#variant.Null) if the image has no security info. Any other error indicates some form of corruption.
525	fn security(self) -> Result<crate::security::Security<'a>> {
526		super::security::try_from(self)
527	}
528
529	/// Gets the Exception Directory.
530	///
531	/// See the [exception](exception/index.html) module for more information.
532	///
533	/// Returns [`Err(Null)`](../enum.Error.html#variant.Null) if the image has no exception directory. Any other error indicates some form of corruption.
534	fn exception(self) -> Result<super::exception::Exception<'a, Self>> {
535		super::exception::Exception::try_from(self)
536	}
537
538	/// Gets the Debug Directory.
539	///
540	/// See the [debug](debug/index.html) module for more information.
541	///
542	/// Returns [`Err(Null)`](../enum.Error.html#variant.Null) if the image has no debug info. Any other error indicates some form of corruption.
543	fn debug(self) -> Result<super::debug::Debug<'a, Self>> {
544		super::debug::Debug::try_from(self)
545	}
546
547	/// Gets the Resources.
548	///
549	/// See the [resources](resources/index.html) module for more information.
550	///
551	/// Returns [`Err(Null)`](../enum.Error.html#variant.Null) if the image has no resources. Any other error indicates some form of corruption.
552	#[cfg(any(feature = "std", feature = "resources_nostd"))]
553	fn resources(self) -> Result<crate::resources::Resources<'a>> where Self: Copy {
554		let datadir = self.data_directory().get(IMAGE_DIRECTORY_ENTRY_RESOURCE).ok_or(Error::Bounds)?;
555		let bytes = self.slice_bytes(datadir.VirtualAddress)?;
556		let size = cmp::min(datadir.Size as usize, bytes.len());
557		Ok(crate::resources::Resources::new(&bytes[..size], datadir))
558	}
559
560	/// Gets Scanner access.
561	///
562	/// See the [scanner](scanner/index.html) module for more information.
563	fn scanner(self) -> super::scanner::Scanner<Self> {
564		super::scanner::Scanner::new(self)
565	}
566}
567
568//----------------------------------------------------------------
569// Make `&PeObject<'a>` trait objects work seamlessly.
570
571unsafe impl<'s, 'a> PeObject<'a> for &'s dyn PeObject<'a> {
572	fn image(&self) -> &'a [u8] {
573		PeObject::image(*self)
574	}
575	fn align(&self) -> Align {
576		PeObject::align(*self)
577	}
578	#[cfg(feature = "serde")]
579	fn serde_name(&self) -> &'static str {
580		PeObject::serde_name(*self)
581	}
582}
583
584unsafe impl<'s, 'a> Pe<'a> for &'s dyn PeObject<'a> {}
585
586//----------------------------------------------------------------
587
588#[cfg(feature = "serde")]
589pub(crate) fn serialize_pe<'a, P: Pe<'a>, S: serde::Serializer>(pe: P, serializer: S) -> std::result::Result<S::Ok, S::Error> {
590	use crate::util::serde_helper::*;
591
592	let mut state = serializer.serialize_struct(pe.serde_name(), 10)?;
593	state.serialize_field("headers", &pe.headers())?;
594	state.serialize_field("rich_structure", &pe.rich_structure().ok())?;
595	state.serialize_field("exports", &pe.exports().ok())?;
596	state.serialize_field("imports", &pe.imports().ok())?;
597	state.serialize_field("base_relocs", &pe.base_relocs().ok())?;
598	state.serialize_field("debug", &pe.debug().ok())?;
599	state.serialize_field("tls", &pe.tls().ok())?;
600	state.serialize_field("load_config", &pe.load_config().ok())?;
601	state.serialize_field("security", &pe.security().ok())?;
602	state.serialize_field("resources", &pe.resources().ok())?;
603	state.end()
604}
605
606//----------------------------------------------------------------
607// Implementation helpers
608
609unsafe fn dos_header(image: &[u8]) -> &IMAGE_DOS_HEADER {
610	&*(image.as_ptr() as *const IMAGE_DOS_HEADER)
611}
612unsafe fn dos_image(image: &[u8]) -> &[u8] {
613	image.get_unchecked(..dos_header(image).e_lfanew as usize)
614}
615unsafe fn nt_headers(image: &[u8]) -> &IMAGE_NT_HEADERS {
616	&*(image.as_ptr().offset(dos_header(image).e_lfanew as isize) as *const IMAGE_NT_HEADERS)
617}
618unsafe fn file_header(image: &[u8]) -> &IMAGE_FILE_HEADER {
619	&nt_headers(image).FileHeader
620}
621unsafe fn optional_header(image: &[u8]) -> &IMAGE_OPTIONAL_HEADER {
622	&nt_headers(image).OptionalHeader
623}
624unsafe fn data_directory(image: &[u8]) -> &[IMAGE_DATA_DIRECTORY] {
625	let opt = optional_header(image);
626	let len = cmp::min(opt.NumberOfRvaAndSizes as usize, IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
627	slice::from_raw_parts(opt.DataDirectory.as_ptr(), len)
628}
629unsafe fn section_headers(image: &[u8]) -> &super::headers::SectionHeaders {
630	let nt = nt_headers(image);
631	let data = (&nt.OptionalHeader as *const _ as *const u8).offset(nt.FileHeader.SizeOfOptionalHeader as isize) as *const IMAGE_SECTION_HEADER;
632	let raw = slice::from_raw_parts(data, nt.FileHeader.NumberOfSections as usize);
633	super::headers::SectionHeaders::new(raw)
634}
635
636unsafe fn slice_section(image: &[u8], rva: Rva, min_size_of: usize, align_of: usize) -> Result<&[u8]> {
637	let start = rva as usize;
638	if rva == 0 {
639		Err(Error::Null)
640	}
641	else if !usize::wrapping_add(image.as_ptr() as usize, start).aligned_to(align_of) {
642		Err(Error::Misaligned)
643	}
644	else {
645		match image.get(start..) {
646			Some(bytes) if bytes.len() >= min_size_of => Ok(bytes),
647			_ => Err(Error::Bounds),
648		}
649	}
650}
651unsafe fn read_section(image: &[u8], va: Va, min_size_of: usize, align_of: usize) -> Result<&[u8]> {
652	let (image_base, image_size) = {
653		let optional_header = optional_header(image);
654		(optional_header.ImageBase, optional_header.SizeOfImage)
655	};
656	if va == 0 {
657		Err(Error::Null)
658	}
659	else if va < image_base || va - image_base > image_size as Va {
660		Err(Error::Bounds)
661	}
662	else {
663		let start = (va - image_base) as usize;
664		if !usize::wrapping_add(image.as_ptr() as usize, start).aligned_to(align_of) {
665			Err(Error::Misaligned)
666		}
667		else {
668			match image.get(start..) {
669				Some(bytes) if bytes.len() >= min_size_of => Ok(bytes),
670				_ => Err(Error::Bounds),
671			}
672		}
673	}
674}
675
676unsafe fn range_file(image: &[u8], rva: Rva, min_size_of: usize) -> Result<&[u8]> {
677	// This code has been carefully designed to avoid panicking on overflow
678	for it in section_headers(image) {
679		// Compare if rva is contained within the virtual address space of a section
680		// If the calculating the section end address overflows the corrupt section will be skipped
681		#[allow(non_snake_case)]
682		let VirtualEnd = it.VirtualAddress.wrapping_add(cmp::max(it.VirtualSize, it.SizeOfRawData));
683		if it.VirtualAddress <= rva && rva < VirtualEnd { // $1
684			// Isolate and range check the pointer and size of raw data
685			// If this fails immediately abort and return an error
686			let section_range = it.PointerToRawData as usize..it.PointerToRawData.wrapping_add(it.SizeOfRawData) as usize;
687			let section_bytes = image.get(section_range).ok_or(Error::Invalid)?;
688			// Calculate the offset in the section requested. cannot underflow, see $1
689			let section_offset = (rva - it.VirtualAddress) as usize;
690			return match section_bytes.get(section_offset..) {
691				Some(bytes) if bytes.len() >= min_size_of => Ok(bytes),
692				// Identify the reason the slice fails. cannot underflow, see $1
693				_ => Err(if min_size_of > (VirtualEnd - rva) as usize { Error::Bounds } else { Error::ZeroFill }),
694			};
695		}
696	}
697	Err(Error::Bounds)
698}
699#[inline(never)]
700unsafe fn slice_file(image: &[u8], rva: Rva, min_size_of: usize, align_of: usize) -> Result<&[u8]> {
701	if rva == 0 {
702		Err(Error::Null)
703	}
704	else if !usize::wrapping_add(image.as_ptr() as usize, rva as usize).aligned_to(align_of) {
705		Err(Error::Misaligned)
706	}
707	else {
708		range_file(image, rva, min_size_of)
709	}
710}
711#[inline(never)]
712unsafe fn read_file(image: &[u8], va: Va, min_size_of: usize, align_of: usize) -> Result<&[u8]> {
713	let (image_base, size_of_image) = {
714		let optional_header = optional_header(image);
715		(optional_header.ImageBase, optional_header.SizeOfImage)
716	};
717	if va == 0 {
718		Err(Error::Null)
719	}
720	else if va < image_base || va - image_base > size_of_image as Va {
721		Err(Error::Bounds)
722	}
723	else {
724		let rva = (va - image_base) as Rva;
725		if !usize::wrapping_add(image.as_ptr() as usize, rva as usize).aligned_to(align_of) {
726			Err(Error::Misaligned)
727		}
728		else {
729			range_file(image, rva, min_size_of)
730		}
731	}
732}
733
734//----------------------------------------------------------------
735
736// TODO: This code needs to be audited...
737// The safety of `Pe` relies on it.
738pub(crate) fn validate_headers(image: &[u8]) -> Result<u32> {
739	// Grab the DOS header
740	if mem::size_of::<IMAGE_DOS_HEADER>() > image.len() {
741		return Err(Error::Bounds);
742	}
743	// Check basic alignment of the image bytes
744	if !image.as_ptr().aligned_to(4) {
745		return Err(Error::Misaligned);
746	}
747	let dos = unsafe { &*(image.as_ptr() as *const IMAGE_DOS_HEADER) };
748	// Verify the DOS header
749	if dos.e_magic != IMAGE_DOS_SIGNATURE {
750		return Err(Error::BadMagic);
751	}
752	// "According to the PE specification, the PE header must be aligned on a 8 byte boundary, but the Windows loader requires only a 4 byte alignment."
753	if !dos.e_lfanew.aligned_to(4) {
754		return Err(Error::Misaligned);
755	}
756	// Prevent overflow the easy way...
757	// When changing, take care of overflow in later offset calculations!
758	if dos.e_lfanew > 0x01000000 {
759		return Err(Error::Insanity);
760	}
761
762	// Grab the NT headers
763	let nt_end = dos.e_lfanew as usize + mem::size_of::<IMAGE_NT_HEADERS>();
764	if nt_end > image.len() {
765		return Err(Error::Bounds);
766	}
767	let nt = unsafe { &*(image.as_ptr().offset(dos.e_lfanew as isize) as *const IMAGE_NT_HEADERS) };
768	// Verify the NT headers
769	if nt.Signature != IMAGE_NT_HEADERS_SIGNATURE ||
770		!(nt.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC || nt.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
771	{
772		return Err(Error::BadMagic);
773	}
774	if nt.OptionalHeader.SizeOfHeaders as usize > image.len() {
775		return Err(Error::Bounds);
776	}
777	if nt.OptionalHeader.SizeOfHeaders > nt.OptionalHeader.SizeOfImage {
778		return Err(Error::Insanity);
779	}
780	// Give the caller a chance to retry with the correct parser
781	if nt.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC {
782		return Err(Error::PeMagic);
783	}
784
785	// Verify the data directory
786	let num_rva_sizes = cmp::min(
787		nt.OptionalHeader.NumberOfRvaAndSizes as usize,
788		IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
789	let size_of_data_dir = num_rva_sizes * mem::size_of::<IMAGE_DATA_DIRECTORY>();
790	if nt_end + size_of_data_dir > image.len() {
791		return Err(Error::Bounds);
792	}
793
794	// Verify the section headers
795	if nt.FileHeader.NumberOfSections > 96 {
796		return Err(Error::Insanity);
797	}
798	// u16 * sizeof(T) casted to usize, cannot reasonably overflow
799	let size_of_sections = nt.FileHeader.NumberOfSections as usize * mem::size_of::<IMAGE_SECTION_HEADER>();
800	// e_lfanew is checked for reasonable values, the others then cannot reasonably cause overflow
801	let start_of_sections = dos.e_lfanew as usize
802		+ (mem::size_of::<IMAGE_NT_HEADERS>() - mem::size_of::<IMAGE_OPTIONAL_HEADER>())
803		+ nt.FileHeader.SizeOfOptionalHeader as usize;
804	// then the sum of these cannot reasonably overflow
805	if size_of_sections + start_of_sections > image.len() {
806		return Err(Error::Bounds);
807	}
808	Ok(nt.OptionalHeader.SizeOfImage)
809}
810
811/// Returns the PE headers as mutable borrows.
812///
813/// # Safety
814///
815/// No checks of any kind are performed, before calling this function ensure the byte slice points to a valid PE image by running it through the `PeFile::from_bytes` constructor.
816#[cfg(feature = "unstable")]
817pub unsafe fn headers_mut(image: &mut [u8]) -> (&mut IMAGE_DOS_HEADER, &mut IMAGE_NT_HEADERS, &mut [IMAGE_DATA_DIRECTORY], &mut [IMAGE_SECTION_HEADER]) {
818	let dos = &mut *(image.as_mut_ptr() as *mut IMAGE_DOS_HEADER);
819	let nt = &mut *(image.as_mut_ptr().offset(dos.e_lfanew as isize) as *mut IMAGE_NT_HEADERS);
820	let dd_ptr = nt.OptionalHeader.DataDirectory.as_mut_ptr();
821	let dd_len = cmp::min(nt.OptionalHeader.NumberOfRvaAndSizes as usize, IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
822	let dd = slice::from_raw_parts_mut(dd_ptr, dd_len);
823	let sections_ptr = (&mut nt.OptionalHeader as *mut _ as *mut u8).offset(nt.FileHeader.SizeOfOptionalHeader as isize) as *mut IMAGE_SECTION_HEADER;
824	let sections_len = nt.FileHeader.NumberOfSections as usize;
825	let sections = slice::from_raw_parts_mut(sections_ptr, sections_len);
826	(dos, nt, dd, sections)
827}