]>
Commit | Line | Data |
---|---|---|
17df50a5 XL |
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>, | |
136023e0 | 28 | pub(super) iter: slice::Iter<'data, pe::ImageSectionHeader>, |
17df50a5 XL |
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 | ||
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>, | |
136023e0 | 61 | section: &'data pe::ImageSectionHeader, |
17df50a5 XL |
62 | } |
63 | ||
64 | impl<'data, 'file, Pe, R> PeSegment<'data, 'file, Pe, R> | |
65 | where | |
66 | Pe: ImageNtHeaders, | |
67 | R: ReadRef<'data>, | |
68 | { | |
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] | |
89 | fn address(&self) -> u64 { | |
90 | u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base) | |
91 | } | |
92 | ||
93 | #[inline] | |
94 | fn size(&self) -> u64 { | |
95 | u64::from(self.section.virtual_size.get(LE)) | |
96 | } | |
97 | ||
98 | #[inline] | |
99 | fn align(&self) -> u64 { | |
100 | self.file.section_alignment() | |
101 | } | |
102 | ||
103 | #[inline] | |
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 | ||
109 | fn data(&self) -> Result<&'data [u8]> { | |
110 | self.bytes() | |
111 | } | |
112 | ||
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] | |
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>, | |
136023e0 | 149 | pub(super) iter: iter::Enumerate<slice::Iter<'data, pe::ImageSectionHeader>>, |
17df50a5 XL |
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 | ||
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, | |
136023e0 | 185 | pub(super) section: &'data pe::ImageSectionHeader, |
17df50a5 XL |
186 | } |
187 | ||
188 | impl<'data, 'file, Pe, R> PeSection<'data, 'file, Pe, R> | |
189 | where | |
190 | Pe: ImageNtHeaders, | |
191 | R: ReadRef<'data>, | |
192 | { | |
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] | |
215 | fn index(&self) -> SectionIndex { | |
216 | self.index | |
217 | } | |
218 | ||
219 | #[inline] | |
220 | fn address(&self) -> u64 { | |
221 | u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base) | |
222 | } | |
223 | ||
224 | #[inline] | |
225 | fn size(&self) -> u64 { | |
226 | u64::from(self.section.virtual_size.get(LE)) | |
227 | } | |
228 | ||
229 | #[inline] | |
230 | fn align(&self) -> u64 { | |
231 | self.file.section_alignment() | |
232 | } | |
233 | ||
234 | #[inline] | |
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 | ||
244 | fn data(&self) -> Result<&'data [u8]> { | |
245 | self.bytes() | |
246 | } | |
247 | ||
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] | |
258 | fn compressed_file_range(&self) -> Result<CompressedFileRange> { | |
259 | Ok(CompressedFileRange::none(self.file_range())) | |
260 | } | |
261 | ||
262 | #[inline] | |
263 | fn compressed_data(&self) -> Result<CompressedData<'data>> { | |
264 | self.data().map(CompressedData::none) | |
265 | } | |
266 | ||
267 | #[inline] | |
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] | |
276 | fn segment_name(&self) -> Result<Option<&str>> { | |
277 | Ok(None) | |
278 | } | |
279 | ||
280 | #[inline] | |
281 | fn kind(&self) -> SectionKind { | |
282 | self.section.kind() | |
283 | } | |
284 | ||
285 | fn relocations(&self) -> PeRelocationIterator<'data, 'file, R> { | |
286 | PeRelocationIterator(PhantomData) | |
287 | } | |
288 | ||
289 | 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. | |
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. | |
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. | |
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. | |
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 | ||
340 | fn next(&mut self) -> Option<Self::Item> { | |
341 | None | |
342 | } | |
343 | } |