1use core::marker::PhantomData;
2use core::{cmp, iter, slice, str};
3
4use crate::endian::LittleEndian as LE;
5use crate::pe;
6use crate::pe::ImageSectionHeader;
7use crate::read::{
8 self, CompressedData, CompressedFileRange, ObjectSection, ObjectSegment, ReadError, ReadRef,
9 Relocation, RelocationMap, Result, SectionFlags, SectionIndex, SectionKind, SegmentFlags,
10};
11
12use super::{ImageNtHeaders, PeFile, SectionTable};
13
14pub type PeSegmentIterator32<'data, 'file, R = &'data [u8]> =
16 PeSegmentIterator<'data, 'file, pe::ImageNtHeaders32, R>;
17pub type PeSegmentIterator64<'data, 'file, R = &'data [u8]> =
19 PeSegmentIterator<'data, 'file, pe::ImageNtHeaders64, R>;
20
21#[derive(Debug)]
23pub struct PeSegmentIterator<'data, 'file, Pe, R = &'data [u8]>
24where
25 Pe: ImageNtHeaders,
26 R: ReadRef<'data>,
27{
28 pub(super) file: &'file PeFile<'data, Pe, R>,
29 pub(super) iter: slice::Iter<'data, pe::ImageSectionHeader>,
30}
31
32impl<'data, 'file, Pe, R> Iterator for PeSegmentIterator<'data, 'file, Pe, R>
33where
34 Pe: ImageNtHeaders,
35 R: ReadRef<'data>,
36{
37 type Item = PeSegment<'data, 'file, Pe, R>;
38
39 fn next(&mut self) -> Option<Self::Item> {
40 self.iter.next().map(|section| PeSegment {
41 file: self.file,
42 section,
43 })
44 }
45}
46
47pub type PeSegment32<'data, 'file, R = &'data [u8]> =
49 PeSegment<'data, 'file, pe::ImageNtHeaders32, R>;
50pub type PeSegment64<'data, 'file, R = &'data [u8]> =
52 PeSegment<'data, 'file, pe::ImageNtHeaders64, R>;
53
54#[derive(Debug)]
58pub struct PeSegment<'data, 'file, Pe, R = &'data [u8]>
59where
60 Pe: ImageNtHeaders,
61 R: ReadRef<'data>,
62{
63 file: &'file PeFile<'data, Pe, R>,
64 section: &'data pe::ImageSectionHeader,
65}
66
67impl<'data, 'file, Pe, R> PeSegment<'data, 'file, Pe, R>
68where
69 Pe: ImageNtHeaders,
70 R: ReadRef<'data>,
71{
72 pub fn pe_file(&self) -> &'file PeFile<'data, Pe, R> {
74 self.file
75 }
76
77 pub fn pe_section(&self) -> &'data pe::ImageSectionHeader {
79 self.section
80 }
81}
82
83impl<'data, 'file, Pe, R> read::private::Sealed for PeSegment<'data, 'file, Pe, R>
84where
85 Pe: ImageNtHeaders,
86 R: ReadRef<'data>,
87{
88}
89
90impl<'data, 'file, Pe, R> ObjectSegment<'data> for PeSegment<'data, 'file, Pe, R>
91where
92 Pe: ImageNtHeaders,
93 R: ReadRef<'data>,
94{
95 #[inline]
96 fn address(&self) -> u64 {
97 u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base)
98 }
99
100 #[inline]
101 fn size(&self) -> u64 {
102 u64::from(self.section.virtual_size.get(LE))
103 }
104
105 #[inline]
106 fn align(&self) -> u64 {
107 self.file.section_alignment()
108 }
109
110 #[inline]
111 fn file_range(&self) -> (u64, u64) {
112 let (offset, size) = self.section.pe_file_range();
113 (u64::from(offset), u64::from(size))
114 }
115
116 fn data(&self) -> Result<&'data [u8]> {
117 self.section.pe_data(self.file.data)
118 }
119
120 fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
121 Ok(read::util::data_range(
122 self.data()?,
123 self.address(),
124 address,
125 size,
126 ))
127 }
128
129 #[inline]
130 fn name_bytes(&self) -> Result<Option<&[u8]>> {
131 self.section
132 .name(self.file.common.symbols.strings())
133 .map(Some)
134 }
135
136 #[inline]
137 fn name(&self) -> Result<Option<&str>> {
138 let name = self.section.name(self.file.common.symbols.strings())?;
139 Ok(Some(
140 str::from_utf8(name)
141 .ok()
142 .read_error("Non UTF-8 PE section name")?,
143 ))
144 }
145
146 #[inline]
147 fn flags(&self) -> SegmentFlags {
148 let characteristics = self.section.characteristics.get(LE);
149 SegmentFlags::Coff { characteristics }
150 }
151}
152
153pub type PeSectionIterator32<'data, 'file, R = &'data [u8]> =
155 PeSectionIterator<'data, 'file, pe::ImageNtHeaders32, R>;
156pub type PeSectionIterator64<'data, 'file, R = &'data [u8]> =
158 PeSectionIterator<'data, 'file, pe::ImageNtHeaders64, R>;
159
160#[derive(Debug)]
162pub struct PeSectionIterator<'data, 'file, Pe, R = &'data [u8]>
163where
164 Pe: ImageNtHeaders,
165 R: ReadRef<'data>,
166{
167 pub(super) file: &'file PeFile<'data, Pe, R>,
168 pub(super) iter: iter::Enumerate<slice::Iter<'data, pe::ImageSectionHeader>>,
169}
170
171impl<'data, 'file, Pe, R> Iterator for PeSectionIterator<'data, 'file, Pe, R>
172where
173 Pe: ImageNtHeaders,
174 R: ReadRef<'data>,
175{
176 type Item = PeSection<'data, 'file, Pe, R>;
177
178 fn next(&mut self) -> Option<Self::Item> {
179 self.iter.next().map(|(index, section)| PeSection {
180 file: self.file,
181 index: SectionIndex(index + 1),
182 section,
183 })
184 }
185}
186
187pub type PeSection32<'data, 'file, R = &'data [u8]> =
189 PeSection<'data, 'file, pe::ImageNtHeaders32, R>;
190pub type PeSection64<'data, 'file, R = &'data [u8]> =
192 PeSection<'data, 'file, pe::ImageNtHeaders64, R>;
193
194#[derive(Debug)]
198pub struct PeSection<'data, 'file, Pe, R = &'data [u8]>
199where
200 Pe: ImageNtHeaders,
201 R: ReadRef<'data>,
202{
203 pub(super) file: &'file PeFile<'data, Pe, R>,
204 pub(super) index: SectionIndex,
205 pub(super) section: &'data pe::ImageSectionHeader,
206}
207
208impl<'data, 'file, Pe, R> PeSection<'data, 'file, Pe, R>
209where
210 Pe: ImageNtHeaders,
211 R: ReadRef<'data>,
212{
213 pub fn pe_file(&self) -> &'file PeFile<'data, Pe, R> {
215 self.file
216 }
217
218 pub fn pe_section(&self) -> &'data pe::ImageSectionHeader {
220 self.section
221 }
222}
223
224impl<'data, 'file, Pe, R> read::private::Sealed for PeSection<'data, 'file, Pe, R>
225where
226 Pe: ImageNtHeaders,
227 R: ReadRef<'data>,
228{
229}
230
231impl<'data, 'file, Pe, R> ObjectSection<'data> for PeSection<'data, 'file, Pe, R>
232where
233 Pe: ImageNtHeaders,
234 R: ReadRef<'data>,
235{
236 type RelocationIterator = PeRelocationIterator<'data, 'file, R>;
237
238 #[inline]
239 fn index(&self) -> SectionIndex {
240 self.index
241 }
242
243 #[inline]
244 fn address(&self) -> u64 {
245 u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base)
246 }
247
248 #[inline]
249 fn size(&self) -> u64 {
250 u64::from(self.section.virtual_size.get(LE))
251 }
252
253 #[inline]
254 fn align(&self) -> u64 {
255 self.file.section_alignment()
256 }
257
258 #[inline]
259 fn file_range(&self) -> Option<(u64, u64)> {
260 let (offset, size) = self.section.pe_file_range();
261 if size == 0 {
262 None
263 } else {
264 Some((u64::from(offset), u64::from(size)))
265 }
266 }
267
268 fn data(&self) -> Result<&'data [u8]> {
269 self.section.pe_data(self.file.data)
270 }
271
272 fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
273 Ok(read::util::data_range(
274 self.data()?,
275 self.address(),
276 address,
277 size,
278 ))
279 }
280
281 #[inline]
282 fn compressed_file_range(&self) -> Result<CompressedFileRange> {
283 Ok(CompressedFileRange::none(self.file_range()))
284 }
285
286 #[inline]
287 fn compressed_data(&self) -> Result<CompressedData<'data>> {
288 self.data().map(CompressedData::none)
289 }
290
291 #[inline]
292 fn name_bytes(&self) -> Result<&'data [u8]> {
293 self.section.name(self.file.common.symbols.strings())
294 }
295
296 #[inline]
297 fn name(&self) -> Result<&'data str> {
298 let name = self.name_bytes()?;
299 str::from_utf8(name)
300 .ok()
301 .read_error("Non UTF-8 PE section name")
302 }
303
304 #[inline]
305 fn segment_name_bytes(&self) -> Result<Option<&[u8]>> {
306 Ok(None)
307 }
308
309 #[inline]
310 fn segment_name(&self) -> Result<Option<&str>> {
311 Ok(None)
312 }
313
314 #[inline]
315 fn kind(&self) -> SectionKind {
316 self.section.kind()
317 }
318
319 fn relocations(&self) -> PeRelocationIterator<'data, 'file, R> {
320 PeRelocationIterator(PhantomData)
321 }
322
323 fn relocation_map(&self) -> read::Result<RelocationMap> {
324 RelocationMap::new(self.file, self)
325 }
326
327 fn flags(&self) -> SectionFlags {
328 SectionFlags::Coff {
329 characteristics: self.section.characteristics.get(LE),
330 }
331 }
332}
333
334impl<'data> SectionTable<'data> {
335 pub fn pe_file_range_at(&self, va: u32) -> Option<(u32, u32)> {
340 self.iter().find_map(|section| section.pe_file_range_at(va))
341 }
342
343 pub fn pe_data_at<R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> {
350 self.iter().find_map(|section| section.pe_data_at(data, va))
351 }
352
353 pub fn pe_data_containing<R: ReadRef<'data>>(
359 &self,
360 data: R,
361 va: u32,
362 ) -> Option<(&'data [u8], u32)> {
363 self.iter()
364 .find_map(|section| section.pe_data_containing(data, va))
365 }
366
367 pub fn section_containing(&self, va: u32) -> Option<&'data ImageSectionHeader> {
369 self.iter().find(|section| section.contains_rva(va))
370 }
371}
372
373impl pe::ImageSectionHeader {
374 pub fn pe_file_range(&self) -> (u32, u32) {
378 let offset = self.pointer_to_raw_data.get(LE);
380 let size = cmp::min(self.virtual_size.get(LE), self.size_of_raw_data.get(LE));
381 (offset, size)
382 }
383
384 pub fn pe_file_range_at(&self, va: u32) -> Option<(u32, u32)> {
389 let section_va = self.virtual_address.get(LE);
390 let offset = va.checked_sub(section_va)?;
391 let (section_offset, section_size) = self.pe_file_range();
392 if offset < section_size {
394 Some((section_offset.checked_add(offset)?, section_size - offset))
395 } else {
396 None
397 }
398 }
399
400 pub fn pe_address_range(&self) -> (u32, u32) {
402 (self.virtual_address.get(LE), self.virtual_size.get(LE))
403 }
404
405 pub fn pe_data<'data, R: ReadRef<'data>>(&self, data: R) -> Result<&'data [u8]> {
409 let (offset, size) = self.pe_file_range();
410 data.read_bytes_at(offset.into(), size.into())
411 .read_error("Invalid PE section offset or size")
412 }
413
414 pub fn pe_data_at<'data, R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> {
421 let (offset, size) = self.pe_file_range_at(va)?;
422 data.read_bytes_at(offset.into(), size.into()).ok()
423 }
424
425 pub fn contains_rva(&self, va: u32) -> bool {
427 let section_va = self.virtual_address.get(LE);
428 match va.checked_sub(section_va) {
429 None => false,
430 Some(offset) => {
431 offset < self.virtual_size.get(LE)
433 }
434 }
435 }
436
437 pub fn pe_data_containing<'data, R: ReadRef<'data>>(
443 &self,
444 data: R,
445 va: u32,
446 ) -> Option<(&'data [u8], u32)> {
447 let section_va = self.virtual_address.get(LE);
448 let offset = va.checked_sub(section_va)?;
449 let (section_offset, section_size) = self.pe_file_range();
450 if offset < section_size {
452 let section_data = data
453 .read_bytes_at(section_offset.into(), section_size.into())
454 .ok()?;
455 Some((section_data, section_va))
456 } else {
457 None
458 }
459 }
460}
461
462#[derive(Debug)]
466pub struct PeRelocationIterator<'data, 'file, R = &'data [u8]>(
467 PhantomData<(&'data (), &'file (), R)>,
468);
469
470impl<'data, 'file, R> Iterator for PeRelocationIterator<'data, 'file, R> {
471 type Item = (u64, Relocation);
472
473 fn next(&mut self) -> Option<Self::Item> {
474 None
475 }
476}