From 836215526028adeb22e293b28913aa95e498a68a Mon Sep 17 00:00:00 2001 From: "381848900@qq.com" Date: Thu, 26 Dec 2024 15:38:47 +0800 Subject: [PATCH] init: first --- .gitignore | 1 + Cargo.lock | 277 ++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 18 ++++ src/errors.rs | 21 ++++ src/help.rs | 7 ++ src/lib.rs | 156 ++++++++++++++++++++++++++++ tests/test.rs | 3 + 7 files changed, 483 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/errors.rs create mode 100644 src/help.rs create mode 100644 src/lib.rs create mode 100644 tests/test.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..8aa8a30 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,277 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "flate2" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "loadpe-rs" +version = "0.1.0" +dependencies = [ + "object", + "thiserror", + "windows", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miniz_oxide" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +dependencies = [ + "adler2", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "flate2", + "memchr", + "ruzstd", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ruzstd" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad02996bfc73da3e301efe90b1837be9ed8f4a462b6ed410aa35d00381de89f" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "2.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core", + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..8323f99 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "loadpe-rs" +version = "0.1.0" +edition = "2021" + +[dependencies] +object = "0.36.7" +thiserror = "2.0.9" + +[build] +target = "i686-pc-windows-msvc" + +[dependencies.windows] +version = "0.58.0" +features=[ + "Win32_System_Memory", + "Win32_System_LibraryLoader" +] \ No newline at end of file diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..67d49c0 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,21 @@ +use thiserror::Error; +use object::Error as ObjectError; +use windows::core::Error as WindowsError; +#[derive(Error, Debug)] +pub enum LoadPEError { + #[error("文件不存在: {0}")] + FileNotFound(String), + #[error("文件读取失败: {0}")] + FileReadError(#[from] std::io::Error), + #[error("文件解析失败: {0}")] + ParseError(#[from] ObjectError), + #[error("内存分配失败")] + MemoryAllocFailed, + + #[error("可执行程序没有包含导入表!")] + ExecutableWithoutImportTable, + #[error("读取一个C风格字符串错误, {0}")] + ReadCStringError(#[from] std::str::Utf8Error), + #[error("LoadLibraryA错误!, {0}")] + LoadLibraryError(#[from] WindowsError), +} \ No newline at end of file diff --git a/src/help.rs b/src/help.rs new file mode 100644 index 0000000..728a72a --- /dev/null +++ b/src/help.rs @@ -0,0 +1,7 @@ +#[macro_export] +/// 将一个数对齐到另一个数的倍数 +macro_rules! align_to{ + ($a:expr, $b:expr) => { + ($a + $b - 1) & !($b - 1) + }; +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..6fca590 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,156 @@ +use core::alloc; +use errors::LoadPEError; +use object::{ + bytes_of, bytes_of_slice, endian, + pe::IMAGE_DIRECTORY_ENTRY_IMPORT, + read::pe::{self, ImageOptionalHeader, PeFile32, PeFile64}, + LittleEndian, Object, ObjectSection, Pod, +}; +use std::{ + alloc::{alloc, Layout}, + fs, +}; +use windows::{ + core::PCSTR, + Win32::{Foundation::CloseHandle, System::LibraryLoader::LoadLibraryA}, +}; +pub mod errors; +mod help; + +/// 加载并启动一个exe文件,需要支持命令行参数 +/// +/// +/// +/// +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())); + } + // 2. 如果文件存在,加载文件 + let data = fs::read(exe_path)?; + #[cfg(target_arch = "x86")] + let file: PeFile32 = pe::PeFile::parse(&data[..])?; + #[cfg(target_arch = "x86_64")] + let file: PeFile64 = pe::PeFile::parse(&data[..])?; + + // 获取镜像大小 + let image_size = file + .nt_headers() + .optional_header + .size_of_image + .get(endian::LittleEndian); + // 3. 为镜像分配内存 + // 分配的内存,后续需要修改内存属性 + // + let buf = unsafe { alloc(Layout::for_value(&image_size)) }; + if buf.is_null() { + return Err(LoadPEError::MemoryAllocFailed); + } + // 进行数据的拷贝。 + { + // 拷贝整个头部 + let head_size = file + .nt_headers() + .optional_header + .size_of_headers + .get(endian::LittleEndian); + let head_data = &data[..head_size as usize]; + unsafe { + std::ptr::copy_nonoverlapping(head_data.as_ptr(), buf, head_size as usize); + } + } + { + // 分块拷贝节区数据 + + let section_alignment = file.nt_headers().optional_header.section_alignment(); + let file_alignment = file.nt_headers().optional_header.file_alignment(); + for section in file.sections() { + // 如果节区没有映射到内存中,那么就不需要拷贝 + if section.pe_section().size_of_raw_data.get(LittleEndian) == 0 { + continue; + } + // VA对齐值 + let va = align_to!( + section.pe_section().virtual_address.get(LittleEndian), + section_alignment + ); + // pointer_to_raw_data对齐值 + let pointer_to_raw_data = align_to!( + section.pe_section().pointer_to_raw_data.get(LittleEndian), + file_alignment + ); + // size_of_raw_data对齐值 + let size_of_raw_data = align_to!( + section.pe_section().size_of_raw_data.get(LittleEndian), + file_alignment + ); + // 从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]; + unsafe { + std::ptr::copy_nonoverlapping( + section_data.as_ptr(), + buf.add(va as usize), + size_of_raw_data as usize, + ); + }; + } + // 修复IAT表 + { + let import_table = file.import_table()?; + if import_table.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() { + 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 + }; + + // 使用LoadLibraryA加载模块 + let h_module = unsafe { + LoadLibraryA(PCSTR(p_module_name)) + .map_err(|err| LoadPEError::LoadLibraryError(err))? + }; + if h_module.is_invalid() { + // 这个逻辑应该走不到 + unimplemented!("LoadLibraryA failed"); + } + // TODO: 遍历IAT表,修复IAT表 + // 加载每一个方法。使用GetProcAddress,获取地址。 + // 然后修复IAT表。如果其中一个环节出现问题,我们应该:释放所有加载的Module,然后返回错误 + + // 如果OriginalFirstThunk不存在,则使用FirstThunk 的值 + + + let original_first_thunk = descriptor.original_first_thunk.get(LittleEndian); + if original_first_thunk == 0 { + + }else { + + + + + } + + + + + + } + } + } + + todo!() +} diff --git a/tests/test.rs b/tests/test.rs new file mode 100644 index 0000000..0f4718b --- /dev/null +++ b/tests/test.rs @@ -0,0 +1,3 @@ +#[cfg(test)] +mod tests { +}