diff --git a/src/bin/main.rs b/src/bin/main.rs index 885cf5a..6778e54 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -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) { diff --git a/src/errors.rs b/src/errors.rs index 8d7abee..9730505 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -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), + } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 871a328..d3def0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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>) -> 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>) -> 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>) -> 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::()) 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>) -> 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::()) + 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::()) + as *const object::pe::ImageThunkData64); + thunk_data }; // 2. 判断是否是最后一个ImageThunkData @@ -190,7 +202,7 @@ pub fn load_exe(exe_path: &str, args: Option>) -> 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>) -> 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::() * index) + as *mut u8; + // 修复IAT表 // 将函数地址写入IAT表 如果是x86_64,需要写入8字节 // 如果是x86,需要写入4字节 @@ -223,26 +238,101 @@ pub fn load_exe(exe_path: &str, args: Option>) -> 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::()) + 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!("未实现") diff --git a/tests/Test.exe b/tests/Test.exe deleted file mode 100644 index d260131..0000000 Binary files a/tests/Test.exe and /dev/null differ diff --git a/tests/Testx32.exe b/tests/Testx32.exe new file mode 100644 index 0000000..241d9c7 Binary files /dev/null and b/tests/Testx32.exe differ diff --git a/tests/Testx64.exe b/tests/Testx64.exe new file mode 100644 index 0000000..6069fdf Binary files /dev/null and b/tests/Testx64.exe differ