From aabbc73ee54963b7e6c01aff235fd44aa30c95b5 Mon Sep 17 00:00:00 2001 From: asahi <381848900@qq.com> Date: Thu, 26 Dec 2024 21:07:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E4=BA=86=E8=8A=82?= =?UTF-8?q?=E8=A1=A8=E5=AF=BC=E5=85=A5=E5=92=8CIAT=E7=9A=84=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cargo/config.toml | 2 + .vscode/launch.json | 9 +++ Cargo.toml | 3 - src/bin/main.rs | 18 +++++ src/errors.rs | 2 + src/lib.rs | 155 +++++++++++++++++++++++++++++++++++--------- tests/Test.exe | Bin 0 -> 1024 bytes 7 files changed, 155 insertions(+), 34 deletions(-) create mode 100644 .cargo/config.toml create mode 100644 .vscode/launch.json create mode 100644 src/bin/main.rs create mode 100644 tests/Test.exe diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..9380186 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "i686-pc-windows-msvc" diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..d6a58ec --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,9 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + {} + ] +} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 8323f99..c959459 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,9 +7,6 @@ edition = "2021" object = "0.36.7" thiserror = "2.0.9" -[build] -target = "i686-pc-windows-msvc" - [dependencies.windows] version = "0.58.0" features=[ diff --git a/src/bin/main.rs b/src/bin/main.rs new file mode 100644 index 0000000..885cf5a --- /dev/null +++ b/src/bin/main.rs @@ -0,0 +1,18 @@ +use loadpe_rs::load_exe; + +#[cfg(target_arch = "x86_64")] +const EXE_PATH: &str = r#"E:\work\逆向工程学习\PE学习\HelloWorld.exe"#; + +#[cfg(target_arch = "x86")] +const EXE_PATH: &str = r#"E:\work\rust\loadpe-rs\tests\Test.exe"#; + +fn main() { + match load_exe(EXE_PATH, None) { + Ok(_) => { + println!("Load exe success!"); + } + Err(e) => { + eprintln!("Load exe failed: {}", e); + } + } +} \ No newline at end of file diff --git a/src/errors.rs b/src/errors.rs index 67d49c0..8d7abee 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -18,4 +18,6 @@ pub enum LoadPEError { ReadCStringError(#[from] std::str::Utf8Error), #[error("LoadLibraryA错误!, {0}")] LoadLibraryError(#[from] WindowsError), + #[error("GetProcAddress错误!, {0}")] + GetProcAddressError(String), } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 6fca590..871a328 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,10 @@ use std::{ }; use windows::{ core::PCSTR, - Win32::{Foundation::CloseHandle, System::LibraryLoader::LoadLibraryA}, + Win32::{ + Foundation::CloseHandle, + System::LibraryLoader::{GetProcAddress, LoadLibraryA}, + }, }; pub mod errors; mod help; @@ -98,59 +101,149 @@ pub fn load_exe(exe_path: &str, args: Option>) -> Result<(), LoadPEErr } // 修复IAT表 { - let import_table = file.import_table()?; - if import_table.is_none() { + // 获取导入表的数据目录 + let import_directory = file.data_directory(IMAGE_DIRECTORY_ENTRY_IMPORT); + if import_directory.is_none() { return Err(LoadPEError::ExecutableWithoutImportTable); } - let import_table = import_table.unwrap(); - - // 1. 加载模块 - let descriptors = import_table.descriptors().unwrap(); - for descriptor_result in descriptors { - // 当descriptor 是Ok(null)的时候表示结束 - let descriptor = descriptor_result?; - if descriptor.is_null() { + let base_import_table_rva = import_directory.unwrap().virtual_address.get(LittleEndian); + let mut import_table_index = 0; + loop { + let descriptor = unsafe { + &*(buf.add(base_import_table_rva as usize) + 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 { - // 从data[module_name_rva..]中读取一个c风格字符串 - data.as_ptr().add(module_name_rva as usize) as *const u8 + // buf[module_name_rva..]中读取一个c风格字符串 + buf.add(module_name_rva as usize) as *const u8 }; // 使用LoadLibraryA加载模块 let h_module = unsafe { - LoadLibraryA(PCSTR(p_module_name)) + LoadLibraryA(PCSTR::from_raw(p_module_name)) .map_err(|err| LoadPEError::LoadLibraryError(err))? }; + dbg!(h_module); if h_module.is_invalid() { // 这个逻辑应该走不到 unimplemented!("LoadLibraryA failed"); } - // TODO: 遍历IAT表,修复IAT表 + // 遍历IAT表,修复IAT表 // 加载每一个方法。使用GetProcAddress,获取地址。 // 然后修复IAT表。如果其中一个环节出现问题,我们应该:释放所有加载的Module,然后返回错误 + // 获取Image_thunk_data数组的首地址 + let base_original_first_thunk_va = + if descriptor.original_first_thunk.get(LittleEndian) != 0 { + descriptor.original_first_thunk.get(LittleEndian) + } else { + // 如果OriginalFirstThunk不存在,则使用FirstThunk 的值 + descriptor.first_thunk.get(LittleEndian) + }; - // 如果OriginalFirstThunk不存在,则使用FirstThunk 的值 - - - let original_first_thunk = descriptor.original_first_thunk.get(LittleEndian); - if original_first_thunk == 0 { - - }else { - - - - + let base_import_address_table_va = descriptor.first_thunk.get(LittleEndian); + let mut index = 0; + loop { + // 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); + #[cfg(target_arch = "x86_64")] + let thunk_data = &*(buf.add(base_original_first_thunk_va as usize) + as *const object::pe::ImageThunkData64) + .add(index); + thunk_data + }; + // 2. 判断是否是最后一个ImageThunkData + let origin_thunk_data_value = origin_thunk_data.0.get(LittleEndian) as u64; + if origin_thunk_data_value == 0 { + break; + } + // 如果不是最后一个,现判断是序号,还是函数名 + #[cfg(target_arch = "x86")] + let is_ordinal = origin_thunk_data_value & 0x80000000 != 0; + #[cfg(target_arch = "x86_64")] + let is_ordinal = origin_thunk_data_value & 0x8000000000000000 != 0; + // 函数地址指针 + let mut function_address: *const u8 = std::ptr::null(); + if is_ordinal { + // 如果最高位是1,0-15位是序号 + let ordinal = origin_thunk_data_value as u16; + let pstr = PCSTR(ordinal as *const u8); + // 使用GetProcAddress获取函数地址 + let p_function = unsafe { GetProcAddress(h_module, pstr) }; + if p_function.is_none() { + // 如果函数地址是null,表示获取失败 + return Err(LoadPEError::GetProcAddressError(format!( + "GetProcAddress failed, ordinal: {:?}", + ordinal + ))); + } + function_address = p_function.unwrap() as *const u8; + } else { + // 否则是名称表的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 }; + // 构造一个PSTR + let p_function_name = PCSTR(p_function_name); + // 使用GetProcAddress获取函数地址 + let p_function = unsafe { GetProcAddress(h_module, p_function_name) }; + if p_function.is_none() { + // 如果函数地址是null,表示获取失败 + return Err(LoadPEError::GetProcAddressError(format!( + "GetProcAddress failed, function name: {:?}", + p_function_name + ))); + } + function_address = p_function.unwrap() as *const u8; + } + // 修复IAT表 + // 需要获取到IAT表的地址 + let iat_address = + unsafe { buf.add(base_import_address_table_va as usize + 4 * index) }; + // 修复IAT表 + // 将函数地址写入IAT表 如果是x86_64,需要写入8字节 + // 如果是x86,需要写入4字节 + unsafe { + #[cfg(target_arch = "x86")] + { + *(iat_address as *mut u32) = function_address as u32; + } + #[cfg(target_arch = "x86_64")] + { + *(iat_address as *mut u64) = function_address as u64; + } + } + index += 1; } - - - - + import_table_index += 1; } } + // TODO: 修复重定向表 + { + + } + // TODO: 修复TLS表 + { + + } + // TODO: 修复资源表 + { + + } + // TODO: 修复命令行参数 + { + + } } - todo!() + todo!("未实现") } 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