diff --git a/.gitignore b/.gitignore index b21bd68..e85353e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ # Generated by Tauri # will have schema files for capabilities auto-completion /gen/schemas + +/tests/*.dll +/tests/*.exe \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index cc30ac0..3cd540f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,7 @@ version = "0.1.0" dependencies = [ "bitflags", "memmap2", + "pe_parse", "serde", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index d7af2f4..8d8f8cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,7 @@ thiserror = "2.0.4" [features] default = [] # 默认不启用任何特性 -memmap2_impl = [] # 定义一个 feature,并启用第三方库 \ No newline at end of file +memmap2_impl = [] # 定义一个 feature,并启用第三方库 + +[dev-dependencies] +pe_parse = { path = ".", features = ["memmap2_impl"] } \ No newline at end of file diff --git a/src/error.rs b/src/error.rs index 0cd3319..c975ae3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -18,6 +18,8 @@ pub enum PEParseError { RvaToEmptySection(u32), #[error("错误的数据目录索引")] InvalidDataDirectoryIndex, + #[error("错误的导出函数序号: {0}")] + ExportOrdinalNotFound(u16), } /// PE操作的错误 #[derive(Error, Debug)] diff --git a/src/header.rs b/src/header.rs index 6a945ee..a2753da 100644 --- a/src/header.rs +++ b/src/header.rs @@ -450,4 +450,36 @@ bitflags! { const RESERVED = 0x7FFFFFFF00000000; } +} + +/// 导出目录表 +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct ImageExportDirectoryTable { + pub characteristics: u32, + pub time_date_stamp: u32, + pub major_version: u16, + pub minor_version: u16, + pub name: u32, + pub base: u32, + pub number_of_functions: u32, + pub number_of_names: u32, + pub address_of_functions: u32, + pub address_of_names: u32, + pub address_of_name_ordinals: u32, +} + +/// 导出地址表 +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub enum ExportAddressTable { + // 导出函数的RVA + ExportFunctionRVA(u32), + // 转发函数字符串的RVA + ForwarderStringRVA(u32), +} + +pub enum ProcName { + Named(String), + Ordinal(u16), } \ No newline at end of file diff --git a/src/pe.rs b/src/pe.rs index 9a8fbff..638715d 100644 --- a/src/pe.rs +++ b/src/pe.rs @@ -291,6 +291,71 @@ pub trait ReadOnlyPE: Deref + Sized + AsRef<[u8]> { let empty_space_size = size_of_headers - last_section_header_offset as u32; Ok(empty_space_size) } + + /// 以传入的RVA为开始偏移,从中解析导出表 + fn parse_export_table(&self, rva: u32) -> Result<&ImageExportDirectoryTable, PEParseError> { + let foa = self.rva_to_foa(rva)?; + let export_table = self.get_ref::(foa as usize)?; + Ok(export_table) + } + + + /// 获取导出函数的RVA地址,类似于GetProcAddress + fn get_export_function_rva(&self, proc_name: ProcName) -> Result{ + let export_table_dir = self.get_data_directory(ImageDirectoryEntry::Export)?; + let export_table_rva = export_table_dir.virtual_address; + let export_table = self.parse_export_table(export_table_rva)?; + let base = export_table.base; // 序号基数 + let number_of_fun = export_table.number_of_functions; + let number_of_names = export_table.number_of_names; + // 名称指针表的FOA + let names_table_foa = self.rva_to_foa(export_table.address_of_names)?; + + match proc_name{ + ProcName::Named(proc_name_str) => { + // 遍历名称表 + for index in 0..number_of_names { + let name_item_foa = names_table_foa + index * std::mem::size_of::() as u32; + let name_rva = self.get_ref::(name_item_foa as usize)?.clone(); + let name_foa = self.rva_to_foa(name_rva)?; + let name = unsafe { + std::ffi::CStr::from_ptr( + self.get_ref::(name_foa as usize)? as *const i8 + ) + .to_str() + .unwrap() + }; + // 比较 + if name == proc_name_str { + // 找到了这个函数 那么需要找到这个函数的序号 + let ordinals_table_foa = self.rva_to_foa(export_table.address_of_name_ordinals)?; + let ordinal_item_foa = ordinals_table_foa + index * std::mem::size_of::() as u32; + let ordinal = self.get_ref::(ordinal_item_foa as usize)?.clone(); + // 找到了序号 那么就可以找到函数地址 + let functions_table_foa = self.rva_to_foa(export_table.address_of_functions)?; + let function_item_foa = functions_table_foa + ordinal as u32 * std::mem::size_of::() as u32; + let rva = self.get_ref::(function_item_foa as usize)?.clone(); + return Ok(rva); + } + } + } + ProcName::Ordinal(order) => { + // 通过序号查找 + // 序号就在序号表的第order - base的下标位置 + let find_ordinal = order as u32 - base; + if find_ordinal >= number_of_fun { + return Err(PEParseError::ExportOrdinalNotFound(order)); + } + let functions_table_foa = self.rva_to_foa(export_table.address_of_functions)?; + let function_item_foa = functions_table_foa + find_ordinal * std::mem::size_of::() as u32; + let rva = self.get_ref::(function_item_foa as usize)?.clone(); + return Ok(rva); + } + } + + todo!() + } + } /// 可修改的PE trait pub trait MutablePE: ReadOnlyPE + DerefMut + AsMut<[u8]> { diff --git a/tests/test_pe.rs b/tests/test_pe.rs new file mode 100644 index 0000000..ba539c7 --- /dev/null +++ b/tests/test_pe.rs @@ -0,0 +1,75 @@ +mod test { + use super::*; + use memmap2::Mmap; + use pe_parse::header::ProcName; + #[test] + fn test_header() { + println!("This is a test for the header"); + } + + /// 测试导出表的解析 + #[test] + #[cfg(feature = "memmap2_impl")] + fn test_export_table() { + use core::ffi; + + // 1. 创建映射 + use pe_parse::pe::ReadOnlyPE; + let file = std::fs::OpenOptions::new() + .read(true) + .open("tests/test_dll.dll") + .unwrap(); + let mmap = unsafe { Mmap::map(&file).unwrap() }; + // 2. 解析导出表 + let export_table_dir = mmap + .get_data_directory(pe_parse::header::ImageDirectoryEntry::Export) + .unwrap(); + + let export_table_rva = export_table_dir.virtual_address; + let export_table = mmap.parse_export_table(export_table_rva).unwrap(); + println!("{:?}", export_table); + + // 3. 遍历导出表,打印导出函数 + let number_of_fun = export_table.number_of_functions; + let functions_table_foa = mmap.rva_to_foa(export_table.address_of_functions).unwrap(); + for i in 0..number_of_fun { + let functions_item_foa = functions_table_foa + i * std::mem::size_of::() as u32; + let rva = mmap + .get_ref::(functions_item_foa as usize) + .unwrap() + .clone(); + // 如果rva在[export_table_dir.virtual_address, export_table_dir.virtual_address + export_table_dir.size]之间,则是一个内部导出 + if rva >= export_table_dir.virtual_address + && rva < export_table_dir.virtual_address + export_table_dir.size + { + // 这是一个转发 + let forward_str_foa = mmap.rva_to_foa(rva).unwrap(); + let forward_str = unsafe { + ffi::CStr::from_ptr( + mmap.get_ref::(forward_str_foa as usize).unwrap() as *const i8 + ) + .to_str() + .unwrap() + }; + println!("i: {i}, Forward: {}", forward_str); + } else { + // 这是一个内部导出 打印函数名 + println!("i: {i}, Function RVA: {:#x}", rva); + } + } + } + + #[test] + fn test_find_export_function(){ + let find_function_str = ProcName::Named("test_def_add".to_string()); + // 1. 还是先映射 + use pe_parse::pe::ReadOnlyPE; + let file = std::fs::OpenOptions::new() + .read(true) + .open("tests/test_dll.dll") + .unwrap(); + let mmap = unsafe { Mmap::map(&file).unwrap() }; + let result_rva = mmap.get_export_function_rva(find_function_str).unwrap(); + println!("Find Function RVA: {:#x}", result_rva); + } +}