Line data Source code
1 : use lief_ffi as ffi;
2 :
3 : use num_traits::{cast, Num};
4 : use std::mem::size_of;
5 : use std::pin::Pin;
6 : use std::path::Path;
7 :
8 : use super::builder::Config;
9 : use super::parser_config::Config as ParserConfig;
10 : use super::data_directory::{DataDirectories, DataDirectory};
11 : use super::debug::{self, Entries, DebugEntry};
12 : use super::delay_import::{DelayImport, DelayImports};
13 : use super::export::Export;
14 : use super::import::{Import, Imports};
15 : use super::load_configuration::LoadConfiguration;
16 : use super::relocation::Relocations;
17 : use super::resources::{Manager as ResourcesManager, NodeBase};
18 : use super::resources::Node as ResourceNode;
19 : use super::rich_header::RichHeader;
20 : use super::section::{Section, Sections};
21 : use super::signature::Signatures;
22 : use super::tls::TLS;
23 : use super::{data_directory, signature};
24 : use super::debug::CodeViewPDB;
25 : use super::exception::RuntimeExceptionFunction;
26 : use crate::coff;
27 : use crate::coff::Symbol;
28 :
29 : use crate::common::{into_optional, FromFFI, AsFFI};
30 : use crate::declare_iterator;
31 : use crate::generic;
32 : use crate::to_conv_result;
33 : use crate::to_result;
34 : use crate::to_slice;
35 : use crate::Error;
36 :
37 : use super::Algorithms;
38 : use super::{DosHeader, Header, OptionalHeader};
39 :
40 : /// This is the main interface to read and write PE binary attributes.
41 : ///
42 : /// Note that this structure implements the [`generic::Binary`] trait from which other generic
43 : /// functions are exposed
44 : ///
45 : /// ```
46 : /// fn use_trait(pe: &Binary) {
47 : /// let generic_binary = pe as &dyn generic::Binary;
48 : /// println!("{}", generic_binary.entrypoint());
49 : /// }
50 : ///
51 : /// ```
52 : pub struct Binary {
53 : ptr: cxx::UniquePtr<ffi::PE_Binary>,
54 : }
55 :
56 : impl FromFFI<ffi::PE_Binary> for Binary {
57 324 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_Binary>) -> Self {
58 324 : Self { ptr }
59 324 : }
60 : }
61 :
62 : impl Binary {
63 : /// Parse from a filepath given as a string
64 2 : pub fn parse<P: AsRef<Path>>(path: P) -> Option<Self> {
65 2 : let ffi = ffi::PE_Binary::parse(path.as_ref().to_str().unwrap());
66 2 : if ffi.is_null() {
67 0 : return None;
68 2 : }
69 2 : Some(Binary::from_ffi(ffi))
70 2 : }
71 :
72 : /// Parse from a string file path and with a provided configuration
73 12 : pub fn parse_with_config<P: AsRef<Path>>(path: P, config: &ParserConfig) -> Option<Self> {
74 12 : let ffi_config = config.to_ffi();
75 12 : let ffi = ffi::PE_Binary::parse_with_config(path.as_ref().to_str().unwrap(), &ffi_config);
76 12 : if ffi.is_null() {
77 0 : return None;
78 12 : }
79 12 : Some(Binary::from_ffi(ffi))
80 12 : }
81 :
82 : /// DosHeader which starts the PE files
83 156 : pub fn dos_header(&self) -> DosHeader<'_> {
84 156 : DosHeader::from_ffi(self.ptr.dos_header())
85 156 : }
86 :
87 : /// Header that follows the [`Binary::header`]. It is named
88 : /// *optional* from the COFF specification but it is mandatory in a PE file.
89 168 : pub fn optional_header(&self) -> OptionalHeader<'_> {
90 168 : OptionalHeader::from_ffi(self.ptr.optional_header())
91 168 : }
92 :
93 : /// Re-compute the value of [`OptionalHeader::checksum`]
94 156 : pub fn compute_checksum(&self) -> u32 {
95 156 : self.ptr.compute_checksum()
96 156 : }
97 :
98 : /// Next header after the [`Binary::dos_header`]
99 156 : pub fn header(&self) -> Header<'_> {
100 156 : Header::from_ffi(self.ptr.header())
101 156 : }
102 :
103 : /// Return TLS information if present
104 156 : pub fn tls(&self) -> Option<TLS<'_>> {
105 156 : into_optional(self.ptr.tls())
106 156 : }
107 :
108 : /// Return rich header information if present.
109 156 : pub fn rich_header(&self) -> Option<RichHeader<'_>> {
110 156 : into_optional(self.ptr.rich_header())
111 156 : }
112 :
113 : /// Return export information
114 156 : pub fn export(&self) -> Option<Export<'_>> {
115 156 : into_optional(self.ptr.get_export())
116 156 : }
117 :
118 : /// Return the root of the PE's resource tree
119 312 : pub fn resources(&self) -> Option<ResourceNode<'_>> {
120 312 : into_optional(self.ptr.resources())
121 312 : }
122 :
123 : /// Return a manager interface to read and manipulate the resources tree with a user friendly
124 : /// interface.
125 156 : pub fn resources_manager(&self) -> Option<ResourcesManager<'_>> {
126 156 : into_optional(self.ptr.resources_manager())
127 156 : }
128 :
129 : /// Return the imports as an **iterator** over the [`Import`] structure
130 156 : pub fn imports(&self) -> Imports<'_> {
131 156 : Imports::new(self.ptr.imports())
132 156 : }
133 :
134 : /// Return the data directories as an iterator over the [`DataDirectory`] structure
135 156 : pub fn data_directories(&self) -> DataDirectories<'_> {
136 156 : DataDirectories::new(self.ptr.data_directories())
137 156 : }
138 :
139 : /// Return the sections as an iterator over the [`Section`] structure
140 156 : pub fn sections(&self) -> Sections<'_> {
141 156 : Sections::new(self.ptr.sections())
142 156 : }
143 :
144 : /// Return the relocations as an iterator over the [`super::Relocation`] structure
145 156 : pub fn relocations(&self) -> Relocations<'_> {
146 156 : Relocations::new(self.ptr.relocations())
147 156 : }
148 :
149 : /// Return the delayed imports as an iterator over the [`DelayImport`] structure
150 156 : pub fn delay_imports(&self) -> DelayImports<'_> {
151 156 : DelayImports::new(self.ptr.delay_imports())
152 156 : }
153 :
154 : /// Return an iterator over the [`signature::Signature`] if the current PE is authenticode-signed.
155 168 : pub fn signatures(&self) -> Signatures<'_> {
156 168 : Signatures::new(self.ptr.signatures())
157 168 : }
158 :
159 : /// Return an iterator over the [`debug::Entries`] of the binary.
160 156 : pub fn debug(&self) -> DebugEntries<'_> {
161 156 : DebugEntries::new(self.ptr.debug())
162 156 : }
163 :
164 : /// Compute the authentihash for the current PE with the given algorithms.
165 156 : pub fn authentihash(&self, algo: Algorithms) -> Vec<u8> {
166 156 : Vec::from(self.ptr.authentihash(algo.into()).as_slice())
167 156 : }
168 :
169 : /// Return load configuration info if present.
170 156 : pub fn load_configuration(&self) -> Option<LoadConfiguration<'_>> {
171 156 : into_optional(self.ptr.load_configuration())
172 156 : }
173 :
174 : /// Return the raw data between the [`Binary::dos_header`] and the regular [`Binary::header`]
175 156 : pub fn dos_stub(&self) -> &[u8] {
176 156 : to_slice!(self.ptr.dos_stub());
177 156 : }
178 :
179 : /// Return the original overlay data of the file
180 156 : pub fn overlay(&self) -> &[u8] {
181 156 : to_slice!(self.ptr.overlay());
182 156 : }
183 :
184 : /// Return the offset computed by LIEF to identify overlay data
185 156 : pub fn overlay_offset(&self) -> u64 {
186 156 : self.ptr.overlay_offset()
187 156 : }
188 :
189 : /// Convert a **relative** virtual address into an offset
190 12 : pub fn rva_to_offset(&self, rva: u64) -> u64 {
191 12 : self.ptr.rva_to_offset(rva)
192 12 : }
193 :
194 : /// Convert an **absolute** virtual address into an offset.
195 12 : pub fn va_to_offset(&self, va: u64) -> u64 {
196 12 : self.ptr.va_to_offset(va)
197 12 : }
198 :
199 : /// Convert the given offset into a relative virtual address (RVA).
200 12 : pub fn offset_to_rva(&self, offset: u64) -> u64 {
201 12 : self.ptr.offset_to_rva(offset)
202 12 : }
203 :
204 : /// Return the size of the current binary when loaded in memory.
205 156 : pub fn virtual_size(&self) -> u64 {
206 156 : self.ptr.virtual_size()
207 156 : }
208 :
209 : /// Compute the size of all the headers.
210 156 : pub fn sizeof_headers(&self) -> u64 {
211 156 : self.ptr.sizeof_headers()
212 156 : }
213 :
214 : /// Find a section by its offset
215 24 : pub fn section_from_offset(&self, offset: u64) -> Option<Section<'_>> {
216 24 : into_optional(self.ptr.section_from_offset(offset))
217 24 : }
218 :
219 : /// Find a section by its **relative** virtual address
220 24 : pub fn section_from_rva(&self, rva: u64) -> Option<Section<'_>> {
221 24 : into_optional(self.ptr.section_from_rva(rva))
222 24 : }
223 :
224 : /// Find a section by its name
225 48 : pub fn section_by_name(&self, name: &str) -> Option<Section<'_>> {
226 48 : into_optional(self.ptr.section_by_name(name))
227 48 : }
228 :
229 : /// Add a section to the binary and return the section added.
230 0 : pub fn add_section(&mut self, section: Section) -> Option<Section<'_>> {
231 0 : into_optional(self.ptr.as_mut().unwrap().add_section(section.as_ffi()))
232 0 : }
233 :
234 : /// Find the data directory with the given type
235 168 : pub fn data_directory_by_type(&self, dir_type: data_directory::Type) -> Option<DataDirectory<'_>> {
236 168 : into_optional(self.ptr.data_directory_by_type(dir_type.into()))
237 168 : }
238 :
239 : /// Verify the binary against the embedded signature(s) (if any)
240 : ///
241 : /// First, it checks that the embedded signatures are correct (c.f. [`signature::Signature::check`])
242 : /// and then, it checks that the authentihash matches [`crate::pe::signature::content_info::ContentInfo::digest`]
243 12 : pub fn verify_signature(
244 12 : &self,
245 12 : checks: signature::VerificationChecks,
246 12 : ) -> signature::VerificationFlags {
247 12 : signature::VerificationFlags::from(self.ptr.verify_signature(checks.into()))
248 12 : }
249 :
250 : /// Verify the binary with the [`signature::Signature`] object provided in the first parameter.
251 : /// It can be used to verify a detached signature:
252 : ///
253 : /// ```
254 : /// if let Some(sig) = Signature::from_file(path_str.unwrap()) {
255 : /// pe.verify_signature(&sig, signature::VerificationChecks::DEFAULT);
256 : /// }
257 : /// ```
258 12 : pub fn verify_with_signature(
259 12 : &self,
260 12 : sig: &signature::Signature,
261 12 : checks: signature::VerificationChecks,
262 12 : ) -> signature::VerificationFlags {
263 12 : signature::VerificationFlags::from(
264 12 : self.ptr.verify_with_signature(sig.into(), checks.into()),
265 12 : )
266 12 : }
267 :
268 : /// Find an import by its DLL name (case insensitive)
269 24 : pub fn import_by_name(&self, name: &str) -> Option<Import<'_>> {
270 24 : into_optional(self.ptr.import_by_name(name))
271 24 : }
272 :
273 : /// Find a delayed import by its name
274 24 : pub fn delay_import_by_name(&self, name: &str) -> Option<DelayImport<'_>> {
275 24 : into_optional(self.ptr.delay_import_by_name(name))
276 24 : }
277 :
278 : /// Return the sized content from the virtual address
279 36 : pub fn content_from_virtual_address(&self, address: u64, size: u64) -> &[u8] {
280 36 : to_slice!(self.ptr.get_content_from_virtual_address(address, size));
281 36 : }
282 :
283 156 : pub fn functions(&self) -> generic::Functions<'_> {
284 156 : generic::Functions::new(self.ptr.functions())
285 156 : }
286 :
287 : /// Return the data directory associated with the export table
288 0 : pub fn export_dir(&self) -> Option<DataDirectory<'_>> {
289 0 : into_optional(self.ptr.export_dir())
290 0 : }
291 :
292 : /// Return the data directory associated with the import table
293 0 : pub fn import_dir(&self) -> Option<DataDirectory<'_>> {
294 0 : into_optional(self.ptr.import_dir())
295 0 : }
296 :
297 : /// Return the data directory associated with the resources tree
298 0 : pub fn rsrc_dir(&self) -> Option<DataDirectory<'_>> {
299 0 : into_optional(self.ptr.rsrc_dir())
300 0 : }
301 :
302 : /// Return the data directory associated with the exceptions
303 0 : pub fn exceptions_dir(&self) -> Option<DataDirectory<'_>> {
304 0 : into_optional(self.ptr.exceptions_dir())
305 0 : }
306 :
307 : /// Return the data directory associated with the certificate table
308 : /// (authenticode)
309 0 : pub fn cert_dir(&self) -> Option<DataDirectory<'_>> {
310 0 : into_optional(self.ptr.cert_dir())
311 0 : }
312 :
313 : /// Return the data directory associated with the relocation table
314 0 : pub fn relocation_dir(&self) -> Option<DataDirectory<'_>> {
315 0 : into_optional(self.ptr.relocation_dir())
316 0 : }
317 :
318 : /// Return the data directory associated with the debug table
319 0 : pub fn debug_dir(&self) -> Option<DataDirectory<'_>> {
320 0 : into_optional(self.ptr.debug_dir())
321 0 : }
322 :
323 : /// Return the data directory associated with TLS
324 0 : pub fn tls_dir(&self) -> Option<DataDirectory<'_>> {
325 0 : into_optional(self.ptr.tls_dir())
326 0 : }
327 :
328 : /// Return the data directory associated with the load config
329 0 : pub fn load_config_dir(&self) -> Option<DataDirectory<'_>> {
330 0 : into_optional(self.ptr.load_config_dir())
331 0 : }
332 :
333 : /// Return the data directory associated with the IAT
334 0 : pub fn iat_dir(&self) -> Option<DataDirectory<'_>> {
335 0 : into_optional(self.ptr.iat_dir())
336 0 : }
337 :
338 : /// Return the data directory associated with delayed imports
339 0 : pub fn export_delay_dirdir(&self) -> Option<DataDirectory<'_>> {
340 0 : into_optional(self.ptr.delay_dir())
341 0 : }
342 :
343 : /// Get the integer value at the given virtual address
344 0 : pub fn get_int_from_virtual_address<T>(&self, addr: u64) -> Result<T, Error>
345 0 : where
346 0 : T: Num + cast::FromPrimitive + cast::ToPrimitive,
347 0 : {
348 0 : // Can't be in the generic trait because of:
349 0 : // > for a trait to be "object safe" it needs to allow building a vtable to allow the call
350 0 : // > to be resolvable dynamically; for more information visit
351 0 : // > https://doc.rust-lang.org/reference/items/traits.html#object-safety
352 0 : if size_of::<T>() == size_of::<u8>() {
353 0 : to_conv_result!(
354 0 : ffi::AbstractBinary::get_u8,
355 0 : self.ptr.as_ref().unwrap().as_ref(),
356 0 : |value| {
357 0 : T::from_u8(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
358 0 : },
359 0 : addr
360 : );
361 0 : }
362 0 :
363 0 : if size_of::<T>() == size_of::<u16>() {
364 0 : to_conv_result!(
365 0 : ffi::AbstractBinary::get_u16,
366 0 : self.ptr.as_ref().unwrap().as_ref(),
367 0 : |value| {
368 0 : T::from_u16(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
369 0 : },
370 0 : addr
371 : );
372 0 : }
373 0 :
374 0 : if size_of::<T>() == size_of::<u32>() {
375 0 : to_conv_result!(
376 0 : ffi::AbstractBinary::get_u32,
377 0 : self.ptr.as_ref().unwrap().as_ref(),
378 0 : |value| {
379 0 : T::from_u32(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
380 0 : },
381 0 : addr
382 : );
383 0 : }
384 0 :
385 0 : if size_of::<T>() == size_of::<u64>() {
386 0 : to_conv_result!(
387 0 : ffi::AbstractBinary::get_u64,
388 0 : self.ptr.as_ref().unwrap().as_ref(),
389 0 : |value| {
390 0 : T::from_u64(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
391 0 : },
392 0 : addr
393 : );
394 0 : }
395 0 :
396 0 : Err(Error::NotSupported)
397 0 : }
398 :
399 : /// Add an imported library (i.e. `DLL`) to the binary
400 0 : pub fn add_import<'a>(&'a mut self, name: &str) -> Import<'a> {
401 0 : Import::from_ffi(self.ptr.pin_mut().add_import(name))
402 0 : }
403 :
404 : /// Add an imported library (i.e. `DLL`) to the binary.
405 : ///
406 : /// The second parameter `pos` defines where to insert the import.
407 0 : pub fn add_import_at_pos<'a>(&'a mut self, name: &str, pos: u32) -> Import<'a> {
408 0 : Import::from_ffi(self.ptr.pin_mut().add_import_pos(name, pos))
409 0 : }
410 :
411 : /// Remove the imported library with the given `name`
412 0 : pub fn remove_import(&mut self, name: &str) {
413 0 : self.ptr.pin_mut().remove_import(name);
414 0 : }
415 :
416 : /// Remove all libraries in the binary
417 0 : pub fn remove_all_imports(&mut self) {
418 0 : self.ptr.pin_mut().remove_all_imports();
419 0 : }
420 :
421 : /// Remove the TLS from the binary
422 0 : pub fn remove_tls(&mut self) {
423 0 : self.ptr.pin_mut().remove_tls();
424 0 : }
425 :
426 : /// Set or change the TLS information
427 0 : pub fn set_tls(&mut self, tls: &TLS) {
428 0 : self.ptr.pin_mut().set_tls(tls.as_ffi());
429 0 : }
430 :
431 : /// Change or set the resources tree to given node
432 0 : pub fn set_resources(&mut self, node: &dyn NodeBase) {
433 0 : self.ptr.pin_mut().set_resources(node.get_base());
434 0 : }
435 :
436 : /// Add a new debug entry
437 0 : pub fn add_debug_info<'a>(&'a mut self, entry: &dyn DebugEntry) -> Option<Entries<'a>> {
438 0 : into_optional(self.ptr.pin_mut().add_debug_info(entry.get_base()))
439 0 : }
440 :
441 : /// Remove a specific debug entry
442 0 : pub fn remove_debug(&mut self, entry: &dyn DebugEntry) -> bool {
443 0 : self.ptr.pin_mut().remove_debug(entry.get_base())
444 0 : }
445 :
446 : /// Remove all debug info
447 0 : pub fn clear_debug(&mut self) -> bool {
448 0 : self.ptr.pin_mut().clear_debug()
449 0 : }
450 :
451 : /// Return the [`CodeViewPDB`] object if present
452 0 : pub fn codeview_pdb(&self) -> Option<CodeViewPDB<'_>> {
453 0 : into_optional(self.ptr.codeview_pdb())
454 0 : }
455 :
456 : /// Write back the current PE binary into the file specified in parameter
457 0 : pub fn write<P: AsRef<Path>>(&mut self, output: P) {
458 0 : self.ptr.as_mut().unwrap().write(output.as_ref().to_str().unwrap());
459 0 : }
460 :
461 : /// Write back the current PE binary into the file specified in parameter with the
462 : /// configuration provided in the second parameter.
463 0 : pub fn write_with_config<P: AsRef<Path>>(&mut self, output: P, config: Config) {
464 0 : let ffi_config = config.to_ffi();
465 0 : self.ptr.as_mut().unwrap().write_with_config(output.as_ref().to_str().unwrap(),
466 0 : ffi_config.as_ref().unwrap());
467 0 : }
468 :
469 : /// Iterator over the strings located in the COFF string table
470 156 : pub fn coff_string_table(&self) -> COFFStrings<'_> {
471 156 : COFFStrings::new(self.ptr.coff_string_table())
472 156 : }
473 :
474 : /// Return an iterator over the binary (COFF) symbols (if any).
475 156 : pub fn symbols(&self) -> Symbols<'_> {
476 156 : Symbols::new(self.ptr.symbols())
477 156 : }
478 :
479 : /// Try to find the COFF string at the given offset in the COFF string table.
480 : ///
481 : /// <div class="warning">
482 : /// This offset must include the first 4 bytes holding the size of the table.
483 : /// Hence, the first string starts a the offset 4.
484 : /// </div>
485 0 : pub fn find_coff_string_at(&self, offset: u32) -> Option<coff::String<'_>> {
486 0 : into_optional(self.ptr.find_coff_string_at(offset))
487 0 : }
488 :
489 : /// Iterator over the exception (`_RUNTIME_FUNCTION`) functions
490 : ///
491 : /// This function requires that the option [`ParserConfig::parse_exceptions`] was turned on
492 : /// (default is `false`) when parsing the binary.
493 156 : pub fn exceptions(&self) -> Exceptions<'_> {
494 156 : Exceptions::new(self.ptr.exceptions())
495 156 : }
496 :
497 : /// Try to find the exception info at the given RVA
498 : ///
499 : /// This function requires that the option [`ParserConfig::parse_exceptions`] was turned on
500 : /// (default is `false`) when parsing the binary.
501 0 : pub fn find_exception_at(&self, rva: u32) -> Option<RuntimeExceptionFunction<'_>> {
502 0 : into_optional(self.ptr.find_exception_at(rva))
503 0 : }
504 :
505 : /// True if this binary is compiled in ARM64EC mode (emulation compatible)
506 0 : pub fn is_arm64ec(&self) -> bool {
507 0 : self.ptr.is_arm64ec()
508 0 : }
509 :
510 : /// True if this binary is compiled in ARM64X mode (contains both ARM64 and ARM64EC).
511 0 : pub fn is_arm64x(&self) -> bool {
512 0 : self.ptr.is_arm64x()
513 0 : }
514 :
515 : /// If the current binary contains dynamic relocations
516 : /// (e.g. LIEF::PE::DynamicFixupARM64X), this function returns the
517 : /// **relocated** view of the current PE.
518 : ///
519 : /// This can be used to get the alternative PE binary, targeting a different
520 : /// architectures.
521 : ///
522 : /// <div class="warning">
523 : /// This function is <b>moving</b> and taking the ownership of the nested
524 : /// PE binary. This means that subsequent calls to this function will return None.
525 : /// </div>
526 : ///
527 : /// This function requires that the option [`ParserConfig::parse_arm64x_binary`] was turned on
528 : /// (default is `false`) when parsing the binary.
529 156 : pub fn nested_pe_binary(&self) -> Option<Binary> {
530 156 : into_optional(self.ptr.nested_pe_binary())
531 156 : }
532 :
533 : /// Set or change the export table
534 0 : pub fn set_export(&mut self, export: &Export) {
535 0 : self.ptr.pin_mut().set_export(export.as_ffi());
536 0 : }
537 : }
538 :
539 : impl AsFFI<ffi::PE_Binary> for Binary {
540 0 : fn as_ffi(&self) -> &ffi::PE_Binary {
541 0 : self.ptr.as_ref().unwrap()
542 0 : }
543 :
544 0 : fn as_mut_ffi(&mut self) -> std::pin::Pin<&mut ffi::PE_Binary> {
545 0 : self.ptr.pin_mut()
546 0 : }
547 : }
548 :
549 :
550 : impl std::fmt::Debug for Binary {
551 156 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
552 156 : f.debug_struct("Binary").finish()
553 156 : }
554 : }
555 :
556 : impl generic::Binary for Binary {
557 180 : fn as_generic(&self) -> &ffi::AbstractBinary {
558 180 : self.ptr.as_ref().unwrap().as_ref()
559 180 : }
560 :
561 0 : fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractBinary> {
562 0 : unsafe {
563 0 : Pin::new_unchecked({
564 0 : (self.ptr.as_ref().unwrap().as_ref()
565 0 : as *const ffi::AbstractBinary
566 0 : as *mut ffi::AbstractBinary).as_mut().unwrap()
567 0 : })
568 0 : }
569 0 : }
570 : }
571 :
572 372 : declare_iterator!(
573 372 : DebugEntries,
574 372 : debug::Entries<'a>,
575 372 : ffi::PE_Debug,
576 372 : ffi::PE_Binary,
577 372 : ffi::PE_Binary_it_debug
578 372 : );
579 :
580 :
581 295860 : declare_iterator!(
582 295860 : COFFStrings,
583 295860 : coff::String<'a>,
584 295860 : ffi::PE_COFFString,
585 295860 : ffi::PE_Binary,
586 295860 : ffi::PE_Binary_it_strings_table
587 295860 : );
588 :
589 366204 : declare_iterator!(
590 366204 : Symbols,
591 366204 : Symbol<'a>,
592 366204 : ffi::PE_Symbol,
593 366204 : ffi::PE_Binary,
594 366204 : ffi::PE_Binary_it_symbols
595 366204 : );
596 :
597 925308 : declare_iterator!(
598 925308 : Exceptions,
599 925308 : RuntimeExceptionFunction<'a>,
600 925308 : ffi::PE_ExceptionInfo,
601 925308 : ffi::PE_Binary,
602 925308 : ffi::PE_Binary_it_exceptions
603 925308 : );
|