pelite\pe64/
view.rs

1/*!
2PE view.
3*/
4
5use std::prelude::v1::*;
6
7use std::{cmp, slice};
8
9use crate::Result;
10
11use super::image::*;
12use super::pe::validate_headers;
13use super::{Align, Pe, PeObject};
14
15/// View into a mapped PE image.
16#[derive(Copy, Clone)]
17pub struct PeView<'a> {
18	image: &'a [u8],
19}
20
21current_target! {
22	impl PeView<'static> {
23		/// Constructs a view of the module this code is executing in.
24		#[inline]
25		pub unsafe fn new() -> PeView<'static> {
26			Self::module(image_base() as *const _ as *const u8)
27		}
28	}
29}
30impl<'a> PeView<'a> {
31	/// Constructs a view from a byte slice.
32	///
33	/// # Errors
34	///
35	/// * [`Bounds`](../enum.Error.html#variant.Bounds):
36	///   The byte slice is too small to fit the PE headers.
37	///
38	/// * [`Misaligned`](../enum.Error.html#variant.Misaligned):
39	///   The minimum alignment of 4 is not satisfied.
40	///
41	/// * [`BadMagic`](../enum.Error.html#variant.BadMagic):
42	///   This is not a PE file.
43	///
44	/// * [`PeMagic`](../enum.Error.html#variant.PeMagic):
45	///   Trying to parse a PE32 file with the PE32+ parser and vice versa.
46	///
47	/// * [`Insanity`](../enum.Error.html#variant.Insanity):
48	///   Reasonable limits on `e_lfanew`, `SizeOfHeaders` or `NumberOfSections` are exceeded.
49	pub fn from_bytes<T: AsRef<[u8]> + ?Sized>(image: &'a T) -> Result<PeView<'a>> {
50		let image = image.as_ref();
51		let _ = validate_headers(image)?;
52		Ok(PeView { image })
53	}
54	/// Constructs a new view from module handle.
55	///
56	/// # Safety
57	///
58	/// The underlying memory is borrowed and an unbounded lifetime is returned.
59	/// Ensure the lifetime outlives this view instance!
60	///
61	/// No sanity or safety checks are done to make sure this is really PE32(+) image.
62	/// When using this with a `HMODULE` from the system the caller must be sure this is a PE32(+) image.
63	#[inline]
64	pub unsafe fn module(base: *const u8) -> PeView<'a> {
65		let dos = &*(base as *const IMAGE_DOS_HEADER);
66		let nt = &*(base.offset(dos.e_lfanew as isize) as *const IMAGE_NT_HEADERS);
67		PeView {
68			image: slice::from_raw_parts(base, nt.OptionalHeader.SizeOfImage as usize),
69		}
70	}
71	/// Converts the view to file alignment.
72	pub fn to_file(self) -> Vec<u8> {
73		let (sizeof_headers, sizeof_image) = {
74			let optional_header = self.optional_header();
75			(optional_header.SizeOfHeaders, optional_header.SizeOfImage)
76		};
77
78		// Figure out the size of the file image
79		let mut file_size = sizeof_headers;
80		for section in self.section_headers() {
81			file_size = cmp::max(file_size, u32::wrapping_add(section.PointerToRawData, section.SizeOfRawData));
82		}
83		// Clamp to the actual image size...
84		file_size = cmp::min(file_size, sizeof_image);
85
86		// Zero fill the underlying file
87		let mut vec = vec![0u8; file_size as usize];
88
89		// Start by copying the headers
90		let image = self.image();
91		unsafe {
92			// Validated by constructor
93			let dest_headers = vec.get_unchecked_mut(..sizeof_headers as usize);
94			let src_headers = image.get_unchecked(..sizeof_headers as usize);
95			dest_headers.copy_from_slice(src_headers);
96		}
97
98		// Copy the section image data
99		for section in self.section_headers() {
100			let dest = vec.get_mut(section.PointerToRawData as usize..u32::wrapping_add(section.PointerToRawData, section.SizeOfRawData) as usize);
101			let src = image.get(section.VirtualAddress as usize..u32::wrapping_add(section.VirtualAddress, section.VirtualSize) as usize);
102			// Skip invalid sections...
103			if let (Some(dest), Some(src)) = (dest, src) {
104				dest.copy_from_slice(src);
105			}
106		}
107
108		vec
109	}
110}
111
112//----------------------------------------------------------------
113
114unsafe impl<'a> Pe<'a> for PeView<'a> {}
115
116unsafe impl<'a> PeObject<'a> for PeView<'a> {
117	fn image(&self) -> &'a [u8] {
118		self.image
119	}
120	fn align(&self) -> Align {
121		Align::Section
122	}
123	#[cfg(feature = "serde")]
124	fn serde_name(&self) -> &'static str {
125		"PeView"
126	}
127}
128
129//----------------------------------------------------------------
130
131#[cfg(feature = "serde")]
132impl<'a> serde::Serialize for PeView<'a> {
133	fn serialize<S: serde::Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
134		super::pe::serialize_pe(*self, serializer)
135	}
136}
137
138//----------------------------------------------------------------
139
140#[cfg(test)]
141mod tests {
142	use crate::Error;
143	use super::PeView;
144
145	#[test]
146	fn from_byte_slice() {
147		assert!(match PeView::from_bytes(&[]) { Err(Error::Bounds) => true, _ => false });
148	}
149}