feat: 增加从内存解析PE的功能

This commit is contained in:
2024-12-18 21:32:13 +08:00
parent cb2c6f3630
commit e68f3fd3db
9 changed files with 209 additions and 50 deletions

View File

@@ -2,6 +2,8 @@ use super::{
error::{MutablePEError, PEParseError},
header::*,
};
use crate::align_to;
use crate::constants::*;
use std::{
mem::{self},
ops::{Deref, DerefMut},
@@ -22,14 +24,14 @@ pub trait ReadOnlyPE: Deref<Target = [u8]> + Sized + AsRef<[u8]> {
fn is_64_bit(&self) -> Result<bool, PEParseError> {
// 先以32位加载可选头通过可选头的Magic字段判断
let optional_header: &ImageOptionalHeader32 = self.get_optional_header_32()?;
let is_64_bit = optional_header.magic == 0x20b;
let is_64_bit = optional_header.magic == OPTIONAL_MAGIC_32;
Ok(is_64_bit)
}
/// 获取数据目录
fn get_data_directories(&self) -> Result<&[ImageDataDirectory], PEParseError> {
// 1. 获取数据目录偏移
let data_directories_offset = self.get_data_directories_offset()?;
// 2. 解析数据目录
let data_directories = unsafe {
@@ -115,8 +117,7 @@ pub trait ReadOnlyPE: Deref<Target = [u8]> + Sized + AsRef<[u8]> {
ImageNTHeader::NTHeader32(nt_header) => nt_header.optional_header.section_alignment,
ImageNTHeader::NTHeader64(nt_header) => nt_header.optional_header.section_alignment,
};
let aligned_size = (size + section_alignment - 1) & !(section_alignment - 1);
Ok(aligned_size)
Ok(align_to!(size, section_alignment))
}
/// 将size与文件对齐值进行对齐返回对齐后的值
@@ -127,11 +128,11 @@ pub trait ReadOnlyPE: Deref<Target = [u8]> + Sized + AsRef<[u8]> {
ImageNTHeader::NTHeader32(nt_header) => nt_header.optional_header.file_alignment,
ImageNTHeader::NTHeader64(nt_header) => nt_header.optional_header.file_alignment,
};
let aligned_size = (size + file_alignment - 1) & !(file_alignment - 1);
Ok(aligned_size)
Ok(align_to!(size, file_alignment))
}
/// Get the DOS header without verifying its contents.
/// 获取DOS头
/// 此方法不会验证DOS头的合法性它仅从0偏移处获取DOS头
fn get_dos_header(&self) -> Result<&ImageDosHeader, PEParseError> {
let result = self.get_ref::<ImageDosHeader>(0)?;
Ok(result)
@@ -159,14 +160,14 @@ pub trait ReadOnlyPE: Deref<Target = [u8]> + Sized + AsRef<[u8]> {
Ok(result)
}
// 获取nt头的偏移
/// 获取nt头的偏移
fn get_nt_headers_offset(&self) -> Result<usize, PEParseError> {
let dos_header = self.get_dos_header()?;
let nt_offset = dos_header.e_lfanew.0 as usize;
let nt_offset = dos_header.e_lfanew as usize;
Ok(nt_offset)
}
// 获取文件头的偏移
/// 获取文件头的偏移
fn get_file_header_offset(&self) -> Result<usize, PEParseError> {
// 1. 获取nt头偏移
let nt_offset = self.get_nt_headers_offset()?;
@@ -175,20 +176,20 @@ pub trait ReadOnlyPE: Deref<Target = [u8]> + Sized + AsRef<[u8]> {
Ok(file_header_offset)
}
// 获取文件头数据
/// 获取文件头数据
fn get_file_header(&self) -> Result<&ImageFileHeader, PEParseError> {
let file_header_offset = self.get_file_header_offset()?;
let result = self.get_ref::<ImageFileHeader>(file_header_offset)?;
Ok(result)
}
// 获取节区数量
/// 获取节区数量
fn get_number_of_sections(&self) -> Result<usize, PEParseError> {
let file_header = self.get_file_header()?;
Ok(file_header.number_of_sections as usize)
}
// 获取可选头大小
/// 获取可选头大小
fn get_size_of_optional_header(&self) -> Result<usize, PEParseError> {
let file_header = self.get_file_header()?;
Ok(file_header.size_of_optional_header as usize)
@@ -201,7 +202,7 @@ pub trait ReadOnlyPE: Deref<Target = [u8]> + Sized + AsRef<[u8]> {
Ok(result)
}
// 作为64位的可选头解析
/// 作为64位的可选头解析
fn get_optional_header_64(&self) -> Result<&ImageOptionalHeader64, PEParseError> {
let file_header_offset = self.get_file_header_offset()?;
let optional_header_offset = file_header_offset + std::mem::size_of::<ImageFileHeader>();
@@ -225,16 +226,16 @@ pub trait ReadOnlyPE: Deref<Target = [u8]> + Sized + AsRef<[u8]> {
}
/// 获取节区头的偏移
/// 算法:节区头偏移 = 可选头偏移 + 可选头大小
fn get_section_headers_offset(&self) -> Result<usize, PEParseError> {
// 节区头偏移在可选头之后,可选头大小是可变的,所以需要计算
let optional_header_size = self.get_size_of_optional_header()?;
let file_header_offset = self.get_file_header_offset()?;
let section_header_offset =
file_header_offset + std::mem::size_of::<ImageFileHeader>() + optional_header_size;
let optional_header_offset = self.get_optional_header_offset()?;
let section_header_offset = optional_header_offset + optional_header_size;
Ok(section_header_offset)
}
// 获取所有节区头数据
/// 获取所有节区头数据
fn get_section_headers(&self) -> Result<&[ImageSectionHeader], PEParseError> {
// 1. 获取节区数量
let number_of_sections = self.get_number_of_sections()?;
@@ -299,9 +300,8 @@ pub trait ReadOnlyPE: Deref<Target = [u8]> + Sized + AsRef<[u8]> {
Ok(export_table)
}
/// 获取导出函数的RVA地址类似于GetProcAddress
fn get_export_function_rva(&self, proc_name: ProcName) -> Result<Option<u32>, PEParseError>{
fn get_export_function_rva(&self, proc_name: ProcName) -> Result<Option<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)?;
@@ -311,7 +311,7 @@ pub trait ReadOnlyPE: Deref<Target = [u8]> + Sized + AsRef<[u8]> {
// 名称指针表的FOA
let names_table_foa = self.rva_to_foa(export_table.address_of_names)?;
match proc_name{
match proc_name {
ProcName::Named(proc_name_str) => {
// 遍历名称表
for index in 0..number_of_names {
@@ -328,12 +328,16 @@ pub trait ReadOnlyPE: Deref<Target = [u8]> + Sized + AsRef<[u8]> {
// 比较
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 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 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(Some(rva));
}
@@ -347,13 +351,35 @@ pub trait ReadOnlyPE: Deref<Target = [u8]> + Sized + AsRef<[u8]> {
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 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(Some(rva));
}
}
Ok(None)
}
/// 以传入的RVA为开始偏移从中解析导入表
fn parse_import_tables(&self, rva: u32) -> Result<&[ImageImportDescriptor], PEParseError> {
let foa = self.rva_to_foa(rva)?;
let mut current_foa = foa;
let mut numbers = 0;
loop {
let import_table = self.get_ref::<ImageImportDescriptor>(current_foa as usize)?;
if import_table.original_first_thunk == 0 {
break;
}
numbers += 1;
current_foa += std::mem::size_of::<ImageImportDescriptor>() as u32;
}
let result_tables = unsafe {
let ptr = self.as_ptr().wrapping_offset(foa as isize) as *const ImageImportDescriptor;
let result = std::slice::from_raw_parts(ptr, numbers);
result
};
Ok(result_tables)
}
}
/// 可修改的PE trait
pub trait MutablePE: ReadOnlyPE + DerefMut<Target = [u8]> + AsMut<[u8]> {