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"
|
object = "0.36.7"
|
||||||
thiserror = "2.0.9"
|
thiserror = "2.0.9"
|
||||||
|
|
||||||
[build]
|
|
||||||
target = "i686-pc-windows-msvc"
|
|
||||||
|
|
||||||
[dependencies.windows]
|
[dependencies.windows]
|
||||||
version = "0.58.0"
|
version = "0.58.0"
|
||||||
features=[
|
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),
|
ReadCStringError(#[from] std::str::Utf8Error),
|
||||||
#[error("LoadLibraryA错误!, {0}")]
|
#[error("LoadLibraryA错误!, {0}")]
|
||||||
LoadLibraryError(#[from] WindowsError),
|
LoadLibraryError(#[from] WindowsError),
|
||||||
|
#[error("GetProcAddress错误!, {0}")]
|
||||||
|
GetProcAddressError(String),
|
||||||
}
|
}
|
155
src/lib.rs
155
src/lib.rs
@ -12,7 +12,10 @@ use std::{
|
|||||||
};
|
};
|
||||||
use windows::{
|
use windows::{
|
||||||
core::PCSTR,
|
core::PCSTR,
|
||||||
Win32::{Foundation::CloseHandle, System::LibraryLoader::LoadLibraryA},
|
Win32::{
|
||||||
|
Foundation::CloseHandle,
|
||||||
|
System::LibraryLoader::{GetProcAddress, LoadLibraryA},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
mod help;
|
mod help;
|
||||||
@ -98,59 +101,149 @@ pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEErr
|
|||||||
}
|
}
|
||||||
// 修复IAT表
|
// 修复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);
|
return Err(LoadPEError::ExecutableWithoutImportTable);
|
||||||
}
|
}
|
||||||
let import_table = import_table.unwrap();
|
let base_import_table_rva = import_directory.unwrap().virtual_address.get(LittleEndian);
|
||||||
|
let mut import_table_index = 0;
|
||||||
// 1. 加载模块
|
loop {
|
||||||
let descriptors = import_table.descriptors().unwrap();
|
let descriptor = unsafe {
|
||||||
for descriptor_result in descriptors {
|
&*(buf.add(base_import_table_rva as usize)
|
||||||
// 当descriptor 是Ok(null)的时候表示结束
|
as *const object::pe::ImageImportDescriptor)
|
||||||
let descriptor = descriptor_result?;
|
.add(import_table_index)
|
||||||
if descriptor.is_null() {
|
};
|
||||||
|
if descriptor.original_first_thunk.get(LittleEndian) == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let module_name_rva = descriptor.name.get(LittleEndian);
|
let module_name_rva = descriptor.name.get(LittleEndian);
|
||||||
let p_module_name = unsafe {
|
let p_module_name = unsafe {
|
||||||
// 从data[module_name_rva..]中读取一个c风格字符串
|
// buf[module_name_rva..]中读取一个c风格字符串
|
||||||
data.as_ptr().add(module_name_rva as usize) as *const u8
|
buf.add(module_name_rva as usize) as *const u8
|
||||||
};
|
};
|
||||||
|
|
||||||
// 使用LoadLibraryA加载模块
|
// 使用LoadLibraryA加载模块
|
||||||
let h_module = unsafe {
|
let h_module = unsafe {
|
||||||
LoadLibraryA(PCSTR(p_module_name))
|
LoadLibraryA(PCSTR::from_raw(p_module_name))
|
||||||
.map_err(|err| LoadPEError::LoadLibraryError(err))?
|
.map_err(|err| LoadPEError::LoadLibraryError(err))?
|
||||||
};
|
};
|
||||||
|
dbg!(h_module);
|
||||||
if h_module.is_invalid() {
|
if h_module.is_invalid() {
|
||||||
// 这个逻辑应该走不到
|
// 这个逻辑应该走不到
|
||||||
unimplemented!("LoadLibraryA failed");
|
unimplemented!("LoadLibraryA failed");
|
||||||
}
|
}
|
||||||
// TODO: 遍历IAT表,修复IAT表
|
// 遍历IAT表,修复IAT表
|
||||||
// 加载每一个方法。使用GetProcAddress,获取地址。
|
// 加载每一个方法。使用GetProcAddress,获取地址。
|
||||||
// 然后修复IAT表。如果其中一个环节出现问题,我们应该:释放所有加载的Module,然后返回错误
|
// 然后修复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 base_import_address_table_va = descriptor.first_thunk.get(LittleEndian);
|
||||||
|
let mut index = 0;
|
||||||
|
loop {
|
||||||
let original_first_thunk = descriptor.original_first_thunk.get(LittleEndian);
|
// 1. 从文件的数据中取出一个ImageThunkData
|
||||||
if original_first_thunk == 0 {
|
let origin_thunk_data = unsafe {
|
||||||
|
#[cfg(target_arch = "x86")]
|
||||||
}else {
|
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