1 use core::marker::PhantomData;
2 use core::{cmp, iter, 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> read::private::Sealed for PeSegment<'data, 'file, Pe, R>
65 where
66     Pe: ImageNtHeaders,
67     R: ReadRef<'data>,
68 {
69 }
70 
71 impl<'data, 'file, Pe, R> ObjectSegment<'data> for PeSegment<'data, 'file, Pe, R>
72 where
73     Pe: ImageNtHeaders,
74     R: ReadRef<'data>,
75 {
76     #[inline]
address(&self) -> u6477     fn address(&self) -> u64 {
78         u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base)
79     }
80 
81     #[inline]
size(&self) -> u6482     fn size(&self) -> u64 {
83         u64::from(self.section.virtual_size.get(LE))
84     }
85 
86     #[inline]
align(&self) -> u6487     fn align(&self) -> u64 {
88         self.file.section_alignment()
89     }
90 
91     #[inline]
file_range(&self) -> (u64, u64)92     fn file_range(&self) -> (u64, u64) {
93         let (offset, size) = self.section.pe_file_range();
94         (u64::from(offset), u64::from(size))
95     }
96 
data(&self) -> Result<&'data [u8]>97     fn data(&self) -> Result<&'data [u8]> {
98         self.section.pe_data(self.file.data)
99     }
100 
data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>101     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
102         Ok(read::util::data_range(
103             self.data()?,
104             self.address(),
105             address,
106             size,
107         ))
108     }
109 
110     #[inline]
name_bytes(&self) -> Result<Option<&[u8]>>111     fn name_bytes(&self) -> Result<Option<&[u8]>> {
112         self.section
113             .name(self.file.common.symbols.strings())
114             .map(Some)
115     }
116 
117     #[inline]
name(&self) -> Result<Option<&str>>118     fn name(&self) -> Result<Option<&str>> {
119         let name = self.section.name(self.file.common.symbols.strings())?;
120         Ok(Some(
121             str::from_utf8(name)
122                 .ok()
123                 .read_error("Non UTF-8 PE section name")?,
124         ))
125     }
126 }
127 
128 /// An iterator over the sections of a `PeFile32`.
129 pub type PeSectionIterator32<'data, 'file, R = &'data [u8]> =
130     PeSectionIterator<'data, 'file, pe::ImageNtHeaders32, R>;
131 /// An iterator over the sections of a `PeFile64`.
132 pub type PeSectionIterator64<'data, 'file, R = &'data [u8]> =
133     PeSectionIterator<'data, 'file, pe::ImageNtHeaders64, R>;
134 
135 /// An iterator over the sections of a `PeFile`.
136 #[derive(Debug)]
137 pub struct PeSectionIterator<'data, 'file, Pe, R = &'data [u8]>
138 where
139     'data: 'file,
140     Pe: ImageNtHeaders,
141     R: ReadRef<'data>,
142 {
143     pub(super) file: &'file PeFile<'data, Pe, R>,
144     pub(super) iter: iter::Enumerate<slice::Iter<'data, pe::ImageSectionHeader>>,
145 }
146 
147 impl<'data, 'file, Pe, R> Iterator for PeSectionIterator<'data, 'file, Pe, R>
148 where
149     Pe: ImageNtHeaders,
150     R: ReadRef<'data>,
151 {
152     type Item = PeSection<'data, 'file, Pe, R>;
153 
next(&mut self) -> Option<Self::Item>154     fn next(&mut self) -> Option<Self::Item> {
155         self.iter.next().map(|(index, section)| PeSection {
156             file: self.file,
157             index: SectionIndex(index + 1),
158             section,
159         })
160     }
161 }
162 
163 /// A section of a `PeFile32`.
164 pub type PeSection32<'data, 'file, R = &'data [u8]> =
165     PeSection<'data, 'file, pe::ImageNtHeaders32, R>;
166 /// A section of a `PeFile64`.
167 pub type PeSection64<'data, 'file, R = &'data [u8]> =
168     PeSection<'data, 'file, pe::ImageNtHeaders64, R>;
169 
170 /// A section of a `PeFile`.
171 #[derive(Debug)]
172 pub struct PeSection<'data, 'file, Pe, R = &'data [u8]>
173 where
174     'data: 'file,
175     Pe: ImageNtHeaders,
176     R: ReadRef<'data>,
177 {
178     pub(super) file: &'file PeFile<'data, Pe, R>,
179     pub(super) index: SectionIndex,
180     pub(super) section: &'data pe::ImageSectionHeader,
181 }
182 
183 impl<'data, 'file, Pe, R> read::private::Sealed for PeSection<'data, 'file, Pe, R>
184 where
185     Pe: ImageNtHeaders,
186     R: ReadRef<'data>,
187 {
188 }
189 
190 impl<'data, 'file, Pe, R> ObjectSection<'data> for PeSection<'data, 'file, Pe, R>
191 where
192     Pe: ImageNtHeaders,
193     R: ReadRef<'data>,
194 {
195     type RelocationIterator = PeRelocationIterator<'data, 'file, R>;
196 
197     #[inline]
index(&self) -> SectionIndex198     fn index(&self) -> SectionIndex {
199         self.index
200     }
201 
202     #[inline]
address(&self) -> u64203     fn address(&self) -> u64 {
204         u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base)
205     }
206 
207     #[inline]
size(&self) -> u64208     fn size(&self) -> u64 {
209         u64::from(self.section.virtual_size.get(LE))
210     }
211 
212     #[inline]
align(&self) -> u64213     fn align(&self) -> u64 {
214         self.file.section_alignment()
215     }
216 
217     #[inline]
file_range(&self) -> Option<(u64, u64)>218     fn file_range(&self) -> Option<(u64, u64)> {
219         let (offset, size) = self.section.pe_file_range();
220         if size == 0 {
221             None
222         } else {
223             Some((u64::from(offset), u64::from(size)))
224         }
225     }
226 
data(&self) -> Result<&'data [u8]>227     fn data(&self) -> Result<&'data [u8]> {
228         self.section.pe_data(self.file.data)
229     }
230 
data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>231     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
232         Ok(read::util::data_range(
233             self.data()?,
234             self.address(),
235             address,
236             size,
237         ))
238     }
239 
240     #[inline]
compressed_file_range(&self) -> Result<CompressedFileRange>241     fn compressed_file_range(&self) -> Result<CompressedFileRange> {
242         Ok(CompressedFileRange::none(self.file_range()))
243     }
244 
245     #[inline]
compressed_data(&self) -> Result<CompressedData<'data>>246     fn compressed_data(&self) -> Result<CompressedData<'data>> {
247         self.data().map(CompressedData::none)
248     }
249 
250     #[inline]
name_bytes(&self) -> Result<&[u8]>251     fn name_bytes(&self) -> Result<&[u8]> {
252         self.section.name(self.file.common.symbols.strings())
253     }
254 
255     #[inline]
name(&self) -> Result<&str>256     fn name(&self) -> Result<&str> {
257         let name = self.name_bytes()?;
258         str::from_utf8(name)
259             .ok()
260             .read_error("Non UTF-8 PE section name")
261     }
262 
263     #[inline]
segment_name_bytes(&self) -> Result<Option<&[u8]>>264     fn segment_name_bytes(&self) -> Result<Option<&[u8]>> {
265         Ok(None)
266     }
267 
268     #[inline]
segment_name(&self) -> Result<Option<&str>>269     fn segment_name(&self) -> Result<Option<&str>> {
270         Ok(None)
271     }
272 
273     #[inline]
kind(&self) -> SectionKind274     fn kind(&self) -> SectionKind {
275         self.section.kind()
276     }
277 
relocations(&self) -> PeRelocationIterator<'data, 'file, R>278     fn relocations(&self) -> PeRelocationIterator<'data, 'file, R> {
279         PeRelocationIterator(PhantomData)
280     }
281 
flags(&self) -> SectionFlags282     fn flags(&self) -> SectionFlags {
283         SectionFlags::Coff {
284             characteristics: self.section.characteristics.get(LE),
285         }
286     }
287 }
288 
289 impl<'data> SectionTable<'data> {
290     /// Return the data at the given virtual address in a PE file.
291     ///
292     /// Ignores sections with invalid data.
pe_data_at<R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]>293     pub fn pe_data_at<R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> {
294         self.iter().find_map(|section| section.pe_data_at(data, va))
295     }
296 
297     /// Return the data of the section that contains the given virtual address in a PE file.
298     ///
299     /// Also returns the virtual address of that section.
300     ///
301     /// Ignores sections with invalid data.
pe_data_containing<R: ReadRef<'data>>( &self, data: R, va: u32, ) -> Option<(&'data [u8], u32)>302     pub fn pe_data_containing<R: ReadRef<'data>>(
303         &self,
304         data: R,
305         va: u32,
306     ) -> Option<(&'data [u8], u32)> {
307         self.iter()
308             .find_map(|section| section.pe_data_containing(data, va))
309     }
310 }
311 
312 impl pe::ImageSectionHeader {
313     /// Return the offset and size of the section in a PE file.
314     ///
315     /// The size of the range will be the minimum of the file size and virtual size.
pe_file_range(&self) -> (u32, u32)316     pub fn pe_file_range(&self) -> (u32, u32) {
317         // Pointer and size will be zero for uninitialized data; we don't need to validate this.
318         let offset = self.pointer_to_raw_data.get(LE);
319         let size = cmp::min(self.virtual_size.get(LE), self.size_of_raw_data.get(LE));
320         (offset, size)
321     }
322 
323     /// Return the virtual address and size of the section.
pe_address_range(&self) -> (u32, u32)324     pub fn pe_address_range(&self) -> (u32, u32) {
325         (self.virtual_address.get(LE), self.virtual_size.get(LE))
326     }
327 
328     /// Return the section data in a PE file.
329     ///
330     /// The length of the data will be the minimum of the file size and virtual size.
pe_data<'data, R: ReadRef<'data>>(&self, data: R) -> Result<&'data [u8]>331     pub fn pe_data<'data, R: ReadRef<'data>>(&self, data: R) -> Result<&'data [u8]> {
332         let (offset, size) = self.pe_file_range();
333         data.read_bytes_at(offset.into(), size.into())
334             .read_error("Invalid PE section offset or size")
335     }
336 
337     /// Return the data at the given virtual address if this section contains it.
338     ///
339     /// Ignores sections with invalid data.
pe_data_at<'data, R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]>340     pub fn pe_data_at<'data, R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> {
341         let section_va = self.virtual_address.get(LE);
342         let offset = va.checked_sub(section_va)?;
343         let (section_offset, section_size) = self.pe_file_range();
344         // Address must be within section (and not at its end).
345         if offset < section_size {
346             let section_data = data
347                 .read_bytes_at(section_offset.into(), section_size.into())
348                 .ok()?;
349             section_data.get(offset as usize..)
350         } else {
351             None
352         }
353     }
354 
355     /// Return the section data if it contains the given virtual address.
356     ///
357     /// Also returns the virtual address of that section.
358     ///
359     /// Ignores sections with invalid data.
pe_data_containing<'data, R: ReadRef<'data>>( &self, data: R, va: u32, ) -> Option<(&'data [u8], u32)>360     pub fn pe_data_containing<'data, R: ReadRef<'data>>(
361         &self,
362         data: R,
363         va: u32,
364     ) -> Option<(&'data [u8], u32)> {
365         let section_va = self.virtual_address.get(LE);
366         let offset = va.checked_sub(section_va)?;
367         let (section_offset, section_size) = self.pe_file_range();
368         // Address must be within section (and not at its end).
369         if offset < section_size {
370             let section_data = data
371                 .read_bytes_at(section_offset.into(), section_size.into())
372                 .ok()?;
373             Some((section_data, section_va))
374         } else {
375             None
376         }
377     }
378 }
379 
380 /// An iterator over the relocations in an `PeSection`.
381 #[derive(Debug)]
382 pub struct PeRelocationIterator<'data, 'file, R = &'data [u8]>(
383     PhantomData<(&'data (), &'file (), R)>,
384 );
385 
386 impl<'data, 'file, R> Iterator for PeRelocationIterator<'data, 'file, R> {
387     type Item = (u64, Relocation);
388 
next(&mut self) -> Option<Self::Item>389     fn next(&mut self) -> Option<Self::Item> {
390         None
391     }
392 }
393