| 1 | use alloc::vec::Vec; | 
| 2 | use core::fmt::Debug; | 
| 3 |  | 
| 4 | use crate::read::{ByteString, Bytes, Error, ReadError, ReadRef, Result}; | 
| 5 | use crate::{pe, LittleEndian as LE, U16Bytes, U32Bytes}; | 
| 6 |  | 
| 7 | /// Where an export is pointing to. | 
| 8 | #[derive (Clone, Copy)] | 
| 9 | pub enum ExportTarget<'data> { | 
| 10 |     /// The address of the export, relative to the image base. | 
| 11 |     Address(u32), | 
| 12 |     /// Forwarded to an export ordinal in another DLL. | 
| 13 |     /// | 
| 14 |     /// This gives the name of the DLL, and the ordinal. | 
| 15 |     ForwardByOrdinal(&'data [u8], u32), | 
| 16 |     /// Forwarded to an export name in another DLL. | 
| 17 |     /// | 
| 18 |     /// This gives the name of the DLL, and the export name. | 
| 19 |     ForwardByName(&'data [u8], &'data [u8]), | 
| 20 | } | 
| 21 |  | 
| 22 | impl<'data> ExportTarget<'data> { | 
| 23 |     /// Returns true if the target is an address. | 
| 24 |     pub fn is_address(&self) -> bool { | 
| 25 |         match self { | 
| 26 |             ExportTarget::Address(_) => true, | 
| 27 |             _ => false, | 
| 28 |         } | 
| 29 |     } | 
| 30 |  | 
| 31 |     /// Returns true if the export is forwarded to another DLL. | 
| 32 |     pub fn is_forward(&self) -> bool { | 
| 33 |         !self.is_address() | 
| 34 |     } | 
| 35 | } | 
| 36 |  | 
| 37 | /// An export from a PE file. | 
| 38 | /// | 
| 39 | /// There are multiple kinds of PE exports (with or without a name, and local or forwarded). | 
| 40 | #[derive (Clone, Copy)] | 
| 41 | pub struct Export<'data> { | 
| 42 |     /// The ordinal of the export. | 
| 43 |     /// | 
| 44 |     /// These are sequential, starting at a base specified in the DLL. | 
| 45 |     pub ordinal: u32, | 
| 46 |     /// The name of the export, if known. | 
| 47 |     pub name: Option<&'data [u8]>, | 
| 48 |     /// The target of this export. | 
| 49 |     pub target: ExportTarget<'data>, | 
| 50 | } | 
| 51 |  | 
| 52 | impl<'a> Debug for Export<'a> { | 
| 53 |     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::result::Result<(), core::fmt::Error> { | 
| 54 |         f&mut DebugStruct<'_, '_>.debug_struct("Export" ) | 
| 55 |             .field("ordinal" , &self.ordinal) | 
| 56 |             .field("name" , &self.name.map(ByteString)) | 
| 57 |             .field(name:"target" , &self.target) | 
| 58 |             .finish() | 
| 59 |     } | 
| 60 | } | 
| 61 |  | 
| 62 | impl<'a> Debug for ExportTarget<'a> { | 
| 63 |     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::result::Result<(), core::fmt::Error> { | 
| 64 |         match self { | 
| 65 |             ExportTarget::Address(address: &u32) => write!(f, "Address( {:#x})" , address), | 
| 66 |             ExportTarget::ForwardByOrdinal(library: &&[u8], ordinal: &u32) => write!( | 
| 67 |                 f, | 
| 68 |                 "ForwardByOrdinal( {:?}.# {})" , | 
| 69 |                 ByteString(library), | 
| 70 |                 ordinal | 
| 71 |             ), | 
| 72 |             ExportTarget::ForwardByName(library: &&[u8], name: &&[u8]) => write!( | 
| 73 |                 f, | 
| 74 |                 "ForwardByName( {:?}. {:?})" , | 
| 75 |                 ByteString(library), | 
| 76 |                 ByteString(name) | 
| 77 |             ), | 
| 78 |         } | 
| 79 |     } | 
| 80 | } | 
| 81 |  | 
| 82 | /// A partially parsed PE export table. | 
| 83 | /// | 
| 84 | /// Returned by [`DataDirectories::export_table`](super::DataDirectories::export_table). | 
| 85 | #[derive (Debug, Clone)] | 
| 86 | pub struct ExportTable<'data> { | 
| 87 |     data: Bytes<'data>, | 
| 88 |     virtual_address: u32, | 
| 89 |     directory: &'data pe::ImageExportDirectory, | 
| 90 |     addresses: &'data [U32Bytes<LE>], | 
| 91 |     names: &'data [U32Bytes<LE>], | 
| 92 |     name_ordinals: &'data [U16Bytes<LE>], | 
| 93 | } | 
| 94 |  | 
| 95 | impl<'data> ExportTable<'data> { | 
| 96 |     /// Parse the export table given its section data and address. | 
| 97 |     pub fn parse(data: &'data [u8], virtual_address: u32) -> Result<Self> { | 
| 98 |         let directory = Self::parse_directory(data)?; | 
| 99 |         let data = Bytes(data); | 
| 100 |  | 
| 101 |         let mut addresses = &[][..]; | 
| 102 |         let address_of_functions = directory.address_of_functions.get(LE); | 
| 103 |         if address_of_functions != 0 { | 
| 104 |             addresses = data | 
| 105 |                 .read_slice_at::<U32Bytes<_>>( | 
| 106 |                     address_of_functions.wrapping_sub(virtual_address) as usize, | 
| 107 |                     directory.number_of_functions.get(LE) as usize, | 
| 108 |                 ) | 
| 109 |                 .read_error("Invalid PE export address table" )?; | 
| 110 |         } | 
| 111 |  | 
| 112 |         let mut names = &[][..]; | 
| 113 |         let mut name_ordinals = &[][..]; | 
| 114 |         let address_of_names = directory.address_of_names.get(LE); | 
| 115 |         let address_of_name_ordinals = directory.address_of_name_ordinals.get(LE); | 
| 116 |         if address_of_names != 0 { | 
| 117 |             if address_of_name_ordinals == 0 { | 
| 118 |                 return Err(Error("Missing PE export ordinal table" )); | 
| 119 |             } | 
| 120 |  | 
| 121 |             let number = directory.number_of_names.get(LE) as usize; | 
| 122 |             names = data | 
| 123 |                 .read_slice_at::<U32Bytes<_>>( | 
| 124 |                     address_of_names.wrapping_sub(virtual_address) as usize, | 
| 125 |                     number, | 
| 126 |                 ) | 
| 127 |                 .read_error("Invalid PE export name pointer table" )?; | 
| 128 |             name_ordinals = data | 
| 129 |                 .read_slice_at::<U16Bytes<_>>( | 
| 130 |                     address_of_name_ordinals.wrapping_sub(virtual_address) as usize, | 
| 131 |                     number, | 
| 132 |                 ) | 
| 133 |                 .read_error("Invalid PE export ordinal table" )?; | 
| 134 |         } | 
| 135 |  | 
| 136 |         Ok(ExportTable { | 
| 137 |             data, | 
| 138 |             virtual_address, | 
| 139 |             directory, | 
| 140 |             addresses, | 
| 141 |             names, | 
| 142 |             name_ordinals, | 
| 143 |         }) | 
| 144 |     } | 
| 145 |  | 
| 146 |     /// Parse the export directory given its section data. | 
| 147 |     pub fn parse_directory(data: &'data [u8]) -> Result<&'data pe::ImageExportDirectory> { | 
| 148 |         data.read_at::<pe::ImageExportDirectory>(0) | 
| 149 |             .read_error("Invalid PE export dir size" ) | 
| 150 |     } | 
| 151 |  | 
| 152 |     /// Returns the header of the export table. | 
| 153 |     pub fn directory(&self) -> &'data pe::ImageExportDirectory { | 
| 154 |         self.directory | 
| 155 |     } | 
| 156 |  | 
| 157 |     /// Returns the base value of ordinals. | 
| 158 |     /// | 
| 159 |     /// Adding this to an address index will give an ordinal. | 
| 160 |     pub fn ordinal_base(&self) -> u32 { | 
| 161 |         self.directory.base.get(LE) | 
| 162 |     } | 
| 163 |  | 
| 164 |     /// Returns the unparsed address table. | 
| 165 |     /// | 
| 166 |     /// An address table entry may be a local address, or the address of a forwarded export entry. | 
| 167 |     /// See [`Self::is_forward`] and [`Self::target_from_address`]. | 
| 168 |     pub fn addresses(&self) -> &'data [U32Bytes<LE>] { | 
| 169 |         self.addresses | 
| 170 |     } | 
| 171 |  | 
| 172 |     /// Returns the unparsed name pointer table. | 
| 173 |     /// | 
| 174 |     /// A name pointer table entry can be used with [`Self::name_from_pointer`]. | 
| 175 |     pub fn name_pointers(&self) -> &'data [U32Bytes<LE>] { | 
| 176 |         self.names | 
| 177 |     } | 
| 178 |  | 
| 179 |     /// Returns the unparsed ordinal table. | 
| 180 |     /// | 
| 181 |     /// An ordinal table entry is a 0-based index into the address table. | 
| 182 |     /// See [`Self::address_by_index`] and [`Self::target_by_index`]. | 
| 183 |     pub fn name_ordinals(&self) -> &'data [U16Bytes<LE>] { | 
| 184 |         self.name_ordinals | 
| 185 |     } | 
| 186 |  | 
| 187 |     /// Returns an iterator for the entries in the name pointer table and ordinal table. | 
| 188 |     /// | 
| 189 |     /// A name pointer table entry can be used with [`Self::name_from_pointer`]. | 
| 190 |     /// | 
| 191 |     /// An ordinal table entry is a 0-based index into the address table. | 
| 192 |     /// See [`Self::address_by_index`] and [`Self::target_by_index`]. | 
| 193 |     pub fn name_iter(&self) -> impl Iterator<Item = (u32, u16)> + 'data { | 
| 194 |         self.names | 
| 195 |             .iter() | 
| 196 |             .map(|x| x.get(LE)) | 
| 197 |             .zip(self.name_ordinals.iter().map(|x| x.get(LE))) | 
| 198 |     } | 
| 199 |  | 
| 200 |     /// Returns the export address table entry at the given address index. | 
| 201 |     /// | 
| 202 |     /// This may be a local address, or the address of a forwarded export entry. | 
| 203 |     /// See [`Self::is_forward`] and [`Self::target_from_address`]. | 
| 204 |     /// | 
| 205 |     /// `index` is a 0-based index into the export address table. | 
| 206 |     pub fn address_by_index(&self, index: u32) -> Result<u32> { | 
| 207 |         Ok(self | 
| 208 |             .addresses | 
| 209 |             .get(index as usize) | 
| 210 |             .read_error("Invalid PE export address index" )? | 
| 211 |             .get(LE)) | 
| 212 |     } | 
| 213 |  | 
| 214 |     /// Returns the export address table entry at the given ordinal. | 
| 215 |     /// | 
| 216 |     /// This may be a local address, or the address of a forwarded export entry. | 
| 217 |     /// See [`Self::is_forward`] and [`Self::target_from_address`]. | 
| 218 |     pub fn address_by_ordinal(&self, ordinal: u32) -> Result<u32> { | 
| 219 |         self.address_by_index(ordinal.wrapping_sub(self.ordinal_base())) | 
| 220 |     } | 
| 221 |  | 
| 222 |     /// Returns the target of the export at the given address index. | 
| 223 |     /// | 
| 224 |     /// `index` is a 0-based index into the export address table. | 
| 225 |     pub fn target_by_index(&self, index: u32) -> Result<ExportTarget<'data>> { | 
| 226 |         self.target_from_address(self.address_by_index(index)?) | 
| 227 |     } | 
| 228 |  | 
| 229 |     /// Returns the target of the export at the given ordinal. | 
| 230 |     pub fn target_by_ordinal(&self, ordinal: u32) -> Result<ExportTarget<'data>> { | 
| 231 |         self.target_from_address(self.address_by_ordinal(ordinal)?) | 
| 232 |     } | 
| 233 |  | 
| 234 |     /// Convert an export address table entry into a target. | 
| 235 |     pub fn target_from_address(&self, address: u32) -> Result<ExportTarget<'data>> { | 
| 236 |         Ok(if let Some(forward) = self.forward_string(address)? { | 
| 237 |             let i = forward | 
| 238 |                 .iter() | 
| 239 |                 .position(|x| *x == b'.' ) | 
| 240 |                 .read_error("Missing PE forwarded export separator" )?; | 
| 241 |             let library = &forward[..i]; | 
| 242 |             match &forward[i + 1..] { | 
| 243 |                 [b'#' , digits @ ..] => { | 
| 244 |                     let ordinal = | 
| 245 |                         parse_ordinal(digits).read_error("Invalid PE forwarded export ordinal" )?; | 
| 246 |                     ExportTarget::ForwardByOrdinal(library, ordinal) | 
| 247 |                 } | 
| 248 |                 [] => { | 
| 249 |                     return Err(Error("Missing PE forwarded export name" )); | 
| 250 |                 } | 
| 251 |                 name => ExportTarget::ForwardByName(library, name), | 
| 252 |             } | 
| 253 |         } else { | 
| 254 |             ExportTarget::Address(address) | 
| 255 |         }) | 
| 256 |     } | 
| 257 |  | 
| 258 |     fn forward_offset(&self, address: u32) -> Option<usize> { | 
| 259 |         let offset = address.wrapping_sub(self.virtual_address) as usize; | 
| 260 |         if offset < self.data.len() { | 
| 261 |             Some(offset) | 
| 262 |         } else { | 
| 263 |             None | 
| 264 |         } | 
| 265 |     } | 
| 266 |  | 
| 267 |     /// Return true if the export address table entry is a forward. | 
| 268 |     pub fn is_forward(&self, address: u32) -> bool { | 
| 269 |         self.forward_offset(address).is_some() | 
| 270 |     } | 
| 271 |  | 
| 272 |     /// Return the forward string if the export address table entry is a forward. | 
| 273 |     pub fn forward_string(&self, address: u32) -> Result<Option<&'data [u8]>> { | 
| 274 |         if let Some(offset) = self.forward_offset(address) { | 
| 275 |             self.data | 
| 276 |                 .read_string_at(offset) | 
| 277 |                 .read_error("Invalid PE forwarded export address" ) | 
| 278 |                 .map(Some) | 
| 279 |         } else { | 
| 280 |             Ok(None) | 
| 281 |         } | 
| 282 |     } | 
| 283 |  | 
| 284 |     /// Convert an export name pointer table entry into a name. | 
| 285 |     pub fn name_from_pointer(&self, name_pointer: u32) -> Result<&'data [u8]> { | 
| 286 |         let offset = name_pointer.wrapping_sub(self.virtual_address); | 
| 287 |         self.data | 
| 288 |             .read_string_at(offset as usize) | 
| 289 |             .read_error("Invalid PE export name pointer" ) | 
| 290 |     } | 
| 291 |  | 
| 292 |     /// Returns the parsed exports in this table. | 
| 293 |     pub fn exports(&self) -> Result<Vec<Export<'data>>> { | 
| 294 |         // First, let's list all exports. | 
| 295 |         let mut exports = Vec::new(); | 
| 296 |         let ordinal_base = self.ordinal_base(); | 
| 297 |         for (i, address) in self.addresses.iter().enumerate() { | 
| 298 |             // Convert from an array index to an ordinal. | 
| 299 |             let ordinal = ordinal_base.wrapping_add(i as u32); | 
| 300 |             let target = self.target_from_address(address.get(LE))?; | 
| 301 |             exports.push(Export { | 
| 302 |                 ordinal, | 
| 303 |                 target, | 
| 304 |                 // Might be populated later. | 
| 305 |                 name: None, | 
| 306 |             }); | 
| 307 |         } | 
| 308 |  | 
| 309 |         // Now, check whether some (or all) of them have an associated name. | 
| 310 |         // `ordinal_index` is a 0-based index into `addresses`. | 
| 311 |         for (name_pointer, ordinal_index) in self.name_iter() { | 
| 312 |             let name = self.name_from_pointer(name_pointer)?; | 
| 313 |             exports | 
| 314 |                 .get_mut(ordinal_index as usize) | 
| 315 |                 .read_error("Invalid PE export ordinal" )? | 
| 316 |                 .name = Some(name); | 
| 317 |         } | 
| 318 |  | 
| 319 |         Ok(exports) | 
| 320 |     } | 
| 321 | } | 
| 322 |  | 
| 323 | fn parse_ordinal(digits: &[u8]) -> Option<u32> { | 
| 324 |     if digits.is_empty() { | 
| 325 |         return None; | 
| 326 |     } | 
| 327 |     let mut result: u32 = 0; | 
| 328 |     for &c: u8 in digits { | 
| 329 |         let x: u32 = (c as char).to_digit(radix:10)?; | 
| 330 |         result = result.checked_mul(10)?.checked_add(x)?; | 
| 331 |     } | 
| 332 |     Some(result) | 
| 333 | } | 
| 334 |  |