1 use core::marker::PhantomData; 2 use core::{cmp, iter, 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<'data, 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: &'data pe::ImageSectionHeader, 62 } 63 64 impl<'data, 'file, Pe, R> read::private::Sealed for PeSegment<'data, 'file, Pe, R> 65 where 66 Pe: ImageNtHeaders, 67 R: ReadRef<'data>, 68 { 69 } 70 71 impl<'data, 'file, Pe, R> ObjectSegment<'data> for PeSegment<'data, 'file, Pe, R> 72 where 73 Pe: ImageNtHeaders, 74 R: ReadRef<'data>, 75 { 76 #[inline] address(&self) -> u6477 fn address(&self) -> u64 { 78 u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base) 79 } 80 81 #[inline] size(&self) -> u6482 fn size(&self) -> u64 { 83 u64::from(self.section.virtual_size.get(LE)) 84 } 85 86 #[inline] align(&self) -> u6487 fn align(&self) -> u64 { 88 self.file.section_alignment() 89 } 90 91 #[inline] file_range(&self) -> (u64, u64)92 fn file_range(&self) -> (u64, u64) { 93 let (offset, size) = self.section.pe_file_range(); 94 (u64::from(offset), u64::from(size)) 95 } 96 data(&self) -> Result<&'data [u8]>97 fn data(&self) -> Result<&'data [u8]> { 98 self.section.pe_data(self.file.data) 99 } 100 data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>101 fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> { 102 Ok(read::util::data_range( 103 self.data()?, 104 self.address(), 105 address, 106 size, 107 )) 108 } 109 110 #[inline] name_bytes(&self) -> Result<Option<&[u8]>>111 fn name_bytes(&self) -> Result<Option<&[u8]>> { 112 self.section 113 .name(self.file.common.symbols.strings()) 114 .map(Some) 115 } 116 117 #[inline] name(&self) -> Result<Option<&str>>118 fn name(&self) -> Result<Option<&str>> { 119 let name = self.section.name(self.file.common.symbols.strings())?; 120 Ok(Some( 121 str::from_utf8(name) 122 .ok() 123 .read_error("Non UTF-8 PE section name")?, 124 )) 125 } 126 } 127 128 /// An iterator over the sections of a `PeFile32`. 129 pub type PeSectionIterator32<'data, 'file, R = &'data [u8]> = 130 PeSectionIterator<'data, 'file, pe::ImageNtHeaders32, R>; 131 /// An iterator over the sections of a `PeFile64`. 132 pub type PeSectionIterator64<'data, 'file, R = &'data [u8]> = 133 PeSectionIterator<'data, 'file, pe::ImageNtHeaders64, R>; 134 135 /// An iterator over the sections of a `PeFile`. 136 #[derive(Debug)] 137 pub struct PeSectionIterator<'data, 'file, Pe, R = &'data [u8]> 138 where 139 'data: 'file, 140 Pe: ImageNtHeaders, 141 R: ReadRef<'data>, 142 { 143 pub(super) file: &'file PeFile<'data, Pe, R>, 144 pub(super) iter: iter::Enumerate<slice::Iter<'data, pe::ImageSectionHeader>>, 145 } 146 147 impl<'data, 'file, Pe, R> Iterator for PeSectionIterator<'data, 'file, Pe, R> 148 where 149 Pe: ImageNtHeaders, 150 R: ReadRef<'data>, 151 { 152 type Item = PeSection<'data, 'file, Pe, R>; 153 next(&mut self) -> Option<Self::Item>154 fn next(&mut self) -> Option<Self::Item> { 155 self.iter.next().map(|(index, section)| PeSection { 156 file: self.file, 157 index: SectionIndex(index + 1), 158 section, 159 }) 160 } 161 } 162 163 /// A section of a `PeFile32`. 164 pub type PeSection32<'data, 'file, R = &'data [u8]> = 165 PeSection<'data, 'file, pe::ImageNtHeaders32, R>; 166 /// A section of a `PeFile64`. 167 pub type PeSection64<'data, 'file, R = &'data [u8]> = 168 PeSection<'data, 'file, pe::ImageNtHeaders64, R>; 169 170 /// A section of a `PeFile`. 171 #[derive(Debug)] 172 pub struct PeSection<'data, 'file, Pe, R = &'data [u8]> 173 where 174 'data: 'file, 175 Pe: ImageNtHeaders, 176 R: ReadRef<'data>, 177 { 178 pub(super) file: &'file PeFile<'data, Pe, R>, 179 pub(super) index: SectionIndex, 180 pub(super) section: &'data pe::ImageSectionHeader, 181 } 182 183 impl<'data, 'file, Pe, R> read::private::Sealed for PeSection<'data, 'file, Pe, R> 184 where 185 Pe: ImageNtHeaders, 186 R: ReadRef<'data>, 187 { 188 } 189 190 impl<'data, 'file, Pe, R> ObjectSection<'data> for PeSection<'data, 'file, Pe, R> 191 where 192 Pe: ImageNtHeaders, 193 R: ReadRef<'data>, 194 { 195 type RelocationIterator = PeRelocationIterator<'data, 'file, R>; 196 197 #[inline] index(&self) -> SectionIndex198 fn index(&self) -> SectionIndex { 199 self.index 200 } 201 202 #[inline] address(&self) -> u64203 fn address(&self) -> u64 { 204 u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base) 205 } 206 207 #[inline] size(&self) -> u64208 fn size(&self) -> u64 { 209 u64::from(self.section.virtual_size.get(LE)) 210 } 211 212 #[inline] align(&self) -> u64213 fn align(&self) -> u64 { 214 self.file.section_alignment() 215 } 216 217 #[inline] file_range(&self) -> Option<(u64, u64)>218 fn file_range(&self) -> Option<(u64, u64)> { 219 let (offset, size) = self.section.pe_file_range(); 220 if size == 0 { 221 None 222 } else { 223 Some((u64::from(offset), u64::from(size))) 224 } 225 } 226 data(&self) -> Result<&'data [u8]>227 fn data(&self) -> Result<&'data [u8]> { 228 self.section.pe_data(self.file.data) 229 } 230 data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>231 fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> { 232 Ok(read::util::data_range( 233 self.data()?, 234 self.address(), 235 address, 236 size, 237 )) 238 } 239 240 #[inline] compressed_file_range(&self) -> Result<CompressedFileRange>241 fn compressed_file_range(&self) -> Result<CompressedFileRange> { 242 Ok(CompressedFileRange::none(self.file_range())) 243 } 244 245 #[inline] compressed_data(&self) -> Result<CompressedData<'data>>246 fn compressed_data(&self) -> Result<CompressedData<'data>> { 247 self.data().map(CompressedData::none) 248 } 249 250 #[inline] name_bytes(&self) -> Result<&[u8]>251 fn name_bytes(&self) -> Result<&[u8]> { 252 self.section.name(self.file.common.symbols.strings()) 253 } 254 255 #[inline] name(&self) -> Result<&str>256 fn name(&self) -> Result<&str> { 257 let name = self.name_bytes()?; 258 str::from_utf8(name) 259 .ok() 260 .read_error("Non UTF-8 PE section name") 261 } 262 263 #[inline] segment_name_bytes(&self) -> Result<Option<&[u8]>>264 fn segment_name_bytes(&self) -> Result<Option<&[u8]>> { 265 Ok(None) 266 } 267 268 #[inline] segment_name(&self) -> Result<Option<&str>>269 fn segment_name(&self) -> Result<Option<&str>> { 270 Ok(None) 271 } 272 273 #[inline] kind(&self) -> SectionKind274 fn kind(&self) -> SectionKind { 275 self.section.kind() 276 } 277 relocations(&self) -> PeRelocationIterator<'data, 'file, R>278 fn relocations(&self) -> PeRelocationIterator<'data, 'file, R> { 279 PeRelocationIterator(PhantomData) 280 } 281 flags(&self) -> SectionFlags282 fn flags(&self) -> SectionFlags { 283 SectionFlags::Coff { 284 characteristics: self.section.characteristics.get(LE), 285 } 286 } 287 } 288 289 impl<'data> SectionTable<'data> { 290 /// Return the data at the given virtual address in a PE file. 291 /// 292 /// Ignores sections with invalid data. pe_data_at<R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]>293 pub fn pe_data_at<R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> { 294 self.iter().find_map(|section| section.pe_data_at(data, va)) 295 } 296 297 /// Return the data of the section that contains the given virtual address in a PE file. 298 /// 299 /// Also returns the virtual address of that section. 300 /// 301 /// Ignores sections with invalid data. pe_data_containing<R: ReadRef<'data>>( &self, data: R, va: u32, ) -> Option<(&'data [u8], u32)>302 pub fn pe_data_containing<R: ReadRef<'data>>( 303 &self, 304 data: R, 305 va: u32, 306 ) -> Option<(&'data [u8], u32)> { 307 self.iter() 308 .find_map(|section| section.pe_data_containing(data, va)) 309 } 310 } 311 312 impl pe::ImageSectionHeader { 313 /// Return the offset and size of the section in a PE file. 314 /// 315 /// The size of the range will be the minimum of the file size and virtual size. pe_file_range(&self) -> (u32, u32)316 pub fn pe_file_range(&self) -> (u32, u32) { 317 // Pointer and size will be zero for uninitialized data; we don't need to validate this. 318 let offset = self.pointer_to_raw_data.get(LE); 319 let size = cmp::min(self.virtual_size.get(LE), self.size_of_raw_data.get(LE)); 320 (offset, size) 321 } 322 323 /// Return the virtual address and size of the section. pe_address_range(&self) -> (u32, u32)324 pub fn pe_address_range(&self) -> (u32, u32) { 325 (self.virtual_address.get(LE), self.virtual_size.get(LE)) 326 } 327 328 /// Return the section data in a PE file. 329 /// 330 /// The length of the data will be the minimum of the file size and virtual size. pe_data<'data, R: ReadRef<'data>>(&self, data: R) -> Result<&'data [u8]>331 pub fn pe_data<'data, R: ReadRef<'data>>(&self, data: R) -> Result<&'data [u8]> { 332 let (offset, size) = self.pe_file_range(); 333 data.read_bytes_at(offset.into(), size.into()) 334 .read_error("Invalid PE section offset or size") 335 } 336 337 /// Return the data at the given virtual address if this section contains it. 338 /// 339 /// Ignores sections with invalid data. pe_data_at<'data, R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]>340 pub fn pe_data_at<'data, R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> { 341 let section_va = self.virtual_address.get(LE); 342 let offset = va.checked_sub(section_va)?; 343 let (section_offset, section_size) = self.pe_file_range(); 344 // Address must be within section (and not at its end). 345 if offset < section_size { 346 let section_data = data 347 .read_bytes_at(section_offset.into(), section_size.into()) 348 .ok()?; 349 section_data.get(offset as usize..) 350 } else { 351 None 352 } 353 } 354 355 /// Return the section data if it contains the given virtual address. 356 /// 357 /// Also returns the virtual address of that section. 358 /// 359 /// Ignores sections with invalid data. pe_data_containing<'data, R: ReadRef<'data>>( &self, data: R, va: u32, ) -> Option<(&'data [u8], u32)>360 pub fn pe_data_containing<'data, R: ReadRef<'data>>( 361 &self, 362 data: R, 363 va: u32, 364 ) -> Option<(&'data [u8], u32)> { 365 let section_va = self.virtual_address.get(LE); 366 let offset = va.checked_sub(section_va)?; 367 let (section_offset, section_size) = self.pe_file_range(); 368 // Address must be within section (and not at its end). 369 if offset < section_size { 370 let section_data = data 371 .read_bytes_at(section_offset.into(), section_size.into()) 372 .ok()?; 373 Some((section_data, section_va)) 374 } else { 375 None 376 } 377 } 378 } 379 380 /// An iterator over the relocations in an `PeSection`. 381 #[derive(Debug)] 382 pub struct PeRelocationIterator<'data, 'file, R = &'data [u8]>( 383 PhantomData<(&'data (), &'file (), R)>, 384 ); 385 386 impl<'data, 'file, R> Iterator for PeRelocationIterator<'data, 'file, R> { 387 type Item = (u64, Relocation); 388 next(&mut self) -> Option<Self::Item>389 fn next(&mut self) -> Option<Self::Item> { 390 None 391 } 392 } 393