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::pod::Bytes;
7 use crate::read::{
8     self, CompressedData, ObjectSection, ObjectSegment, ReadError, Relocation, Result,
9     SectionFlags, SectionIndex, SectionKind,
10 };
11 
12 use super::{ImageNtHeaders, PeFile};
13 
14 /// An iterator over the loadable sections of a `PeFile32`.
15 pub type PeSegmentIterator32<'data, 'file> = PeSegmentIterator<'data, 'file, pe::ImageNtHeaders32>;
16 /// An iterator over the loadable sections of a `PeFile64`.
17 pub type PeSegmentIterator64<'data, 'file> = PeSegmentIterator<'data, 'file, pe::ImageNtHeaders64>;
18 
19 /// An iterator over the loadable sections of a `PeFile`.
20 #[derive(Debug)]
21 pub struct PeSegmentIterator<'data, 'file, Pe>
22 where
23     'data: 'file,
24     Pe: ImageNtHeaders,
25 {
26     pub(super) file: &'file PeFile<'data, Pe>,
27     pub(super) iter: slice::Iter<'file, pe::ImageSectionHeader>,
28 }
29 
30 impl<'data, 'file, Pe: ImageNtHeaders> Iterator for PeSegmentIterator<'data, 'file, Pe> {
31     type Item = PeSegment<'data, 'file, Pe>;
32 
next(&mut self) -> Option<Self::Item>33     fn next(&mut self) -> Option<Self::Item> {
34         self.iter.next().map(|section| PeSegment {
35             file: self.file,
36             section,
37         })
38     }
39 }
40 
41 /// A loadable section of a `PeFile32`.
42 pub type PeSegment32<'data, 'file> = PeSegment<'data, 'file, pe::ImageNtHeaders32>;
43 /// A loadable section of a `PeFile64`.
44 pub type PeSegment64<'data, 'file> = PeSegment<'data, 'file, pe::ImageNtHeaders64>;
45 
46 /// A loadable section of a `PeFile`.
47 #[derive(Debug)]
48 pub struct PeSegment<'data, 'file, Pe>
49 where
50     'data: 'file,
51     Pe: ImageNtHeaders,
52 {
53     file: &'file PeFile<'data, Pe>,
54     section: &'file pe::ImageSectionHeader,
55 }
56 
57 impl<'data, 'file, Pe: ImageNtHeaders> PeSegment<'data, 'file, Pe> {
bytes(&self) -> Result<Bytes<'data>>58     fn bytes(&self) -> Result<Bytes<'data>> {
59         self.section
60             .pe_data(self.file.data)
61             .read_error("Invalid PE section offset or size")
62     }
63 }
64 
65 impl<'data, 'file, Pe: ImageNtHeaders> read::private::Sealed for PeSegment<'data, 'file, Pe> {}
66 
67 impl<'data, 'file, Pe: ImageNtHeaders> ObjectSegment<'data> for PeSegment<'data, 'file, Pe> {
68     #[inline]
address(&self) -> u6469     fn address(&self) -> u64 {
70         u64::from(self.section.virtual_address.get(LE))
71     }
72 
73     #[inline]
size(&self) -> u6474     fn size(&self) -> u64 {
75         u64::from(self.section.virtual_size.get(LE))
76     }
77 
78     #[inline]
align(&self) -> u6479     fn align(&self) -> u64 {
80         self.file.section_alignment()
81     }
82 
83     #[inline]
file_range(&self) -> (u64, u64)84     fn file_range(&self) -> (u64, u64) {
85         let (offset, size) = self.section.pe_file_range();
86         (u64::from(offset), u64::from(size))
87     }
88 
data(&self) -> Result<&'data [u8]>89     fn data(&self) -> Result<&'data [u8]> {
90         Ok(self.bytes()?.0)
91     }
92 
data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>93     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
94         Ok(read::data_range(
95             self.bytes()?,
96             self.address(),
97             address,
98             size,
99         ))
100     }
101 
102     #[inline]
name(&self) -> Result<Option<&str>>103     fn name(&self) -> Result<Option<&str>> {
104         let name = self.section.name(self.file.symbols.strings())?;
105         Ok(Some(
106             str::from_utf8(name)
107                 .ok()
108                 .read_error("Non UTF-8 PE section name")?,
109         ))
110     }
111 }
112 
113 /// An iterator over the sections of a `PeFile32`.
114 pub type PeSectionIterator32<'data, 'file> = PeSectionIterator<'data, 'file, pe::ImageNtHeaders32>;
115 /// An iterator over the sections of a `PeFile64`.
116 pub type PeSectionIterator64<'data, 'file> = PeSectionIterator<'data, 'file, pe::ImageNtHeaders64>;
117 
118 /// An iterator over the sections of a `PeFile`.
119 #[derive(Debug)]
120 pub struct PeSectionIterator<'data, 'file, Pe>
121 where
122     'data: 'file,
123     Pe: ImageNtHeaders,
124 {
125     pub(super) file: &'file PeFile<'data, Pe>,
126     pub(super) iter: iter::Enumerate<slice::Iter<'file, pe::ImageSectionHeader>>,
127 }
128 
129 impl<'data, 'file, Pe: ImageNtHeaders> Iterator for PeSectionIterator<'data, 'file, Pe> {
130     type Item = PeSection<'data, 'file, Pe>;
131 
next(&mut self) -> Option<Self::Item>132     fn next(&mut self) -> Option<Self::Item> {
133         self.iter.next().map(|(index, section)| PeSection {
134             file: self.file,
135             index: SectionIndex(index + 1),
136             section,
137         })
138     }
139 }
140 
141 /// A section of a `PeFile32`.
142 pub type PeSection32<'data, 'file> = PeSection<'data, 'file, pe::ImageNtHeaders32>;
143 /// A section of a `PeFile64`.
144 pub type PeSection64<'data, 'file> = PeSection<'data, 'file, pe::ImageNtHeaders64>;
145 
146 /// A section of a `PeFile`.
147 #[derive(Debug)]
148 pub struct PeSection<'data, 'file, Pe>
149 where
150     'data: 'file,
151     Pe: ImageNtHeaders,
152 {
153     pub(super) file: &'file PeFile<'data, Pe>,
154     pub(super) index: SectionIndex,
155     pub(super) section: &'file pe::ImageSectionHeader,
156 }
157 
158 impl<'data, 'file, Pe: ImageNtHeaders> PeSection<'data, 'file, Pe> {
bytes(&self) -> Result<Bytes<'data>>159     fn bytes(&self) -> Result<Bytes<'data>> {
160         self.section
161             .pe_data(self.file.data)
162             .read_error("Invalid PE section offset or size")
163     }
164 }
165 
166 impl<'data, 'file, Pe: ImageNtHeaders> read::private::Sealed for PeSection<'data, 'file, Pe> {}
167 
168 impl<'data, 'file, Pe: ImageNtHeaders> ObjectSection<'data> for PeSection<'data, 'file, Pe> {
169     type RelocationIterator = PeRelocationIterator<'data, 'file>;
170 
171     #[inline]
index(&self) -> SectionIndex172     fn index(&self) -> SectionIndex {
173         self.index
174     }
175 
176     #[inline]
address(&self) -> u64177     fn address(&self) -> u64 {
178         u64::from(self.section.virtual_address.get(LE))
179     }
180 
181     #[inline]
size(&self) -> u64182     fn size(&self) -> u64 {
183         u64::from(self.section.virtual_size.get(LE))
184     }
185 
186     #[inline]
align(&self) -> u64187     fn align(&self) -> u64 {
188         self.file.section_alignment()
189     }
190 
191     #[inline]
file_range(&self) -> Option<(u64, u64)>192     fn file_range(&self) -> Option<(u64, u64)> {
193         let (offset, size) = self.section.pe_file_range();
194         if size == 0 {
195             None
196         } else {
197             Some((u64::from(offset), u64::from(size)))
198         }
199     }
200 
data(&self) -> Result<&'data [u8]>201     fn data(&self) -> Result<&'data [u8]> {
202         Ok(self.bytes()?.0)
203     }
204 
data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>205     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
206         Ok(read::data_range(
207             self.bytes()?,
208             self.address(),
209             address,
210             size,
211         ))
212     }
213 
214     #[inline]
compressed_data(&self) -> Result<CompressedData<'data>>215     fn compressed_data(&self) -> Result<CompressedData<'data>> {
216         self.data().map(CompressedData::none)
217     }
218 
219     #[inline]
name(&self) -> Result<&str>220     fn name(&self) -> Result<&str> {
221         let name = self.section.name(self.file.symbols.strings())?;
222         str::from_utf8(name)
223             .ok()
224             .read_error("Non UTF-8 PE section name")
225     }
226 
227     #[inline]
segment_name(&self) -> Result<Option<&str>>228     fn segment_name(&self) -> Result<Option<&str>> {
229         Ok(None)
230     }
231 
232     #[inline]
kind(&self) -> SectionKind233     fn kind(&self) -> SectionKind {
234         self.section.kind()
235     }
236 
relocations(&self) -> PeRelocationIterator<'data, 'file>237     fn relocations(&self) -> PeRelocationIterator<'data, 'file> {
238         PeRelocationIterator::default()
239     }
240 
flags(&self) -> SectionFlags241     fn flags(&self) -> SectionFlags {
242         SectionFlags::Coff {
243             characteristics: self.section.characteristics.get(LE),
244         }
245     }
246 }
247 
248 impl pe::ImageSectionHeader {
pe_file_range(&self) -> (u32, u32)249     fn pe_file_range(&self) -> (u32, u32) {
250         // Pointer and size will be zero for uninitialized data; we don't need to validate this.
251         let offset = self.pointer_to_raw_data.get(LE);
252         let size = cmp::min(self.virtual_size.get(LE), self.size_of_raw_data.get(LE));
253         (offset, size)
254     }
255 
256     /// Return the data for a PE section.
pe_data<'data>(&self, data: Bytes<'data>) -> result::Result<Bytes<'data>, ()>257     pub fn pe_data<'data>(&self, data: Bytes<'data>) -> result::Result<Bytes<'data>, ()> {
258         let (offset, size) = self.pe_file_range();
259         data.read_bytes_at(offset as usize, size as usize)
260     }
261 }
262 
263 /// An iterator over the relocations in an `PeSection`.
264 #[derive(Debug, Default)]
265 pub struct PeRelocationIterator<'data, 'file>(PhantomData<(&'data (), &'file ())>);
266 
267 impl<'data, 'file> Iterator for PeRelocationIterator<'data, 'file> {
268     type Item = (u64, Relocation);
269 
next(&mut self) -> Option<Self::Item>270     fn next(&mut self) -> Option<Self::Item> {
271         None
272     }
273 }
274