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