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