1 use core::marker::PhantomData;
2 use core::{cmp, iter, result, slice, str};
3 
4 use crate::endian::LittleEndian as LE;
5 use crate::pe;
6 use crate::read::{
7     self, CompressedData, CompressedFileRange, ObjectSection, ObjectSegment, ReadError, ReadRef,
8     Relocation, Result, SectionFlags, SectionIndex, SectionKind,
9 };
10 
11 use super::{ImageNtHeaders, PeFile, SectionTable};
12 
13 /// An iterator over the loadable sections of a `PeFile32`.
14 pub type PeSegmentIterator32<'data, 'file, R = &'data [u8]> =
15     PeSegmentIterator<'data, 'file, pe::ImageNtHeaders32, R>;
16 /// An iterator over the loadable sections of a `PeFile64`.
17 pub type PeSegmentIterator64<'data, 'file, R = &'data [u8]> =
18     PeSegmentIterator<'data, 'file, pe::ImageNtHeaders64, R>;
19 
20 /// An iterator over the loadable sections of a `PeFile`.
21 #[derive(Debug)]
22 pub struct PeSegmentIterator<'data, 'file, Pe, R = &'data [u8]>
23 where
24     Pe: ImageNtHeaders,
25     R: ReadRef<'data>,
26 {
27     pub(super) file: &'file PeFile<'data, Pe, R>,
28     pub(super) iter: slice::Iter<'data, pe::ImageSectionHeader>,
29 }
30 
31 impl<'data, 'file, Pe, R> Iterator for PeSegmentIterator<'data, 'file, Pe, R>
32 where
33     Pe: ImageNtHeaders,
34     R: ReadRef<'data>,
35 {
36     type Item = PeSegment<'data, 'file, Pe, R>;
37 
next(&mut self) -> Option<Self::Item>38     fn next(&mut self) -> Option<Self::Item> {
39         self.iter.next().map(|section| PeSegment {
40             file: self.file,
41             section,
42         })
43     }
44 }
45 
46 /// A loadable section of a `PeFile32`.
47 pub type PeSegment32<'data, 'file, R = &'data [u8]> =
48     PeSegment<'data, 'file, pe::ImageNtHeaders32, R>;
49 /// A loadable section of a `PeFile64`.
50 pub type PeSegment64<'data, 'file, R = &'data [u8]> =
51     PeSegment<'data, 'file, pe::ImageNtHeaders64, R>;
52 
53 /// A loadable section of a `PeFile`.
54 #[derive(Debug)]
55 pub struct PeSegment<'data, 'file, Pe, R = &'data [u8]>
56 where
57     Pe: ImageNtHeaders,
58     R: ReadRef<'data>,
59 {
60     file: &'file PeFile<'data, Pe, R>,
61     section: &'data pe::ImageSectionHeader,
62 }
63 
64 impl<'data, 'file, Pe, R> PeSegment<'data, 'file, Pe, R>
65 where
66     Pe: ImageNtHeaders,
67     R: ReadRef<'data>,
68 {
bytes(&self) -> Result<&'data [u8]>69     fn bytes(&self) -> Result<&'data [u8]> {
70         self.section
71             .pe_data(self.file.data)
72             .read_error("Invalid PE section offset or size")
73     }
74 }
75 
76 impl<'data, 'file, Pe, R> read::private::Sealed for PeSegment<'data, 'file, Pe, R>
77 where
78     Pe: ImageNtHeaders,
79     R: ReadRef<'data>,
80 {
81 }
82 
83 impl<'data, 'file, Pe, R> ObjectSegment<'data> for PeSegment<'data, 'file, Pe, R>
84 where
85     Pe: ImageNtHeaders,
86     R: ReadRef<'data>,
87 {
88     #[inline]
address(&self) -> u6489     fn address(&self) -> u64 {
90         u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base)
91     }
92 
93     #[inline]
size(&self) -> u6494     fn size(&self) -> u64 {
95         u64::from(self.section.virtual_size.get(LE))
96     }
97 
98     #[inline]
align(&self) -> u6499     fn align(&self) -> u64 {
100         self.file.section_alignment()
101     }
102 
103     #[inline]
file_range(&self) -> (u64, u64)104     fn file_range(&self) -> (u64, u64) {
105         let (offset, size) = self.section.pe_file_range();
106         (u64::from(offset), u64::from(size))
107     }
108 
data(&self) -> Result<&'data [u8]>109     fn data(&self) -> Result<&'data [u8]> {
110         self.bytes()
111     }
112 
data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>113     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
114         Ok(read::util::data_range(
115             self.bytes()?,
116             self.address(),
117             address,
118             size,
119         ))
120     }
121 
122     #[inline]
name(&self) -> Result<Option<&str>>123     fn name(&self) -> Result<Option<&str>> {
124         let name = self.section.name(self.file.common.symbols.strings())?;
125         Ok(Some(
126             str::from_utf8(name)
127                 .ok()
128                 .read_error("Non UTF-8 PE section name")?,
129         ))
130     }
131 }
132 
133 /// An iterator over the sections of a `PeFile32`.
134 pub type PeSectionIterator32<'data, 'file, R = &'data [u8]> =
135     PeSectionIterator<'data, 'file, pe::ImageNtHeaders32, R>;
136 /// An iterator over the sections of a `PeFile64`.
137 pub type PeSectionIterator64<'data, 'file, R = &'data [u8]> =
138     PeSectionIterator<'data, 'file, pe::ImageNtHeaders64, R>;
139 
140 /// An iterator over the sections of a `PeFile`.
141 #[derive(Debug)]
142 pub struct PeSectionIterator<'data, 'file, Pe, R = &'data [u8]>
143 where
144     'data: 'file,
145     Pe: ImageNtHeaders,
146     R: ReadRef<'data>,
147 {
148     pub(super) file: &'file PeFile<'data, Pe, R>,
149     pub(super) iter: iter::Enumerate<slice::Iter<'data, pe::ImageSectionHeader>>,
150 }
151 
152 impl<'data, 'file, Pe, R> Iterator for PeSectionIterator<'data, 'file, Pe, R>
153 where
154     Pe: ImageNtHeaders,
155     R: ReadRef<'data>,
156 {
157     type Item = PeSection<'data, 'file, Pe, R>;
158 
next(&mut self) -> Option<Self::Item>159     fn next(&mut self) -> Option<Self::Item> {
160         self.iter.next().map(|(index, section)| PeSection {
161             file: self.file,
162             index: SectionIndex(index + 1),
163             section,
164         })
165     }
166 }
167 
168 /// A section of a `PeFile32`.
169 pub type PeSection32<'data, 'file, R = &'data [u8]> =
170     PeSection<'data, 'file, pe::ImageNtHeaders32, R>;
171 /// A section of a `PeFile64`.
172 pub type PeSection64<'data, 'file, R = &'data [u8]> =
173     PeSection<'data, 'file, pe::ImageNtHeaders64, R>;
174 
175 /// A section of a `PeFile`.
176 #[derive(Debug)]
177 pub struct PeSection<'data, 'file, Pe, R = &'data [u8]>
178 where
179     'data: 'file,
180     Pe: ImageNtHeaders,
181     R: ReadRef<'data>,
182 {
183     pub(super) file: &'file PeFile<'data, Pe, R>,
184     pub(super) index: SectionIndex,
185     pub(super) section: &'data pe::ImageSectionHeader,
186 }
187 
188 impl<'data, 'file, Pe, R> PeSection<'data, 'file, Pe, R>
189 where
190     Pe: ImageNtHeaders,
191     R: ReadRef<'data>,
192 {
bytes(&self) -> Result<&'data [u8]>193     fn bytes(&self) -> Result<&'data [u8]> {
194         self.section
195             .pe_data(self.file.data)
196             .read_error("Invalid PE section offset or size")
197     }
198 }
199 
200 impl<'data, 'file, Pe, R> read::private::Sealed for PeSection<'data, 'file, Pe, R>
201 where
202     Pe: ImageNtHeaders,
203     R: ReadRef<'data>,
204 {
205 }
206 
207 impl<'data, 'file, Pe, R> ObjectSection<'data> for PeSection<'data, 'file, Pe, R>
208 where
209     Pe: ImageNtHeaders,
210     R: ReadRef<'data>,
211 {
212     type RelocationIterator = PeRelocationIterator<'data, 'file, R>;
213 
214     #[inline]
index(&self) -> SectionIndex215     fn index(&self) -> SectionIndex {
216         self.index
217     }
218 
219     #[inline]
address(&self) -> u64220     fn address(&self) -> u64 {
221         u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base)
222     }
223 
224     #[inline]
size(&self) -> u64225     fn size(&self) -> u64 {
226         u64::from(self.section.virtual_size.get(LE))
227     }
228 
229     #[inline]
align(&self) -> u64230     fn align(&self) -> u64 {
231         self.file.section_alignment()
232     }
233 
234     #[inline]
file_range(&self) -> Option<(u64, u64)>235     fn file_range(&self) -> Option<(u64, u64)> {
236         let (offset, size) = self.section.pe_file_range();
237         if size == 0 {
238             None
239         } else {
240             Some((u64::from(offset), u64::from(size)))
241         }
242     }
243 
data(&self) -> Result<&'data [u8]>244     fn data(&self) -> Result<&'data [u8]> {
245         self.bytes()
246     }
247 
data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>248     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
249         Ok(read::util::data_range(
250             self.bytes()?,
251             self.address(),
252             address,
253             size,
254         ))
255     }
256 
257     #[inline]
compressed_file_range(&self) -> Result<CompressedFileRange>258     fn compressed_file_range(&self) -> Result<CompressedFileRange> {
259         Ok(CompressedFileRange::none(self.file_range()))
260     }
261 
262     #[inline]
compressed_data(&self) -> Result<CompressedData<'data>>263     fn compressed_data(&self) -> Result<CompressedData<'data>> {
264         self.data().map(CompressedData::none)
265     }
266 
267     #[inline]
name(&self) -> Result<&str>268     fn name(&self) -> Result<&str> {
269         let name = self.section.name(self.file.common.symbols.strings())?;
270         str::from_utf8(name)
271             .ok()
272             .read_error("Non UTF-8 PE section name")
273     }
274 
275     #[inline]
segment_name(&self) -> Result<Option<&str>>276     fn segment_name(&self) -> Result<Option<&str>> {
277         Ok(None)
278     }
279 
280     #[inline]
kind(&self) -> SectionKind281     fn kind(&self) -> SectionKind {
282         self.section.kind()
283     }
284 
relocations(&self) -> PeRelocationIterator<'data, 'file, R>285     fn relocations(&self) -> PeRelocationIterator<'data, 'file, R> {
286         PeRelocationIterator(PhantomData)
287     }
288 
flags(&self) -> SectionFlags289     fn flags(&self) -> SectionFlags {
290         SectionFlags::Coff {
291             characteristics: self.section.characteristics.get(LE),
292         }
293     }
294 }
295 
296 impl<'data> SectionTable<'data> {
297     /// Return the data at the given virtual address in a PE file.
pe_data_at<R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]>298     pub fn pe_data_at<R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> {
299         self.iter()
300             .filter_map(|section| section.pe_data_at(data, va))
301             .next()
302     }
303 }
304 
305 impl pe::ImageSectionHeader {
306     /// Return the offset and size of the section in a PE file.
307     ///
308     /// Returns `None` for sections that have no data in the file.
pe_file_range(&self) -> (u32, u32)309     pub fn pe_file_range(&self) -> (u32, u32) {
310         // Pointer and size will be zero for uninitialized data; we don't need to validate this.
311         let offset = self.pointer_to_raw_data.get(LE);
312         let size = cmp::min(self.virtual_size.get(LE), self.size_of_raw_data.get(LE));
313         (offset, size)
314     }
315 
316     /// Return the section data in a PE file.
pe_data<'data, R: ReadRef<'data>>(&self, data: R) -> result::Result<&'data [u8], ()>317     pub fn pe_data<'data, R: ReadRef<'data>>(&self, data: R) -> result::Result<&'data [u8], ()> {
318         let (offset, size) = self.pe_file_range();
319         data.read_bytes_at(offset.into(), size.into())
320     }
321 
322     /// Return the data at the given virtual address if this section contains it.
pe_data_at<'data, R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]>323     pub fn pe_data_at<'data, R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> {
324         let section_va = self.virtual_address.get(LE);
325         let offset = va.checked_sub(section_va)?;
326         let section_data = self.pe_data(data).ok()?;
327         section_data.get(offset as usize..)
328     }
329 }
330 
331 /// An iterator over the relocations in an `PeSection`.
332 #[derive(Debug)]
333 pub struct PeRelocationIterator<'data, 'file, R = &'data [u8]>(
334     PhantomData<(&'data (), &'file (), R)>,
335 );
336 
337 impl<'data, 'file, R> Iterator for PeRelocationIterator<'data, 'file, R> {
338     type Item = (u64, Relocation);
339 
next(&mut self) -> Option<Self::Item>340     fn next(&mut self) -> Option<Self::Item> {
341         None
342     }
343 }
344