feat: 增加节区属性恢复
This commit is contained in:
parent
989abab053
commit
6ffc10abe9
@ -26,5 +26,6 @@ pub enum LoadPEError {
|
|||||||
NoRelocationTable,
|
NoRelocationTable,
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
LayoutError(#[from] LayoutError),
|
LayoutError(#[from] LayoutError),
|
||||||
|
#[error("更改内存属性失败!")]
|
||||||
|
ChangeMemoryProtectFailed,
|
||||||
}
|
}
|
162
src/lib.rs
162
src/lib.rs
@ -1,20 +1,24 @@
|
|||||||
use core::alloc;
|
|
||||||
use errors::LoadPEError;
|
use errors::LoadPEError;
|
||||||
use object::{
|
use object::{
|
||||||
bytes_of, bytes_of_slice, endian,
|
endian,
|
||||||
pe::{IMAGE_DIRECTORY_ENTRY_BASERELOC, IMAGE_DIRECTORY_ENTRY_IMPORT},
|
pe::{
|
||||||
read::pe::{self, ImageOptionalHeader, PeFile32, PeFile64},
|
IMAGE_DIRECTORY_ENTRY_BASERELOC, IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_SCN_MEM_EXECUTE,
|
||||||
LittleEndian, Object, ObjectSection, Pod,
|
IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE,
|
||||||
|
},
|
||||||
|
read::pe::{self, ImageOptionalHeader, PeFile32},
|
||||||
|
LittleEndian, Object,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
alloc::{alloc, Layout},
|
alloc::{alloc, Layout}, arch::asm, fs
|
||||||
fs,
|
|
||||||
};
|
};
|
||||||
use windows::{
|
use windows::{
|
||||||
core::PCSTR,
|
core::PCSTR,
|
||||||
Win32::{
|
Win32::System::{
|
||||||
Foundation::CloseHandle,
|
LibraryLoader::{GetProcAddress, LoadLibraryA},
|
||||||
System::LibraryLoader::{GetProcAddress, LoadLibraryA},
|
Memory::{
|
||||||
|
VirtualProtect, PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE,
|
||||||
|
PAGE_PROTECTION_FLAGS, PAGE_READONLY, PAGE_READWRITE,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
@ -25,7 +29,7 @@ mod help;
|
|||||||
///
|
///
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEError> {
|
pub fn load_exe(exe_path: &str, _args: Option<Vec<&str>>) -> Result<(), LoadPEError> {
|
||||||
// 1. 检查文件是否存在
|
// 1. 检查文件是否存在
|
||||||
if !fs::metadata(exe_path).is_ok() {
|
if !fs::metadata(exe_path).is_ok() {
|
||||||
return Err(LoadPEError::FileNotFound(exe_path.to_string()));
|
return Err(LoadPEError::FileNotFound(exe_path.to_string()));
|
||||||
@ -183,7 +187,7 @@ pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEErr
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
let is_ordinal = origin_thunk_data_value & 0x8000000000000000 != 0;
|
let is_ordinal = origin_thunk_data_value & 0x8000000000000000 != 0;
|
||||||
// 函数地址指针
|
// 函数地址指针
|
||||||
let mut function_address: *const u8 = std::ptr::null();
|
let function_address;
|
||||||
if is_ordinal {
|
if is_ordinal {
|
||||||
// 如果最高位是1,0-15位是序号
|
// 如果最高位是1,0-15位是序号
|
||||||
let ordinal = origin_thunk_data_value as u16;
|
let ordinal = origin_thunk_data_value as u16;
|
||||||
@ -241,7 +245,7 @@ pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEErr
|
|||||||
import_table_index += 1;
|
import_table_index += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: 修复重定向表
|
// 修复重定向表
|
||||||
{
|
{
|
||||||
// 1. 获取重定向表的数据目录
|
// 1. 获取重定向表的数据目录
|
||||||
let relocation_table_directory = file.data_directory(IMAGE_DIRECTORY_ENTRY_BASERELOC);
|
let relocation_table_directory = file.data_directory(IMAGE_DIRECTORY_ENTRY_BASERELOC);
|
||||||
@ -285,6 +289,15 @@ pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEErr
|
|||||||
let r_offset = type_offset & 0x0FFF;
|
let r_offset = type_offset & 0x0FFF;
|
||||||
// 需要修复的地址偏移
|
// 需要修复的地址偏移
|
||||||
let offset_va = virtual_address + r_offset as u32;
|
let offset_va = virtual_address + r_offset as u32;
|
||||||
|
// 若要应用基址重定位,会计算首选基址与在其中实际加载映像的基址之间的差异。 如果在首选基址处加载映像,则差异为零,因此无需应用基址重定位。
|
||||||
|
let reloc_offset = buf as usize
|
||||||
|
- file
|
||||||
|
.nt_headers()
|
||||||
|
.optional_header
|
||||||
|
.image_base
|
||||||
|
.get(LittleEndian) as usize;
|
||||||
|
let p_address = (buf as usize + offset_va as usize) as *mut u32;
|
||||||
|
let address_value = unsafe { *p_address };
|
||||||
dbg!(
|
dbg!(
|
||||||
"r_type: {:?}, r_offset: {:?}, offset_va: {:?}, virtual_address: {:?}",
|
"r_type: {:?}, r_offset: {:?}, offset_va: {:?}, virtual_address: {:?}",
|
||||||
r_type,
|
r_type,
|
||||||
@ -292,26 +305,44 @@ pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEErr
|
|||||||
offset_va,
|
offset_va,
|
||||||
virtual_address
|
virtual_address
|
||||||
);
|
);
|
||||||
|
|
||||||
match r_type {
|
match r_type {
|
||||||
0 => {
|
0 => {}
|
||||||
// 如果r_type是0,表示这个TypeOffset是一个IMAGE_REL_BASED_ABSOLUTE
|
1 => {
|
||||||
// 这个时候不需要做任何操作
|
// IMAGE_REL_BASED_HIGH 基址重定位在偏移量处将差值的高 16 位添加到 16 位字段。 16 位字段表示 32 位单词的高值。
|
||||||
|
// 取reloc_offset的高16位
|
||||||
|
let high = (reloc_offset >> 16) as u16;
|
||||||
|
let new_address = address_value + high as u32;
|
||||||
|
unsafe {
|
||||||
|
*p_address = new_address;
|
||||||
|
}
|
||||||
|
dbg!("修复一个16位地址: {:?} -> {:?}", address_value, new_address);
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
// IMAGE_REL_BASED_LOW 基准重定位将差值的低 16 位加到偏移的 16 位字段。 16 位字段代表 32 位字的低半部分。
|
||||||
|
// 取reloc_offset的低16位
|
||||||
|
let low = reloc_offset as u16;
|
||||||
|
let new_address = address_value + low as u32;
|
||||||
|
unsafe {
|
||||||
|
*p_address = new_address;
|
||||||
|
}
|
||||||
|
dbg!("修复一个16位地址: {:?} -> {:?}", address_value, new_address);
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
// 如果r_type是3,表示这个TypeOffset是一个IMAGE_REL_BASED_HIGHLOW
|
// 如果r_type是3,表示这个TypeOffset是一个IMAGE_REL_BASED_HIGHLOW
|
||||||
// 这个时候需要修复一个32位的地址
|
// 这个时候需要修复一个32位的地址
|
||||||
let p_address = (buf as usize + offset_va as usize) as *mut u32;
|
let new_address = address_value + buf as u32;
|
||||||
let address = unsafe { *p_address };
|
|
||||||
let new_address = address + buf as u32;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
*p_address = new_address;
|
*p_address = new_address;
|
||||||
}
|
}
|
||||||
dbg!("修复一个32位地址: {:?} -> {:?}", address, new_address);
|
dbg!("修复一个32位地址: {:?} -> {:?}", address_value, new_address);
|
||||||
}
|
}
|
||||||
10 => {
|
10 => {
|
||||||
// 需要实现64位的重定位
|
// IMAGE_REL_BASED_DIR64 基址重定位将差值添加到偏移的 64 位字段。
|
||||||
unimplemented!("未实现的重定位类型: {:?}", r_type);
|
let new_address = address_value + reloc_offset as u32;
|
||||||
|
unsafe {
|
||||||
|
*(p_address as *mut u64) = new_address as u64;
|
||||||
|
}
|
||||||
|
dbg!("修复一个64位地址: {:?} -> {:?}", address_value, new_address);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// 其他的类型,暂时不支持
|
// 其他的类型,暂时不支持
|
||||||
@ -329,11 +360,86 @@ pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEErr
|
|||||||
{}
|
{}
|
||||||
// TODO: 修复命令行参数
|
// TODO: 修复命令行参数
|
||||||
{}
|
{}
|
||||||
// TODO: 设置节区属性
|
// 设置节区属性
|
||||||
{}
|
{
|
||||||
// TODO: 跳转到入口点
|
let section_alignment = file.nt_headers().optional_header.section_alignment();
|
||||||
{}
|
// 遍历节区,设置节区属性
|
||||||
|
for section in file.sections() {
|
||||||
|
let va = section.pe_section().virtual_address.get(LittleEndian);
|
||||||
|
let size_of_raw_data = section.pe_section().size_of_raw_data.get(LittleEndian);
|
||||||
|
let characteristics = section.pe_section().characteristics.get(LittleEndian);
|
||||||
|
let section_va = buf as usize + va as usize;
|
||||||
|
let section_size = align_to!(size_of_raw_data, section_alignment);
|
||||||
|
if section_size == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 设置节区属性
|
||||||
|
let protect;
|
||||||
|
if characteristics & IMAGE_SCN_MEM_EXECUTE != 0
|
||||||
|
&& characteristics & IMAGE_SCN_MEM_READ == 0
|
||||||
|
&& characteristics & IMAGE_SCN_MEM_WRITE == 0
|
||||||
|
{
|
||||||
|
protect = PAGE_EXECUTE.0;
|
||||||
|
} else if characteristics & IMAGE_SCN_MEM_EXECUTE != 0
|
||||||
|
&& characteristics & IMAGE_SCN_MEM_READ != 0
|
||||||
|
&& characteristics & IMAGE_SCN_MEM_WRITE == 0
|
||||||
|
{
|
||||||
|
protect = PAGE_EXECUTE_READ.0;
|
||||||
|
} else if characteristics & IMAGE_SCN_MEM_EXECUTE != 0
|
||||||
|
&& characteristics & IMAGE_SCN_MEM_READ != 0
|
||||||
|
&& characteristics & IMAGE_SCN_MEM_WRITE != 0
|
||||||
|
{
|
||||||
|
protect = PAGE_EXECUTE_READWRITE.0;
|
||||||
|
} else if characteristics & IMAGE_SCN_MEM_EXECUTE == 0
|
||||||
|
&& characteristics & IMAGE_SCN_MEM_READ != 0
|
||||||
|
&& characteristics & IMAGE_SCN_MEM_WRITE == 0
|
||||||
|
{
|
||||||
|
protect = PAGE_READONLY.0;
|
||||||
|
} else if characteristics & IMAGE_SCN_MEM_EXECUTE == 0
|
||||||
|
&& characteristics & IMAGE_SCN_MEM_READ != 0
|
||||||
|
&& characteristics & IMAGE_SCN_MEM_WRITE != 0
|
||||||
|
{
|
||||||
|
protect = PAGE_READWRITE.0;
|
||||||
|
} else {
|
||||||
|
return Err(LoadPEError::ChangeMemoryProtectFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
todo!("未实现")
|
// 设置属性
|
||||||
|
let mut old_protect = PAGE_PROTECTION_FLAGS(0);
|
||||||
|
|
||||||
|
dbg!(
|
||||||
|
"设置节区属性: va: {:?}, size: {:?}, protect: {:?}",
|
||||||
|
section_va,
|
||||||
|
section_size,
|
||||||
|
protect
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = unsafe {
|
||||||
|
VirtualProtect(
|
||||||
|
section_va as *mut _,
|
||||||
|
section_size as usize,
|
||||||
|
PAGE_PROTECTION_FLAGS(protect),
|
||||||
|
&mut old_protect,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if result.is_err() {
|
||||||
|
dbg!("设置节区属性失败: {:?}", result.unwrap_err());
|
||||||
|
return Err(LoadPEError::ChangeMemoryProtectFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let entry_point = file
|
||||||
|
.nt_headers()
|
||||||
|
.optional_header
|
||||||
|
.address_of_entry_point
|
||||||
|
.get(LittleEndian);
|
||||||
|
let entry_point = buf as usize + entry_point as usize;
|
||||||
|
let entry_point: extern "system" fn() = unsafe { std::mem::transmute(entry_point) };
|
||||||
|
dbg!("entry_point: {:p}", entry_point);
|
||||||
|
|
||||||
|
entry_point();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
BIN
tests/Test.exe
Normal file
BIN
tests/Test.exe
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user