object/read/pe/
data_directory.rs1use core::slice;
2
3use crate::endian::LittleEndian as LE;
4use crate::pe;
5use crate::read::{Error, ReadError, ReadRef, Result};
6
7use super::{
8 DelayLoadImportTable, ExportTable, ImportTable, RelocationBlockIterator, ResourceDirectory,
9 SectionTable,
10};
11
12#[derive(Debug, Clone, Copy)]
16pub struct DataDirectories<'data> {
17 entries: &'data [pe::ImageDataDirectory],
18}
19
20impl<'data> DataDirectories<'data> {
21 pub fn parse(data: &'data [u8], number: u32) -> Result<Self> {
28 let entries = data
29 .read_slice_at(0, number as usize)
30 .read_error("Invalid PE number of RVA and sizes")?;
31 Ok(DataDirectories { entries })
32 }
33
34 #[allow(clippy::len_without_is_empty)]
36 pub fn len(&self) -> usize {
37 self.entries.len()
38 }
39
40 pub fn iter(&self) -> slice::Iter<'data, pe::ImageDataDirectory> {
42 self.entries.iter()
43 }
44
45 pub fn enumerate(&self) -> core::iter::Enumerate<slice::Iter<'data, pe::ImageDataDirectory>> {
47 self.entries.iter().enumerate()
48 }
49
50 pub fn get(&self, index: usize) -> Option<&'data pe::ImageDataDirectory> {
57 self.entries
58 .get(index)
59 .filter(|d| d.virtual_address.get(LE) != 0)
60 }
61
62 pub fn export_directory<R: ReadRef<'data>>(
66 &self,
67 data: R,
68 sections: &SectionTable<'data>,
69 ) -> Result<Option<&'data pe::ImageExportDirectory>> {
70 let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_EXPORT) {
71 Some(data_dir) => data_dir,
72 None => return Ok(None),
73 };
74 let export_data = data_dir.data(data, sections)?;
75 ExportTable::parse_directory(export_data).map(Some)
76 }
77
78 pub fn export_table<R: ReadRef<'data>>(
82 &self,
83 data: R,
84 sections: &SectionTable<'data>,
85 ) -> Result<Option<ExportTable<'data>>> {
86 let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_EXPORT) {
87 Some(data_dir) => data_dir,
88 None => return Ok(None),
89 };
90 let export_va = data_dir.virtual_address.get(LE);
91 let export_data = data_dir.data(data, sections)?;
92 ExportTable::parse(export_data, export_va).map(Some)
93 }
94
95 pub fn import_table<R: ReadRef<'data>>(
99 &self,
100 data: R,
101 sections: &SectionTable<'data>,
102 ) -> Result<Option<ImportTable<'data>>> {
103 let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_IMPORT) {
104 Some(data_dir) => data_dir,
105 None => return Ok(None),
106 };
107 let import_va = data_dir.virtual_address.get(LE);
108 ImportTable::from_sections(data, sections, import_va).map(Some)
109 }
110
111 pub fn delay_load_import_table<R: ReadRef<'data>>(
115 &self,
116 data: R,
117 sections: &SectionTable<'data>,
118 ) -> Result<Option<DelayLoadImportTable<'data>>> {
119 let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT) {
120 Some(data_dir) => data_dir,
121 None => return Ok(None),
122 };
123 let import_va = data_dir.virtual_address.get(LE);
124 let (section_data, section_va) = sections
125 .pe_data_containing(data, import_va)
126 .read_error("Invalid import data dir virtual address")?;
127 Ok(Some(DelayLoadImportTable::new(
128 section_data,
129 section_va,
130 import_va,
131 )))
132 }
133
134 pub fn relocation_blocks<R: ReadRef<'data>>(
138 &self,
139 data: R,
140 sections: &SectionTable<'data>,
141 ) -> Result<Option<RelocationBlockIterator<'data>>> {
142 let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_BASERELOC) {
143 Some(data_dir) => data_dir,
144 None => return Ok(None),
145 };
146 let reloc_data = data_dir.data(data, sections)?;
147 Ok(Some(RelocationBlockIterator::new(reloc_data)))
148 }
149
150 pub fn resource_directory<R: ReadRef<'data>>(
154 &self,
155 data: R,
156 sections: &SectionTable<'data>,
157 ) -> Result<Option<ResourceDirectory<'data>>> {
158 let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_RESOURCE) {
159 Some(data_dir) => data_dir,
160 None => return Ok(None),
161 };
162 let rsrc_data = data_dir.data(data, sections)?;
163 Ok(Some(ResourceDirectory::new(rsrc_data)))
164 }
165}
166
167impl pe::ImageDataDirectory {
168 pub fn address_range(&self) -> (u32, u32) {
170 (self.virtual_address.get(LE), self.size.get(LE))
171 }
172
173 pub fn file_range(&self, sections: &SectionTable<'_>) -> Result<(u32, u32)> {
182 let (offset, section_size) = sections
183 .pe_file_range_at(self.virtual_address.get(LE))
184 .read_error("Invalid data dir virtual address")?;
185 let size = self.size.get(LE);
186 if size > section_size {
187 return Err(Error("Invalid data dir size"));
188 }
189 Ok((offset, size))
190 }
191
192 pub fn data<'data, R: ReadRef<'data>>(
201 &self,
202 data: R,
203 sections: &SectionTable<'data>,
204 ) -> Result<&'data [u8]> {
205 sections
206 .pe_data_at(data, self.virtual_address.get(LE))
207 .read_error("Invalid data dir virtual address")?
208 .get(..self.size.get(LE) as usize)
209 .read_error("Invalid data dir size")
210 }
211}