feat: 增加导出表解析的功能和测试用例
This commit is contained in:
parent
f48803b3c5
commit
3e0a858318
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,3 +5,6 @@
|
||||
# Generated by Tauri
|
||||
# will have schema files for capabilities auto-completion
|
||||
/gen/schemas
|
||||
|
||||
/tests/*.dll
|
||||
/tests/*.exe
|
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -32,6 +32,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"memmap2",
|
||||
"pe_parse",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
@ -12,3 +12,6 @@ thiserror = "2.0.4"
|
||||
[features]
|
||||
default = [] # 默认不启用任何特性
|
||||
memmap2_impl = [] # 定义一个 feature,并启用第三方库
|
||||
|
||||
[dev-dependencies]
|
||||
pe_parse = { path = ".", features = ["memmap2_impl"] }
|
@ -18,6 +18,8 @@ pub enum PEParseError {
|
||||
RvaToEmptySection(u32),
|
||||
#[error("错误的数据目录索引")]
|
||||
InvalidDataDirectoryIndex,
|
||||
#[error("错误的导出函数序号: {0}")]
|
||||
ExportOrdinalNotFound(u16),
|
||||
}
|
||||
/// PE操作的错误
|
||||
#[derive(Error, Debug)]
|
||||
|
@ -451,3 +451,35 @@ bitflags! {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// 导出目录表
|
||||
#[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),
|
||||
}
|
65
src/pe.rs
65
src/pe.rs
@ -291,6 +291,71 @@ pub trait ReadOnlyPE: Deref<Target = [u8]> + 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::<ImageExportDirectoryTable>(foa as usize)?;
|
||||
Ok(export_table)
|
||||
}
|
||||
|
||||
|
||||
/// 获取导出函数的RVA地址,类似于GetProcAddress
|
||||
fn get_export_function_rva(&self, proc_name: ProcName) -> Result<u32, PEParseError>{
|
||||
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::<u32>() as u32;
|
||||
let name_rva = self.get_ref::<u32>(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::<i8>(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::<u16>() as u32;
|
||||
let ordinal = self.get_ref::<u16>(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::<u32>() as u32;
|
||||
let rva = self.get_ref::<u32>(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::<u32>() as u32;
|
||||
let rva = self.get_ref::<u32>(function_item_foa as usize)?.clone();
|
||||
return Ok(rva);
|
||||
}
|
||||
}
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
}
|
||||
/// 可修改的PE trait
|
||||
pub trait MutablePE: ReadOnlyPE + DerefMut<Target = [u8]> + AsMut<[u8]> {
|
||||
|
75
tests/test_pe.rs
Normal file
75
tests/test_pe.rs
Normal file
@ -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::<u32>() as u32;
|
||||
let rva = mmap
|
||||
.get_ref::<u32>(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::<i8>(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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user