// ============================== // PE stuff // ============================== use core::ops::Range; use crate::upcast::Upcast; #[repr(C)] pub struct ImageDOSHeader { pub e_magic: u16, pub e_cblp: u16, pub e_cp: u16, pub e_crlc: u16, pub e_cparhdr: u16, pub e_minalloc: u16, pub e_maxalloc: u16, pub e_ss: u16, pub e_sp: u16, pub e_csum: u16, pub e_ip: u16, pub e_cs: u16, pub e_lfarlc: u16, pub e_ovno: u16, pub e_res: [u16;4], pub e_oemid: u16, pub e_oeminfo: u16, pub e_res2: [u16;10], pub e_lfanew: u32, } #[repr(C)] pub struct ImageNTHeaders64 { pub signature: u32, pub file_header: ImageFileHeader, pub optional_header: ImageOptionalHeader64, } #[repr(C)] pub struct ImageFileHeader { pub machine: u16, pub number_of_sections: u16, pub timestamp: u32, pub pointer_to_symbol_table: u32, pub number_of_symbols: u32, pub size_of_optional_header: u16, pub characteristics: u16, } #[repr(C)] pub struct ImageOptionalHeader64 { pub magic: u16, pub major_linker_version: u8, pub minor_linker_version: u8, pub size_of_code: u32, pub size_of_initialized_data: u32, pub size_of_uninitialized_data: u32, pub address_of_entry_point: u32, pub base_of_code: u32, pub image_base: u64, pub section_alignment: u32, pub file_alignment: u32, pub major_operating_system_version: u16, pub minor_operating_system_version: u16, pub major_image_version: u16, pub minor_image_version: u16, pub major_subsystem_version: u16, pub minor_subsystem_version: u16, pub win32_version_value: u32, pub size_of_image: u32, pub size_of_headers: u32, pub checksum: u32, pub subsystem: u16, pub dll_characteristics: u16, pub size_of_stack_reserve: u64, pub size_of_stack_commit: u64, pub size_of_heap_reserve: u64, pub size_of_heap_commit: u64, pub loader_flags: u32, pub number_of_rva_and_sizes: u32, pub data_directory: [ImageDataDirectory; ImageBase::NUMBEROF_DIRECTORY_ENTRIES] } #[repr(C)] pub struct ImageDataDirectory { pub virtual_address: u32, pub size: u32, } #[repr(C)] pub struct ImageSectionHeader { pub name: [u8;8], pub virtual_size: u32, pub virtual_address: u32, pub size_of_raw_data: u32, pub pointer_to_raw_data: u32, pub pointer_to_relocations: u32, pub pointer_to_linenumbers: u32, pub number_of_relocations: u16, pub number_of_linenumbers: u16, pub characteristics: u32, } #[repr(C)] pub struct ImageImportDescriptor { pub original_first_thunk: u32, pub timestamp: u32, pub forwarder_chain: u32, pub name: u32, pub first_thunk: u32, } #[repr(C)] pub struct ImageBoundImportDescriptor { pub timestamp: u32, pub offset_module_name: u16, pub number_of_module_forwarder_refs: u16, } #[repr(C)] pub struct ImageImportByName { pub hint: u16, pub name: [u8] } #[repr(C)] pub struct ImageBaseRelocation { pub virtual_address: u32, pub size_of_block: u32, } #[repr(C)] pub struct ImageExportDirectory { pub export_flags: u32, pub timestamp: u32, pub major_version: u16, pub minor_version: u16, pub name_rva: u32, pub ordinal_base: u32, pub address_table_entries: u32, pub number_of_name_pointers: u32, pub export_address_table_rva: u32, pub name_pointer_rva: u32, pub ordinal_table_rva: u32, } #[repr(C)] pub struct ImageExportAddressEntry { pub export_rva: u32, pub forwarder_rva: u32, } #[repr(C)] pub struct ImageBase(()); impl ImageDataDirectory { pub fn contains(&self, offset: u32) -> bool { // offset - self.virtual_address < self.size offset.overflowing_sub(self.virtual_address).0 < self.size } } impl ImageBase { pub const PE_SIGNATURE: u32 = 0x00004550; pub const DOS_MAGIC: u16 = 0x5A4D; pub const IOH_MAGIC_PE32: u16 = 0x10B; // 32 bit executable pub const IOH_MAGIC_PE64: u16 = 0x20B; // 64 bit executable pub const IOH_MAGIC_ROM: u16 = 0x107; // Yes! pub const NUMBEROF_DIRECTORY_ENTRIES: usize = 16; pub const DIRECTORY_ENTRY_EXPORT: usize = 0x0; // Export Directory pub const DIRECTORY_ENTRY_IMPORT: usize = 0x1; // Import Directory pub const DIRECTORY_ENTRY_RESOURCE: usize = 0x2; // Resource Directory pub const DIRECTORY_ENTRY_EXCEPTION: usize = 0x3; // Exception Directory pub const DIRECTORY_ENTRY_SECURITY: usize = 0x4; // Security Directory pub const DIRECTORY_ENTRY_BASERELOC: usize = 0x5; // Base Relocation Table pub const DIRECTORY_ENTRY_DEBUG: usize = 0x6; // Debug Directory pub const DIRECTORY_ENTRY_ARCHITECTURE: usize = 0x7; // Architecture Specific Data pub const DIRECTORY_ENTRY_GLOBALPTR: usize = 0x8; // RVA of GP pub const DIRECTORY_ENTRY_TLS: usize = 0x9; // TLS Directory pub const DIRECTORY_ENTRY_LOAD_CONFIG: usize = 0xA; // Load Configuration Directory pub const DIRECTORY_ENTRY_BOUND_IMPORT: usize = 0xB; // Bound Import Directory in headers pub const DIRECTORY_ENTRY_IAT: usize = 0xC; // Import Address Table pub const DIRECTORY_ENTRY_DELAY_IMPORT: usize = 0xD; // Delay Load Import Descriptors pub const DIRECTORY_ENTRY_COM_DESCRIPTOR: usize = 0xE; // COM Runtime descriptor pub const IMAGE_FILE_MACHINE_I386: u16 = 0x014c; pub const IMAGE_FILE_MACHINE_IA64: u16 = 0x0200; pub const IMAGE_FILE_MACHINE_AMD64: u16 = 0x8664; #[inline(always)] pub fn as_ptr(&self) -> usize { self as *const _ as usize } #[inline(always)] fn offset>(&self, offset: T) -> *const u8 { unsafe { (self as *const _ as *const u8).add(offset.upcast()) } } pub unsafe fn dos(&self) -> &ImageDOSHeader { &*(self as *const _ as *const ImageDOSHeader) } pub unsafe fn dos_mut(&mut self) -> &mut ImageDOSHeader { &mut *(self as *mut _ as *mut ImageDOSHeader) } pub unsafe fn nt_header(&self) -> &'static ImageNTHeaders64 { &*(self.offset(self.dos().e_lfanew) as *const ImageNTHeaders64) } pub unsafe fn nt_header_mut(&mut self) -> &'static mut ImageNTHeaders64 { &mut *(self.offset(self.dos().e_lfanew) as *mut ImageNTHeaders64) } pub unsafe fn sections(&self) -> &[ImageSectionHeader] { self.nt_header().sections() } pub unsafe fn exports(&self) -> Option { let directory = &self.nt_header().optional_header.data_directory[ImageBase::DIRECTORY_ENTRY_EXPORT]; if directory.size == 0 || directory.virtual_address == 0 { return None; } let export_directory = &*(self.offset(directory.virtual_address) as *const ImageExportDirectory); Some(ExportIter { image: self, export_dir: export_directory, export_index: 0, }) } pub unsafe fn as_range(&self) -> Range { self.as_ptr()..self.as_ptr() + self.nt_header().optional_header.size_of_image as usize } } impl ImageNTHeaders64 { pub fn sections(&self) -> &[ImageSectionHeader] { let section_base = ( &self.optional_header as *const _ as usize ) + self.file_header.size_of_optional_header as usize; unsafe { core::slice::from_raw_parts( section_base as *const ImageSectionHeader, self.file_header.number_of_sections as usize) } } } pub struct ExportIter<'a> { image: &'a ImageBase, export_dir: &'a ImageExportDirectory, export_index: usize, } impl<'a> Iterator for ExportIter<'a> { type Item = (usize, &'static [u8]); fn next(&mut self) -> Option { match self.export_index < self.export_dir.number_of_name_pointers as usize { true => unsafe { #[inline(always)] unsafe fn u8_nul_terminated(ptr: *const u8) -> &'static [u8] { let mut end = ptr; while *end != 0 { end = end.add(1) } let len = (end as usize) - (ptr as usize); &*core::ptr::slice_from_raw_parts(ptr, len) } let export_functions = self.image.offset(self.export_dir.export_address_table_rva) as *const u32; let export_names = self.image.offset(self.export_dir.name_pointer_rva) as *const u32; let export_ordinals = self.image.offset(self.export_dir.ordinal_table_rva) as *const u16; let export_name = self.image.offset(*export_names.add(self.export_index)); let export_ordinal = *export_ordinals.add(self.export_index); let export_rva = self.image.offset(*export_functions.add(export_ordinal as usize)) as usize; self.export_index += 1; Some((export_rva, u8_nul_terminated(export_name))) } false => None, } } }