From 6ffc10abe981b3e7cb1f9330224aee500f9f4e82 Mon Sep 17 00:00:00 2001 From: asahi <381848900@qq.com> Date: Fri, 27 Dec 2024 12:04:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E8=8A=82=E5=8C=BA?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E6=81=A2=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/errors.rs | 3 +- src/lib.rs | 164 ++++++++++++++++++++++++++++++++++++++++--------- tests/Test.exe | Bin 0 -> 1024 bytes 3 files changed, 137 insertions(+), 30 deletions(-) create mode 100644 tests/Test.exe diff --git a/src/errors.rs b/src/errors.rs index 9730505..279dbcc 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -26,5 +26,6 @@ pub enum LoadPEError { NoRelocationTable, #[error(transparent)] LayoutError(#[from] LayoutError), - + #[error("更改内存属性失败!")] + ChangeMemoryProtectFailed, } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index d3def0c..e13b53a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,20 +1,24 @@ -use core::alloc; use errors::LoadPEError; use object::{ - bytes_of, bytes_of_slice, endian, - pe::{IMAGE_DIRECTORY_ENTRY_BASERELOC, IMAGE_DIRECTORY_ENTRY_IMPORT}, - read::pe::{self, ImageOptionalHeader, PeFile32, PeFile64}, - LittleEndian, Object, ObjectSection, Pod, + endian, + pe::{ + IMAGE_DIRECTORY_ENTRY_BASERELOC, IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_SCN_MEM_EXECUTE, + IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE, + }, + read::pe::{self, ImageOptionalHeader, PeFile32}, + LittleEndian, Object, }; use std::{ - alloc::{alloc, Layout}, - fs, + alloc::{alloc, Layout}, arch::asm, fs }; use windows::{ core::PCSTR, - Win32::{ - Foundation::CloseHandle, - System::LibraryLoader::{GetProcAddress, LoadLibraryA}, + Win32::System::{ + LibraryLoader::{GetProcAddress, LoadLibraryA}, + Memory::{ + VirtualProtect, PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, + PAGE_PROTECTION_FLAGS, PAGE_READONLY, PAGE_READWRITE, + }, }, }; pub mod errors; @@ -25,7 +29,7 @@ mod help; /// /// /// -pub fn load_exe(exe_path: &str, args: Option>) -> Result<(), LoadPEError> { +pub fn load_exe(exe_path: &str, _args: Option>) -> Result<(), LoadPEError> { // 1. 检查文件是否存在 if !fs::metadata(exe_path).is_ok() { return Err(LoadPEError::FileNotFound(exe_path.to_string())); @@ -183,7 +187,7 @@ pub fn load_exe(exe_path: &str, args: Option>) -> Result<(), LoadPEErr #[cfg(target_arch = "x86_64")] let is_ordinal = origin_thunk_data_value & 0x8000000000000000 != 0; // 函数地址指针 - let mut function_address: *const u8 = std::ptr::null(); + let function_address; if is_ordinal { // 如果最高位是1,0-15位是序号 let ordinal = origin_thunk_data_value as u16; @@ -241,7 +245,7 @@ pub fn load_exe(exe_path: &str, args: Option>) -> Result<(), LoadPEErr import_table_index += 1; } } - // TODO: 修复重定向表 + // 修复重定向表 { // 1. 获取重定向表的数据目录 let relocation_table_directory = file.data_directory(IMAGE_DIRECTORY_ENTRY_BASERELOC); @@ -285,6 +289,15 @@ pub fn load_exe(exe_path: &str, args: Option>) -> Result<(), LoadPEErr let r_offset = type_offset & 0x0FFF; // 需要修复的地址偏移 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!( "r_type: {:?}, r_offset: {:?}, offset_va: {:?}, virtual_address: {:?}", r_type, @@ -292,26 +305,44 @@ pub fn load_exe(exe_path: &str, args: Option>) -> Result<(), LoadPEErr offset_va, virtual_address ); - match r_type { - 0 => { - // 如果r_type是0,表示这个TypeOffset是一个IMAGE_REL_BASED_ABSOLUTE - // 这个时候不需要做任何操作 + 0 => {} + 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 => { // 如果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; + let new_address = address_value + buf as u32; unsafe { *p_address = new_address; } - dbg!("修复一个32位地址: {:?} -> {:?}", address, new_address); + dbg!("修复一个32位地址: {:?} -> {:?}", address_value, new_address); } 10 => { - // 需要实现64位的重定位 - unimplemented!("未实现的重定位类型: {:?}", r_type); + // IMAGE_REL_BASED_DIR64 基址重定位将差值添加到偏移的 64 位字段。 + 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>) -> Result<(), LoadPEErr {} // 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(()) } diff --git a/tests/Test.exe b/tests/Test.exe new file mode 100644 index 0000000000000000000000000000000000000000..d2601315ddf9363a8916f4d377af53ad30ed9dab GIT binary patch literal 1024 zcmeZ`n!v!!z`(!)#Q*;@Fzf)*Am9Kd@e>Dt(tPr}_!zcuo>knz=yO&vBqOs}p`a)~ zy(lqPAvrNGFTX?~DOI7UG*2NjPr=1MSRpq*B~_1?mrDg|bndG1Lz<^0C&KXZD_j$` zzER|3`{T) z1_l)YARB}gKw=IMHc%eqZx{y2faQVWYn2(G+JTxt`alGjhEpIx1|Oi94VXn`0%09i zgY`;MD@tH8Aa{ZM3c^T0fq@|biHnsv1L~(OP}(CkCnsMaJijO>MUlbOFtIq7fgy__ zLsr0nAwvL2WHG$p2O0#VK$aao^Iw$#DEeQO14wp2%>Y@n48#WF2}ojxfNTyVK1dx5 zpt~cH(X}G8B%mliIkmW$!P_;+&(+7+NG~NPhk;=(qc2b}F+J5OzrvBBv^cd0CId5V IlqNO=09jUEaR2}S literal 0 HcmV?d00001