feat: 实现了节表导入和IAT的修复
This commit is contained in:
parent
cbd1b5b6a5
commit
aabbc73ee5
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[build]
|
||||
target = "i686-pc-windows-msvc"
|
9
.vscode/launch.json
vendored
Normal file
9
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
// 使用 IntelliSense 了解相关属性。
|
||||
// 悬停以查看现有属性的描述。
|
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{}
|
||||
]
|
||||
}
|
@ -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=[
|
||||
|
18
src/bin/main.rs
Normal file
18
src/bin/main.rs
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -18,4 +18,6 @@ pub enum LoadPEError {
|
||||
ReadCStringError(#[from] std::str::Utf8Error),
|
||||
#[error("LoadLibraryA错误!, {0}")]
|
||||
LoadLibraryError(#[from] WindowsError),
|
||||
#[error("GetProcAddress错误!, {0}")]
|
||||
GetProcAddressError(String),
|
||||
}
|
155
src/lib.rs
155
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<Vec<&str>>) -> 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!("未实现")
|
||||
}
|
||||
|
BIN
tests/Test.exe
Normal file
BIN
tests/Test.exe
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user