fix: 修复对指针的操作,导致修改了指针.

This commit is contained in:
asahi 2024-12-27 01:07:22 +08:00
parent aabbc73ee5
commit 989abab053
6 changed files with 132 additions and 35 deletions

View File

@ -1,10 +1,10 @@
use loadpe_rs::load_exe;
#[cfg(target_arch = "x86_64")]
const EXE_PATH: &str = r#"E:\work\逆向工程学习\PE学习\HelloWorld.exe"#;
const EXE_PATH: &str = r#"E:\work\rust\loadpe-rs\tests\Testx64.exe"#;
#[cfg(target_arch = "x86")]
const EXE_PATH: &str = r#"E:\work\rust\loadpe-rs\tests\Test.exe"#;
const EXE_PATH: &str = r#"E:\work\rust\loadpe-rs\tests\Testx32.exe"#;
fn main() {
match load_exe(EXE_PATH, None) {

View File

@ -1,3 +1,5 @@
use std::alloc::LayoutError;
use thiserror::Error;
use object::Error as ObjectError;
use windows::core::Error as WindowsError;
@ -20,4 +22,9 @@ pub enum LoadPEError {
LoadLibraryError(#[from] WindowsError),
#[error("GetProcAddress错误, {0}")]
GetProcAddressError(String),
#[error("没有重定位表!")]
NoRelocationTable,
#[error(transparent)]
LayoutError(#[from] LayoutError),
}

View File

@ -2,7 +2,7 @@ use core::alloc;
use errors::LoadPEError;
use object::{
bytes_of, bytes_of_slice, endian,
pe::IMAGE_DIRECTORY_ENTRY_IMPORT,
pe::{IMAGE_DIRECTORY_ENTRY_BASERELOC, IMAGE_DIRECTORY_ENTRY_IMPORT},
read::pe::{self, ImageOptionalHeader, PeFile32, PeFile64},
LittleEndian, Object, ObjectSection, Pod,
};
@ -46,10 +46,14 @@ pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEErr
// 3. 为镜像分配内存
// 分配的内存,后续需要修改内存属性
//
let buf = unsafe { alloc(Layout::for_value(&image_size)) };
let layout = Layout::from_size_align(image_size as usize, 1)?;
let buf = unsafe { alloc(layout) };
if buf.is_null() {
return Err(LoadPEError::MemoryAllocFailed);
}
dbg!("分配的内存地址: {:?}", buf);
// 进行数据的拷贝。
{
// 拷贝整个头部
@ -91,12 +95,17 @@ pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEErr
// 从data[pointer_to_raw_data..pointer_to_raw_data + size_of_raw_data]中拷贝数据到buf[va..va + size_of_raw_data]
let section_data = &data
[pointer_to_raw_data as usize..(pointer_to_raw_data + size_of_raw_data) as usize];
dbg!(
"拷贝节区数据: va: {:?}, size_of_raw_data: {:?}, pointer_to_raw_data: {:?}, section_data.len: {:?}",
va, size_of_raw_data, pointer_to_raw_data, section_data.len()
);
unsafe {
std::ptr::copy_nonoverlapping(
section_data.as_ptr(),
buf.add(va as usize),
size_of_raw_data as usize,
);
let dst = (buf as usize + va as usize) as *mut u8;
dbg!("dst: {:p}", dst);
std::ptr::copy(section_data.as_ptr(), dst, size_of_raw_data as usize);
};
}
// 修复IAT表
@ -110,18 +119,17 @@ pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEErr
let mut import_table_index = 0;
loop {
let descriptor = unsafe {
&*(buf.add(base_import_table_rva as usize)
&*((buf as usize
+ base_import_table_rva as usize
+ import_table_index
* std::mem::size_of::<object::pe::ImageImportDescriptor>())
as *const object::pe::ImageImportDescriptor)
.add(import_table_index)
};
if descriptor.original_first_thunk.get(LittleEndian) == 0 {
break;
}
let module_name_rva = descriptor.name.get(LittleEndian);
let p_module_name = unsafe {
// buf[module_name_rva..]中读取一个c风格字符串
buf.add(module_name_rva as usize) as *const u8
};
let p_module_name = (buf as usize + module_name_rva as usize) as *const u8;
// 使用LoadLibraryA加载模块
let h_module = unsafe {
@ -151,13 +159,17 @@ pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEErr
// 1. 从文件的数据中取出一个ImageThunkData
let origin_thunk_data = unsafe {
#[cfg(target_arch = "x86")]
let thunk_data = &*(buf.add(base_original_first_thunk_va as usize)
as *const object::pe::ImageThunkData32)
.add(index);
let thunk_data = &*((buf as usize
+ base_original_first_thunk_va as usize
+ index * std::mem::size_of::<object::pe::ImageThunkData32>())
as *const object::pe::ImageThunkData32);
#[cfg(target_arch = "x86_64")]
let thunk_data = &*(buf.add(base_original_first_thunk_va as usize)
as *const object::pe::ImageThunkData64)
.add(index);
let thunk_data = &*((buf as usize
+ base_original_first_thunk_va as usize
+ index * std::mem::size_of::<object::pe::ImageThunkData64>())
as *const object::pe::ImageThunkData64);
thunk_data
};
// 2. 判断是否是最后一个ImageThunkData
@ -190,7 +202,7 @@ pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEErr
// 否则是名称表的RVA
let name_table_rva = origin_thunk_data_value;
let p_function_name =
unsafe { buf.add(name_table_rva as usize + 2) as *const u8 };
(buf as usize + name_table_rva as usize + 2) as *const u8;
// 构造一个PSTR
let p_function_name = PCSTR(p_function_name);
// 使用GetProcAddress获取函数地址
@ -206,8 +218,11 @@ pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEErr
}
// 修复IAT表
// 需要获取到IAT表的地址
let iat_address =
unsafe { buf.add(base_import_address_table_va as usize + 4 * index) };
let iat_address = (buf as usize
+ base_import_address_table_va as usize
+ std::mem::size_of::<u32>() * index)
as *mut u8;
// 修复IAT表
// 将函数地址写入IAT表 如果是x86_64需要写入8字节
// 如果是x86需要写入4字节
@ -223,26 +238,101 @@ pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEErr
}
index += 1;
}
import_table_index += 1;
import_table_index += 1;
}
}
// TODO: 修复重定向表
{
// 1. 获取重定向表的数据目录
let relocation_table_directory = file.data_directory(IMAGE_DIRECTORY_ENTRY_BASERELOC);
if relocation_table_directory.is_none() {
// TODO: 如果没有重定位表,应该要把这个错误返回出去
return Err(LoadPEError::NoRelocationTable);
}
let base_relocation_table_rva = relocation_table_directory
.unwrap()
.virtual_address
.get(LittleEndian);
let mut relocation_offset = 0;
loop {
// 读取一个IMAGE_BASE_RELOCATION
let relocation = unsafe {
&*((buf as usize + base_relocation_table_rva as usize + relocation_offset)
as *const object::pe::ImageBaseRelocation)
};
// 如果SizeOfBlock为0表示已经到了最后一个IMAGE_BASE_RELOCATION
if relocation.size_of_block.get(LittleEndian) == 0 {
break;
}
// 获取重定位表的VirtualAddress和SizeOfBlock
let virtual_address = relocation.virtual_address.get(LittleEndian);
let size_of_block = relocation.size_of_block.get(LittleEndian);
let base_block = base_relocation_table_rva as usize + relocation_offset + 8;
let block_num = (size_of_block - 8) / 2;
for i in 0..block_num {
// 读取一个TypeOffset
let type_offset = unsafe {
&*((buf as usize
+ base_block as usize
+ i as usize * std::mem::size_of::<u16>())
as *mut u16)
};
// 高四位
let r_type = (type_offset >> 12) as u8;
// 剩余12位
let r_offset = type_offset & 0x0FFF;
// 需要修复的地址偏移
let offset_va = virtual_address + r_offset as u32;
dbg!(
"r_type: {:?}, r_offset: {:?}, offset_va: {:?}, virtual_address: {:?}",
r_type,
r_offset,
offset_va,
virtual_address
);
match r_type {
0 => {
// 如果r_type是0表示这个TypeOffset是一个IMAGE_REL_BASED_ABSOLUTE
// 这个时候不需要做任何操作
}
3 => {
// 如果r_type是3表示这个TypeOffset是一个IMAGE_REL_BASED_HIGHLOW
// 这个时候需要修复一个32位的地址
let p_address = (buf as usize + offset_va as usize) as *mut u32;
let address = unsafe { *p_address };
let new_address = address + buf as u32;
unsafe {
*p_address = new_address;
}
dbg!("修复一个32位地址: {:?} -> {:?}", address, new_address);
}
10 => {
// 需要实现64位的重定位
unimplemented!("未实现的重定位类型: {:?}", r_type);
}
_ => {
// 其他的类型,暂时不支持
unimplemented!("未实现的重定位类型: {:?}", r_type);
}
}
}
// 计算下一个IMAGE_BASE_RELOCATION的偏移
relocation_offset += size_of_block as usize;
}
}
// TODO: 修复TLS表
{
}
{}
// TODO: 修复资源表
{
}
{}
// TODO: 修复命令行参数
{
}
{}
// TODO: 设置节区属性
{}
// TODO: 跳转到入口点
{}
}
todo!("未实现")

Binary file not shown.

BIN
tests/Testx32.exe Normal file

Binary file not shown.

BIN
tests/Testx64.exe Normal file

Binary file not shown.