init: first

This commit is contained in:
381848900@qq.com 2024-12-26 15:38:47 +08:00
commit 8362155260
7 changed files with 483 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

277
Cargo.lock generated Normal file
View File

@ -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"

18
Cargo.toml Normal file
View File

@ -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"
]

21
src/errors.rs Normal file
View File

@ -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),
}

7
src/help.rs Normal file
View File

@ -0,0 +1,7 @@
#[macro_export]
/// 将一个数对齐到另一个数的倍数
macro_rules! align_to{
($a:expr, $b:expr) => {
($a + $b - 1) & !($b - 1)
};
}

156
src/lib.rs Normal file
View File

@ -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<Vec<&str>>) -> 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!()
}

3
tests/test.rs Normal file
View File

@ -0,0 +1,3 @@
#[cfg(test)]
mod tests {
}