]>
Commit | Line | Data |
---|---|---|
f035d41b 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::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 | ||
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> { | |
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] | |
69 | fn address(&self) -> u64 { | |
70 | u64::from(self.section.virtual_address.get(LE)) | |
71 | } | |
72 | ||
73 | #[inline] | |
74 | fn size(&self) -> u64 { | |
75 | u64::from(self.section.virtual_size.get(LE)) | |
76 | } | |
77 | ||
78 | #[inline] | |
79 | fn align(&self) -> u64 { | |
80 | self.file.section_alignment() | |
81 | } | |
82 | ||
83 | #[inline] | |
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 | ||
89 | fn data(&self) -> Result<&'data [u8]> { | |
90 | Ok(self.bytes()?.0) | |
91 | } | |
92 | ||
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] | |
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 | ||
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> { | |
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] | |
172 | fn index(&self) -> SectionIndex { | |
173 | self.index | |
174 | } | |
175 | ||
176 | #[inline] | |
177 | fn address(&self) -> u64 { | |
178 | u64::from(self.section.virtual_address.get(LE)) | |
179 | } | |
180 | ||
181 | #[inline] | |
182 | fn size(&self) -> u64 { | |
183 | u64::from(self.section.virtual_size.get(LE)) | |
184 | } | |
185 | ||
186 | #[inline] | |
187 | fn align(&self) -> u64 { | |
188 | self.file.section_alignment() | |
189 | } | |
190 | ||
191 | #[inline] | |
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 | ||
201 | fn data(&self) -> Result<&'data [u8]> { | |
202 | Ok(self.bytes()?.0) | |
203 | } | |
204 | ||
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] | |
215 | fn compressed_data(&self) -> Result<CompressedData<'data>> { | |
216 | self.data().map(CompressedData::none) | |
217 | } | |
218 | ||
219 | #[inline] | |
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] | |
228 | fn segment_name(&self) -> Result<Option<&str>> { | |
229 | Ok(None) | |
230 | } | |
231 | ||
232 | #[inline] | |
233 | fn kind(&self) -> SectionKind { | |
234 | self.section.kind() | |
235 | } | |
236 | ||
237 | fn relocations(&self) -> PeRelocationIterator<'data, 'file> { | |
238 | PeRelocationIterator::default() | |
239 | } | |
240 | ||
241 | fn flags(&self) -> SectionFlags { | |
242 | SectionFlags::Coff { | |
243 | characteristics: self.section.characteristics.get(LE), | |
244 | } | |
245 | } | |
246 | } | |
247 | ||
248 | impl pe::ImageSectionHeader { | |
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. | |
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 | ||
270 | fn next(&mut self) -> Option<Self::Item> { | |
271 | None | |
272 | } | |
273 | } |