feat: 增加导出表解析的功能和测试用例
This commit is contained in:
parent
f48803b3c5
commit
3e0a858318
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,3 +5,6 @@
|
|||||||
# Generated by Tauri
|
# Generated by Tauri
|
||||||
# will have schema files for capabilities auto-completion
|
# will have schema files for capabilities auto-completion
|
||||||
/gen/schemas
|
/gen/schemas
|
||||||
|
|
||||||
|
/tests/*.dll
|
||||||
|
/tests/*.exe
|
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -32,6 +32,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
|
"pe_parse",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
@ -11,4 +11,7 @@ thiserror = "2.0.4"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [] # 默认不启用任何特性
|
default = [] # 默认不启用任何特性
|
||||||
memmap2_impl = [] # 定义一个 feature,并启用第三方库
|
memmap2_impl = [] # 定义一个 feature,并启用第三方库
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
pe_parse = { path = ".", features = ["memmap2_impl"] }
|
@ -18,6 +18,8 @@ pub enum PEParseError {
|
|||||||
RvaToEmptySection(u32),
|
RvaToEmptySection(u32),
|
||||||
#[error("错误的数据目录索引")]
|
#[error("错误的数据目录索引")]
|
||||||
InvalidDataDirectoryIndex,
|
InvalidDataDirectoryIndex,
|
||||||
|
#[error("错误的导出函数序号: {0}")]
|
||||||
|
ExportOrdinalNotFound(u16),
|
||||||
}
|
}
|
||||||
/// PE操作的错误
|
/// PE操作的错误
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
|
@ -450,4 +450,36 @@ bitflags! {
|
|||||||
const RESERVED = 0x7FFFFFFF00000000;
|
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),
|
||||||
}
|
}
|
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;
|
let empty_space_size = size_of_headers - last_section_header_offset as u32;
|
||||||
Ok(empty_space_size)
|
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
|
/// 可修改的PE trait
|
||||||
pub trait MutablePE: ReadOnlyPE + DerefMut<Target = [u8]> + AsMut<[u8]> {
|
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