]> git.proxmox.com Git - rustc.git/blob - vendor/object/src/read/pe/import.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / vendor / object / src / read / pe / import.rs
1 use core::fmt::Debug;
2 use core::mem;
3
4 use crate::read::{Bytes, ReadError, Result};
5 use crate::{pe, LittleEndian as LE, Pod, U16Bytes};
6
7 use super::ImageNtHeaders;
8
9 /// Information for parsing a PE import table.
10 #[derive(Debug, Clone)]
11 pub struct ImportTable<'data> {
12 section_data: Bytes<'data>,
13 section_address: u32,
14 import_address: u32,
15 }
16
17 impl<'data> ImportTable<'data> {
18 /// Create a new import table parser.
19 ///
20 /// The import descriptors start at `import_address`.
21 /// The size declared in the `IMAGE_DIRECTORY_ENTRY_IMPORT` data directory is
22 /// ignored by the Windows loader, and so descriptors will be parsed until a null entry.
23 ///
24 /// `section_data` should be from the section containing `import_address`, and
25 /// `section_address` should be the address of that section. Pointers within the
26 /// descriptors and thunks may point to anywhere within the section data.
27 pub fn new(section_data: &'data [u8], section_address: u32, import_address: u32) -> Self {
28 ImportTable {
29 section_data: Bytes(section_data),
30 section_address,
31 import_address,
32 }
33 }
34
35 /// Return an iterator for the import descriptors.
36 pub fn descriptors(&self) -> Result<ImportDescriptorIterator<'data>> {
37 let offset = self.import_address.wrapping_sub(self.section_address);
38 let mut data = self.section_data;
39 data.skip(offset as usize)
40 .read_error("Invalid PE import descriptor address")?;
41 Ok(ImportDescriptorIterator { data })
42 }
43
44 /// Return a library name given its address.
45 ///
46 /// This address may be from [`pe::ImageImportDescriptor::name`].
47 pub fn name(&self, address: u32) -> Result<&'data [u8]> {
48 self.section_data
49 .read_string_at(address.wrapping_sub(self.section_address) as usize)
50 .read_error("Invalid PE import descriptor name")
51 }
52
53 /// Return a list of thunks given its address.
54 ///
55 /// This address may be from [`pe::ImageImportDescriptor::original_first_thunk`]
56 /// or [`pe::ImageImportDescriptor::first_thunk`].
57 pub fn thunks(&self, address: u32) -> Result<ImportThunkList<'data>> {
58 let offset = address.wrapping_sub(self.section_address);
59 let mut data = self.section_data;
60 data.skip(offset as usize)
61 .read_error("Invalid PE import thunk table address")?;
62 Ok(ImportThunkList { data })
63 }
64
65 /// Parse a thunk.
66 pub fn import<Pe: ImageNtHeaders>(&self, thunk: Pe::ImageThunkData) -> Result<Import<'data>> {
67 if thunk.is_ordinal() {
68 Ok(Import::Ordinal(thunk.ordinal()))
69 } else {
70 let (hint, name) = self.hint_name(thunk.address())?;
71 Ok(Import::Name(hint, name))
72 }
73 }
74
75 /// Return the hint and name at the given address.
76 ///
77 /// This address may be from [`pe::ImageThunkData32`] or [`pe::ImageThunkData64`].
78 ///
79 /// The hint is an index into the export name pointer table in the target library.
80 pub fn hint_name(&self, address: u32) -> Result<(u16, &'data [u8])> {
81 let offset = address.wrapping_sub(self.section_address);
82 let mut data = self.section_data;
83 data.skip(offset as usize)
84 .read_error("Invalid PE import thunk address")?;
85 let hint = data
86 .read::<U16Bytes<LE>>()
87 .read_error("Missing PE import thunk hint")?
88 .get(LE);
89 let name = data
90 .read_string()
91 .read_error("Missing PE import thunk name")?;
92 Ok((hint, name))
93 }
94 }
95
96 /// A fallible iterator for the descriptors in the import data directory.
97 #[derive(Debug, Clone)]
98 pub struct ImportDescriptorIterator<'data> {
99 data: Bytes<'data>,
100 }
101
102 impl<'data> ImportDescriptorIterator<'data> {
103 /// Return the next descriptor.
104 ///
105 /// Returns `Ok(None)` when a null descriptor is found.
106 pub fn next(&mut self) -> Result<Option<&'data pe::ImageImportDescriptor>> {
107 let import_desc = self
108 .data
109 .read::<pe::ImageImportDescriptor>()
110 .read_error("Missing PE null import descriptor")?;
111 if import_desc.is_null() {
112 Ok(None)
113 } else {
114 Ok(Some(import_desc))
115 }
116 }
117 }
118
119 /// A list of import thunks.
120 ///
121 /// These may be in the import lookup table, or the import address table.
122 #[derive(Debug, Clone)]
123 pub struct ImportThunkList<'data> {
124 data: Bytes<'data>,
125 }
126
127 impl<'data> ImportThunkList<'data> {
128 /// Get the thunk at the given index.
129 pub fn get<Pe: ImageNtHeaders>(&self, index: usize) -> Result<Pe::ImageThunkData> {
130 let thunk = self
131 .data
132 .read_at(index * mem::size_of::<Pe::ImageThunkData>())
133 .read_error("Invalid PE import thunk index")?;
134 Ok(*thunk)
135 }
136
137 /// Return the first thunk in the list, and update `self` to point after it.
138 ///
139 /// Returns `Ok(None)` when a null thunk is found.
140 pub fn next<Pe: ImageNtHeaders>(&mut self) -> Result<Option<Pe::ImageThunkData>> {
141 let thunk = self
142 .data
143 .read::<Pe::ImageThunkData>()
144 .read_error("Missing PE null import thunk")?;
145 if thunk.address() == 0 {
146 Ok(None)
147 } else {
148 Ok(Some(*thunk))
149 }
150 }
151 }
152
153 /// A parsed import thunk.
154 #[derive(Debug, Clone, Copy)]
155 pub enum Import<'data> {
156 /// Import by ordinal.
157 Ordinal(u16),
158 /// Import by name.
159 ///
160 /// Includes a hint for the index into the export name pointer table in the target library.
161 Name(u16, &'data [u8]),
162 }
163
164 /// A trait for generic access to [`pe::ImageThunkData32`] and [`pe::ImageThunkData64`].
165 #[allow(missing_docs)]
166 pub trait ImageThunkData: Debug + Pod {
167 /// Return the raw thunk value.
168 fn raw(self) -> u64;
169
170 /// Returns true if the ordinal flag is set.
171 fn is_ordinal(self) -> bool;
172
173 /// Return the ordinal portion of the thunk.
174 ///
175 /// Does not check the ordinal flag.
176 fn ordinal(self) -> u16;
177
178 /// Return the RVA portion of the thunk.
179 ///
180 /// Does not check the ordinal flag.
181 fn address(self) -> u32;
182 }
183
184 impl ImageThunkData for pe::ImageThunkData64 {
185 fn raw(self) -> u64 {
186 self.0.get(LE)
187 }
188
189 fn is_ordinal(self) -> bool {
190 self.0.get(LE) & pe::IMAGE_ORDINAL_FLAG64 != 0
191 }
192
193 fn ordinal(self) -> u16 {
194 self.0.get(LE) as u16
195 }
196
197 fn address(self) -> u32 {
198 self.0.get(LE) as u32 & 0x7fff_ffff
199 }
200 }
201
202 impl ImageThunkData for pe::ImageThunkData32 {
203 fn raw(self) -> u64 {
204 self.0.get(LE).into()
205 }
206
207 fn is_ordinal(self) -> bool {
208 self.0.get(LE) & pe::IMAGE_ORDINAL_FLAG32 != 0
209 }
210
211 fn ordinal(self) -> u16 {
212 self.0.get(LE) as u16
213 }
214
215 fn address(self) -> u32 {
216 self.0.get(LE) & 0x7fff_ffff
217 }
218 }
219
220 /// Information for parsing a PE delay-load import table.
221 #[derive(Debug, Clone)]
222 pub struct DelayLoadImportTable<'data> {
223 section_data: Bytes<'data>,
224 section_address: u32,
225 import_address: u32,
226 }
227
228 impl<'data> DelayLoadImportTable<'data> {
229 /// Create a new delay load import table parser.
230 ///
231 /// The import descriptors start at `import_address`.
232 /// This table works in the same way the import table does: descriptors will be
233 /// parsed until a null entry.
234 ///
235 /// `section_data` should be from the section containing `import_address`, and
236 /// `section_address` should be the address of that section. Pointers within the
237 /// descriptors and thunks may point to anywhere within the section data.
238 pub fn new(section_data: &'data [u8], section_address: u32, import_address: u32) -> Self {
239 DelayLoadImportTable {
240 section_data: Bytes(section_data),
241 section_address,
242 import_address,
243 }
244 }
245
246 /// Return an iterator for the import descriptors.
247 pub fn descriptors(&self) -> Result<DelayLoadDescriptorIterator<'data>> {
248 let offset = self.import_address.wrapping_sub(self.section_address);
249 let mut data = self.section_data;
250 data.skip(offset as usize)
251 .read_error("Invalid PE delay-load import descriptor address")?;
252 Ok(DelayLoadDescriptorIterator { data })
253 }
254
255 /// Return a library name given its address.
256 ///
257 /// This address may be from [`pe::ImageDelayloadDescriptor::dll_name_rva`].
258 pub fn name(&self, address: u32) -> Result<&'data [u8]> {
259 self.section_data
260 .read_string_at(address.wrapping_sub(self.section_address) as usize)
261 .read_error("Invalid PE import descriptor name")
262 }
263
264 /// Return a list of thunks given its address.
265 ///
266 /// This address may be from the INT, i.e. from
267 /// [`pe::ImageDelayloadDescriptor::import_name_table_rva`].
268 ///
269 /// Please note that others RVA values from [`pe::ImageDelayloadDescriptor`] are used
270 /// by the delay loader at runtime to store values, and thus do not point inside the same
271 /// section as the INT. Calling this function on those addresses will fail.
272 pub fn thunks(&self, address: u32) -> Result<ImportThunkList<'data>> {
273 let offset = address.wrapping_sub(self.section_address);
274 let mut data = self.section_data;
275 data.skip(offset as usize)
276 .read_error("Invalid PE delay load import thunk table address")?;
277 Ok(ImportThunkList { data })
278 }
279
280 /// Parse a thunk.
281 pub fn import<Pe: ImageNtHeaders>(&self, thunk: Pe::ImageThunkData) -> Result<Import<'data>> {
282 if thunk.is_ordinal() {
283 Ok(Import::Ordinal(thunk.ordinal()))
284 } else {
285 let (hint, name) = self.hint_name(thunk.address())?;
286 Ok(Import::Name(hint, name))
287 }
288 }
289
290 /// Return the hint and name at the given address.
291 ///
292 /// This address may be from [`pe::ImageThunkData32`] or [`pe::ImageThunkData64`].
293 ///
294 /// The hint is an index into the export name pointer table in the target library.
295 pub fn hint_name(&self, address: u32) -> Result<(u16, &'data [u8])> {
296 let offset = address.wrapping_sub(self.section_address);
297 let mut data = self.section_data;
298 data.skip(offset as usize)
299 .read_error("Invalid PE delay load import thunk address")?;
300 let hint = data
301 .read::<U16Bytes<LE>>()
302 .read_error("Missing PE delay load import thunk hint")?
303 .get(LE);
304 let name = data
305 .read_string()
306 .read_error("Missing PE delay load import thunk name")?;
307 Ok((hint, name))
308 }
309 }
310
311 /// A fallible iterator for the descriptors in the delay-load data directory.
312 #[derive(Debug, Clone)]
313 pub struct DelayLoadDescriptorIterator<'data> {
314 data: Bytes<'data>,
315 }
316
317 impl<'data> DelayLoadDescriptorIterator<'data> {
318 /// Return the next descriptor.
319 ///
320 /// Returns `Ok(None)` when a null descriptor is found.
321 pub fn next(&mut self) -> Result<Option<&'data pe::ImageDelayloadDescriptor>> {
322 let import_desc = self
323 .data
324 .read::<pe::ImageDelayloadDescriptor>()
325 .read_error("Missing PE null delay-load import descriptor")?;
326 if import_desc.is_null() {
327 Ok(None)
328 } else {
329 Ok(Some(import_desc))
330 }
331 }
332 }