Compare commits
No commits in common. "dev" and "master" have entirely different histories.
@ -1,2 +0,0 @@
|
|||||||
[build]
|
|
||||||
target = "i686-pc-windows-msvc"
|
|
9
.vscode/launch.json
vendored
9
.vscode/launch.json
vendored
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
// 使用 IntelliSense 了解相关属性。
|
|
||||||
// 悬停以查看现有属性的描述。
|
|
||||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{}
|
|
||||||
]
|
|
||||||
}
|
|
44
Cargo.lock
generated
44
Cargo.lock
generated
@ -23,12 +23,6 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "equivalent"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.35"
|
version = "1.0.35"
|
||||||
@ -39,50 +33,15 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foldhash"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.15.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
|
||||||
dependencies = [
|
|
||||||
"foldhash",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indexmap"
|
|
||||||
version = "2.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
|
||||||
dependencies = [
|
|
||||||
"equivalent",
|
|
||||||
"hashbrown",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "loadpe-rs"
|
name = "loadpe-rs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lz4_flex",
|
|
||||||
"object",
|
"object",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"windows",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lz4_flex"
|
|
||||||
version = "0.11.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5"
|
|
||||||
dependencies = [
|
|
||||||
"twox-hash",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
@ -104,10 +63,7 @@ version = "0.36.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crc32fast",
|
|
||||||
"flate2",
|
"flate2",
|
||||||
"hashbrown",
|
|
||||||
"indexmap",
|
|
||||||
"memchr",
|
"memchr",
|
||||||
"ruzstd",
|
"ruzstd",
|
||||||
]
|
]
|
||||||
|
@ -4,13 +4,15 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lz4_flex = "0.11.3"
|
object = "0.36.7"
|
||||||
object = {version= "0.36.7", features=["default", "write"]}
|
|
||||||
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=[
|
||||||
"Win32_System_Memory",
|
"Win32_System_Memory",
|
||||||
"Win32_System_LibraryLoader"
|
"Win32_System_LibraryLoader"
|
||||||
]
|
]
|
@ -4,10 +4,4 @@
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
git remote add origin ssh://git@81.70.52.148:17022/asahi/loadpe-rs.git
|
git remote add origin ssh://git@81.70.52.148:17022/asahi/loadpe-rs.git
|
||||||
```
|
```
|
||||||
|
|
||||||
如果使用rust进行壳的开发:
|
|
||||||
- 压缩程序并生成PE
|
|
||||||
- 编写shellcode,shellcode依赖:
|
|
||||||
- 解压缩API
|
|
||||||
- kernel32.dll中的API
|
|
@ -1,18 +0,0 @@
|
|||||||
use loadpe_rs::load_exe;
|
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
const EXE_PATH: &str = r#"E:\work\rust\loadpe-rs\tests\Testx64.exe"#;
|
|
||||||
|
|
||||||
#[cfg(target_arch = "x86")]
|
|
||||||
const EXE_PATH: &str = r#"E:\work\rust\loadpe-rs\tests\Testx32R.exe"#;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
match load_exe(EXE_PATH, None) {
|
|
||||||
Ok(_) => {
|
|
||||||
println!("Load exe success!");
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Load exe failed: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +1,5 @@
|
|||||||
use std::alloc::LayoutError;
|
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use object::Error as ObjectError;
|
use object::Error as ObjectError;
|
||||||
use object::write::Error as ObjectWriteError;
|
|
||||||
use windows::core::Error as WindowsError;
|
use windows::core::Error as WindowsError;
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum LoadPEError {
|
pub enum LoadPEError {
|
||||||
@ -21,14 +18,4 @@ 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),
|
|
||||||
#[error("没有重定位表!")]
|
|
||||||
NoRelocationTable,
|
|
||||||
#[error(transparent)]
|
|
||||||
LayoutError(#[from] LayoutError),
|
|
||||||
#[error("更改内存属性失败!")]
|
|
||||||
ChangeMemoryProtectFailed,
|
|
||||||
#[error("写入PE文件失败!")]
|
|
||||||
WritePEError(#[from] ObjectWriteError),
|
|
||||||
}
|
}
|
420
src/lib.rs
420
src/lib.rs
@ -1,37 +1,28 @@
|
|||||||
|
use core::alloc;
|
||||||
use errors::LoadPEError;
|
use errors::LoadPEError;
|
||||||
|
|
||||||
use lz4_flex::block::compress_prepend_size;
|
|
||||||
use object::{
|
use object::{
|
||||||
endian,
|
bytes_of, bytes_of_slice, endian,
|
||||||
pe::{
|
pe::IMAGE_DIRECTORY_ENTRY_IMPORT,
|
||||||
IMAGE_DIRECTORY_ENTRY_BASERELOC, IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_SCN_MEM_EXECUTE,
|
read::pe::{self, ImageOptionalHeader, PeFile32, PeFile64},
|
||||||
IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE,
|
LittleEndian, Object, ObjectSection, Pod,
|
||||||
},
|
|
||||||
read::pe::{self, ImageOptionalHeader, PeFile32},
|
|
||||||
write::pe::Writer,
|
|
||||||
LittleEndian, Object, ObjectSection, SectionIndex, U16Bytes,
|
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
alloc::{alloc, Layout},
|
alloc::{alloc, Layout},
|
||||||
fs,
|
fs,
|
||||||
};
|
};
|
||||||
use types::CompressPeInfo;
|
|
||||||
use windows::{
|
use windows::{
|
||||||
core::PCSTR,
|
core::PCSTR,
|
||||||
Win32::System::{
|
Win32::{Foundation::CloseHandle, System::LibraryLoader::LoadLibraryA},
|
||||||
LibraryLoader::{GetProcAddress, LoadLibraryA},
|
|
||||||
Memory::{
|
|
||||||
VirtualProtect, PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE,
|
|
||||||
PAGE_PROTECTION_FLAGS, PAGE_READONLY, PAGE_READWRITE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
mod help;
|
mod help;
|
||||||
mod types;
|
|
||||||
|
|
||||||
/// 加载并启动一个exe文件,需要支持命令行参数
|
/// 加载并启动一个exe文件,需要支持命令行参数
|
||||||
pub fn load_exe(exe_path: &str, _args: Option<Vec<&str>>) -> Result<(), LoadPEError> {
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
pub fn load_exe(exe_path: &str, args: Option<Vec<&str>>) -> Result<(), LoadPEError> {
|
||||||
// 1. 检查文件是否存在
|
// 1. 检查文件是否存在
|
||||||
if !fs::metadata(exe_path).is_ok() {
|
if !fs::metadata(exe_path).is_ok() {
|
||||||
return Err(LoadPEError::FileNotFound(exe_path.to_string()));
|
return Err(LoadPEError::FileNotFound(exe_path.to_string()));
|
||||||
@ -51,15 +42,11 @@ pub fn load_exe(exe_path: &str, _args: Option<Vec<&str>>) -> Result<(), LoadPEEr
|
|||||||
.get(endian::LittleEndian);
|
.get(endian::LittleEndian);
|
||||||
// 3. 为镜像分配内存
|
// 3. 为镜像分配内存
|
||||||
// 分配的内存,后续需要修改内存属性
|
// 分配的内存,后续需要修改内存属性
|
||||||
|
//
|
||||||
// 对齐值一定要写0x1000,否则会出现问题
|
let buf = unsafe { alloc(Layout::for_value(&image_size)) };
|
||||||
let layout = Layout::from_size_align(image_size as usize, 0x1000)?;
|
|
||||||
let buf = unsafe { alloc(layout) };
|
|
||||||
if buf.is_null() {
|
if buf.is_null() {
|
||||||
return Err(LoadPEError::MemoryAllocFailed);
|
return Err(LoadPEError::MemoryAllocFailed);
|
||||||
}
|
}
|
||||||
dbg!("分配的内存地址: {:?}", buf);
|
|
||||||
|
|
||||||
// 进行数据的拷贝。
|
// 进行数据的拷贝。
|
||||||
{
|
{
|
||||||
// 拷贝整个头部
|
// 拷贝整个头部
|
||||||
@ -101,381 +88,68 @@ pub fn load_exe(exe_path: &str, _args: Option<Vec<&str>>) -> Result<(), LoadPEEr
|
|||||||
// 从data[pointer_to_raw_data..pointer_to_raw_data + size_of_raw_data]中拷贝数据到buf[va..va + size_of_raw_data]
|
// 从data[pointer_to_raw_data..pointer_to_raw_data + size_of_raw_data]中拷贝数据到buf[va..va + size_of_raw_data]
|
||||||
let section_data = &data
|
let section_data = &data
|
||||||
[pointer_to_raw_data as usize..(pointer_to_raw_data + size_of_raw_data) as usize];
|
[pointer_to_raw_data as usize..(pointer_to_raw_data + size_of_raw_data) as usize];
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let dst = (buf as usize + va as usize) as *mut u8;
|
std::ptr::copy_nonoverlapping(
|
||||||
std::ptr::copy(section_data.as_ptr(), dst, size_of_raw_data as usize);
|
section_data.as_ptr(),
|
||||||
|
buf.add(va as usize),
|
||||||
|
size_of_raw_data as usize,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// 修复IAT表
|
// 修复IAT表
|
||||||
{
|
{
|
||||||
// 获取导入表的数据目录
|
let import_table = file.import_table()?;
|
||||||
let import_directory = file.data_directory(IMAGE_DIRECTORY_ENTRY_IMPORT);
|
if import_table.is_none() {
|
||||||
if import_directory.is_none() {
|
|
||||||
return Err(LoadPEError::ExecutableWithoutImportTable);
|
return Err(LoadPEError::ExecutableWithoutImportTable);
|
||||||
}
|
}
|
||||||
let base_import_table_rva = import_directory.unwrap().virtual_address.get(LittleEndian);
|
let import_table = import_table.unwrap();
|
||||||
let mut import_table_index = 0;
|
|
||||||
loop {
|
// 1. 加载模块
|
||||||
let descriptor = unsafe {
|
let descriptors = import_table.descriptors().unwrap();
|
||||||
&*((buf as usize
|
for descriptor_result in descriptors {
|
||||||
+ base_import_table_rva as usize
|
// 当descriptor 是Ok(null)的时候表示结束
|
||||||
+ import_table_index
|
let descriptor = descriptor_result?;
|
||||||
* std::mem::size_of::<object::pe::ImageImportDescriptor>())
|
if descriptor.is_null() {
|
||||||
as *const object::pe::ImageImportDescriptor)
|
|
||||||
};
|
|
||||||
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 = (buf as usize + module_name_rva as usize) as *const u8;
|
let p_module_name = unsafe {
|
||||||
|
// 从data[module_name_rva..]中读取一个c风格字符串
|
||||||
|
data.as_ptr().add(module_name_rva as usize) as *const u8
|
||||||
|
};
|
||||||
|
|
||||||
// 使用LoadLibraryA加载模块
|
// 使用LoadLibraryA加载模块
|
||||||
let h_module = unsafe {
|
let h_module = unsafe {
|
||||||
LoadLibraryA(PCSTR::from_raw(p_module_name))
|
LoadLibraryA(PCSTR(p_module_name))
|
||||||
.map_err(|err| LoadPEError::LoadLibraryError(err))?
|
.map_err(|err| LoadPEError::LoadLibraryError(err))?
|
||||||
};
|
};
|
||||||
if h_module.is_invalid() {
|
if h_module.is_invalid() {
|
||||||
// 这个逻辑应该走不到
|
// 这个逻辑应该走不到
|
||||||
unimplemented!("LoadLibraryA failed");
|
unimplemented!("LoadLibraryA failed");
|
||||||
}
|
}
|
||||||
// 遍历IAT表,修复IAT表
|
// TODO: 遍历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)
|
|
||||||
};
|
|
||||||
|
|
||||||
let base_import_address_table_va = descriptor.first_thunk.get(LittleEndian);
|
// 如果OriginalFirstThunk不存在,则使用FirstThunk 的值
|
||||||
let mut index = 0;
|
|
||||||
loop {
|
|
||||||
// 1. 从文件的数据中取出一个ImageThunkData
|
let original_first_thunk = descriptor.original_first_thunk.get(LittleEndian);
|
||||||
let origin_thunk_data = unsafe {
|
if original_first_thunk == 0 {
|
||||||
#[cfg(target_arch = "x86")]
|
|
||||||
let thunk_data = &*((buf as usize
|
}else {
|
||||||
+ base_original_first_thunk_va as usize
|
|
||||||
+ index * std::mem::size_of::<object::pe::ImageThunkData32>())
|
|
||||||
as *const object::pe::ImageThunkData32);
|
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
let thunk_data = &*((buf as usize
|
|
||||||
+ base_original_first_thunk_va as usize
|
|
||||||
+ index * std::mem::size_of::<object::pe::ImageThunkData64>())
|
|
||||||
as *const object::pe::ImageThunkData64);
|
|
||||||
|
|
||||||
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 function_address;
|
|
||||||
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 =
|
|
||||||
(buf as usize + 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 = (buf as usize
|
|
||||||
+ base_import_address_table_va as usize
|
|
||||||
+ std::mem::size_of::<u32>() * index)
|
|
||||||
as *mut u8;
|
|
||||||
|
|
||||||
// 修复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;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 修复重定向表
|
|
||||||
{
|
|
||||||
// 1. 获取重定向表的数据目录
|
|
||||||
let relocation_table_directory = file.data_directory(IMAGE_DIRECTORY_ENTRY_BASERELOC);
|
|
||||||
if relocation_table_directory.is_none() {
|
|
||||||
return Err(LoadPEError::NoRelocationTable);
|
|
||||||
}
|
|
||||||
let base_relocation_table_rva = relocation_table_directory
|
|
||||||
.unwrap()
|
|
||||||
.virtual_address
|
|
||||||
.get(LittleEndian);
|
|
||||||
|
|
||||||
let mut relocation_offset = 0;
|
|
||||||
let image_base = file
|
|
||||||
.nt_headers()
|
|
||||||
.optional_header
|
|
||||||
.image_base
|
|
||||||
.get(LittleEndian);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
// 读取一个IMAGE_BASE_RELOCATION
|
|
||||||
let relocation = unsafe {
|
|
||||||
&*((buf as usize + base_relocation_table_rva as usize + relocation_offset)
|
|
||||||
as *const object::pe::ImageBaseRelocation)
|
|
||||||
};
|
|
||||||
// 如果SizeOfBlock为0,表示已经到了最后一个IMAGE_BASE_RELOCATION
|
|
||||||
if relocation.size_of_block.get(LittleEndian) == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// 获取重定位表的VirtualAddress和SizeOfBlock
|
|
||||||
let virtual_address = relocation.virtual_address.get(LittleEndian);
|
|
||||||
let size_of_block = relocation.size_of_block.get(LittleEndian);
|
|
||||||
let base_block = base_relocation_table_rva as usize + relocation_offset + 8;
|
|
||||||
let block_num = (size_of_block - 8) / 2;
|
|
||||||
|
|
||||||
for i in 0..block_num {
|
|
||||||
// 读取一个TypeOffset
|
|
||||||
let type_offset = unsafe {
|
|
||||||
&*((buf as usize
|
|
||||||
+ base_block as usize
|
|
||||||
+ i as usize * std::mem::size_of::<u16>())
|
|
||||||
as *mut u16)
|
|
||||||
};
|
|
||||||
// 高四位
|
|
||||||
let r_type = (type_offset >> 12) as u8;
|
|
||||||
// 剩余12位
|
|
||||||
let r_offset = type_offset & 0x0FFF;
|
|
||||||
// 需要修复的地址偏移
|
|
||||||
let offset_va = virtual_address + r_offset as u32;
|
|
||||||
// 若要应用基址重定位,会计算首选基址与在其中实际加载映像的基址之间的差异。 如果在首选基址处加载映像,则差异为零,因此无需应用基址重定位。
|
|
||||||
// 修复后的值: 按类型
|
|
||||||
let reloc_offset = buf as usize - image_base as usize;
|
|
||||||
// 被修复的地址:
|
|
||||||
let p_address = (buf as usize + offset_va as usize) as *mut u32;
|
|
||||||
let address_value = unsafe { *p_address };
|
|
||||||
|
|
||||||
// TODO: 验证一下是否修复了
|
|
||||||
match r_type {
|
|
||||||
0 => {}
|
|
||||||
1 => {
|
|
||||||
// IMAGE_REL_BASED_HIGH 基址重定位在偏移量处将差值的高 16 位添加到 16 位字段。 16 位字段表示 32 位单词的高值。
|
|
||||||
// 取reloc_offset的高16位
|
|
||||||
let high = (reloc_offset >> 16) as u16;
|
|
||||||
let new_address = address_value + high as u32;
|
|
||||||
unsafe {
|
|
||||||
*p_address = new_address;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
// IMAGE_REL_BASED_LOW 基准重定位将差值的低 16 位加到偏移的 16 位字段。 16 位字段代表 32 位字的低半部分。
|
|
||||||
// 取reloc_offset的低16位
|
|
||||||
let low = reloc_offset as u16;
|
|
||||||
let new_address = address_value + low as u32;
|
|
||||||
unsafe {
|
|
||||||
*p_address = new_address;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
3 => {
|
|
||||||
// 如果r_type是3,表示这个TypeOffset是一个IMAGE_REL_BASED_HIGHLOW
|
|
||||||
// 这个时候需要修复一个32位的地址
|
|
||||||
let new_address = address_value + reloc_offset as u32;
|
|
||||||
unsafe {
|
|
||||||
*p_address = new_address;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
10 => {
|
|
||||||
// IMAGE_REL_BASED_DIR64 基址重定位将差值添加到偏移的 64 位字段。
|
|
||||||
let new_address = address_value + reloc_offset as u32;
|
|
||||||
unsafe {
|
|
||||||
*(p_address as *mut u64) = new_address as u64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// 其他的类型,暂时不支持
|
|
||||||
unimplemented!("未实现的重定位类型: {:?}", r_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 计算下一个IMAGE_BASE_RELOCATION的偏移
|
|
||||||
relocation_offset += size_of_block as usize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: 修复TLS表
|
|
||||||
{}
|
|
||||||
// TODO: 修复资源表
|
|
||||||
{}
|
|
||||||
// TODO: 修复命令行参数
|
|
||||||
{}
|
|
||||||
// 设置节区属性
|
|
||||||
{
|
|
||||||
let section_alignment = file.nt_headers().optional_header.section_alignment();
|
|
||||||
// 遍历节区,设置节区属性
|
|
||||||
for section in file.sections() {
|
|
||||||
let va = section.pe_section().virtual_address.get(LittleEndian);
|
|
||||||
// let size_of_raw_data = section.pe_section().size_of_raw_data.get(LittleEndian);
|
|
||||||
let section_name = section.name().unwrap();
|
|
||||||
let virtual_size = section.pe_section().virtual_size.get(LittleEndian);
|
|
||||||
let characteristics = section.pe_section().characteristics.get(LittleEndian);
|
|
||||||
let section_va = buf as usize + va as usize;
|
|
||||||
let section_size = align_to!(virtual_size, section_alignment);
|
|
||||||
|
|
||||||
// 设置节区属性
|
|
||||||
let protect;
|
|
||||||
if characteristics & IMAGE_SCN_MEM_EXECUTE != 0
|
|
||||||
&& characteristics & IMAGE_SCN_MEM_READ == 0
|
|
||||||
&& characteristics & IMAGE_SCN_MEM_WRITE == 0
|
|
||||||
{
|
|
||||||
protect = PAGE_EXECUTE.0;
|
|
||||||
} else if characteristics & IMAGE_SCN_MEM_EXECUTE != 0
|
|
||||||
&& characteristics & IMAGE_SCN_MEM_READ != 0
|
|
||||||
&& characteristics & IMAGE_SCN_MEM_WRITE == 0
|
|
||||||
{
|
|
||||||
protect = PAGE_EXECUTE_READ.0;
|
|
||||||
} else if characteristics & IMAGE_SCN_MEM_EXECUTE != 0
|
|
||||||
&& characteristics & IMAGE_SCN_MEM_READ != 0
|
|
||||||
&& characteristics & IMAGE_SCN_MEM_WRITE != 0
|
|
||||||
{
|
|
||||||
protect = PAGE_EXECUTE_READWRITE.0;
|
|
||||||
} else if characteristics & IMAGE_SCN_MEM_EXECUTE == 0
|
|
||||||
&& characteristics & IMAGE_SCN_MEM_READ != 0
|
|
||||||
&& characteristics & IMAGE_SCN_MEM_WRITE == 0
|
|
||||||
{
|
|
||||||
protect = PAGE_READONLY.0;
|
|
||||||
} else if characteristics & IMAGE_SCN_MEM_EXECUTE == 0
|
|
||||||
&& characteristics & IMAGE_SCN_MEM_READ != 0
|
|
||||||
&& characteristics & IMAGE_SCN_MEM_WRITE != 0
|
|
||||||
{
|
|
||||||
protect = PAGE_READWRITE.0;
|
|
||||||
} else {
|
|
||||||
return Err(LoadPEError::ChangeMemoryProtectFailed);
|
|
||||||
}
|
|
||||||
// 设置属性
|
|
||||||
let mut old_protect = PAGE_PROTECTION_FLAGS(0);
|
|
||||||
println!("{section_name} va: {:x}, section_size: {:x} address: {:x} characteristics: {:x} protect: {:x}", va, section_size, section_va, characteristics, protect);
|
|
||||||
|
|
||||||
let result = unsafe {
|
|
||||||
VirtualProtect(
|
|
||||||
section_va as *mut _,
|
|
||||||
section_size as usize,
|
|
||||||
PAGE_PROTECTION_FLAGS(protect),
|
|
||||||
&mut old_protect,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
if result.is_err() {
|
|
||||||
return Err(LoadPEError::ChangeMemoryProtectFailed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let entry_point = file
|
|
||||||
.nt_headers()
|
|
||||||
.optional_header
|
|
||||||
.address_of_entry_point
|
|
||||||
.get(LittleEndian);
|
|
||||||
let entry_point = buf as usize + entry_point as usize;
|
|
||||||
let entry_point: extern "system" fn() = unsafe { std::mem::transmute(entry_point) };
|
|
||||||
dbg!("entry_point: {:p}", entry_point);
|
|
||||||
entry_point();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 压缩PE并保存到指定路径
|
|
||||||
/// 需要注入解压缩的位置无关代码
|
|
||||||
pub fn compress_pe(pe_data: &[u8], output_path: &str) -> Result<(), LoadPEError> {
|
|
||||||
// 1. 解析PE文件
|
|
||||||
#[cfg(target_arch = "x86")]
|
|
||||||
let origin_pe: PeFile32 = pe::PeFile::parse(pe_data)?;
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
let origin_pe: PeFile64 = pe::PeFile::parse(pe_data)?;
|
|
||||||
// 2. 获取头部数据
|
|
||||||
let origin_pe_header_data = {
|
|
||||||
let head_size = origin_pe
|
|
||||||
.nt_headers()
|
|
||||||
.optional_header
|
|
||||||
.size_of_headers
|
|
||||||
.get(endian::LittleEndian);
|
|
||||||
&pe_data[..head_size as usize]
|
|
||||||
};
|
|
||||||
// 压缩头部数据
|
|
||||||
let compressed_header_data = compress_prepend_size(origin_pe_header_data);
|
|
||||||
|
|
||||||
// 3. 获取节区数据
|
|
||||||
let section_data = {
|
|
||||||
let offset = origin_pe
|
|
||||||
.section_by_index(SectionIndex(0))?
|
|
||||||
.pe_section()
|
|
||||||
.pointer_to_raw_data
|
|
||||||
.get(LittleEndian);
|
|
||||||
&pe_data[offset as usize..]
|
|
||||||
};
|
|
||||||
// 压缩节区数据
|
|
||||||
let compressed_section_data = compress_prepend_size(section_data);
|
|
||||||
|
|
||||||
// 4. 构造压缩后的PE文件
|
|
||||||
{
|
|
||||||
let section_alignment = origin_pe.nt_headers().optional_header.section_alignment();
|
|
||||||
let file_alignment = origin_pe.nt_headers().optional_header.file_alignment();
|
|
||||||
let compress_info = CompressPeInfo {
|
|
||||||
header_origin_size: origin_pe_header_data.len() as u32,
|
|
||||||
header_compress_size: compressed_header_data.len() as u32,
|
|
||||||
code_origin_size: section_data.len() as u32,
|
|
||||||
code_compress_size: compressed_section_data.len() as u32,
|
|
||||||
};
|
|
||||||
let mut buf = Vec::with_capacity(1024 * 1024);
|
|
||||||
let is_64 = origin_pe.is_64();
|
|
||||||
let mut new_pe_writer = Writer::new(is_64, section_alignment, file_alignment, &mut buf);
|
|
||||||
|
|
||||||
// 写入DOS头和dos sub
|
|
||||||
new_pe_writer.write_dos_header_and_stub()?;
|
|
||||||
// 写入PE头 拷贝一份
|
|
||||||
let mut new_pe_header = origin_pe.nt_headers().clone();
|
|
||||||
// 重写节区
|
|
||||||
new_pe_header.file_header.number_of_sections = U16Bytes::new(LittleEndian, 2);
|
|
||||||
|
|
||||||
// TODO: 数据目录中,我还是想要kernel32.dll中的LoadLibraryA和GetProcAddress地址
|
|
||||||
}
|
}
|
||||||
|
|
||||||
todo!()
|
todo!()
|
||||||
|
14
src/types.rs
14
src/types.rs
@ -1,14 +0,0 @@
|
|||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
/// 保存压缩前的原始PE文件信息
|
|
||||||
pub struct CompressPeInfo {
|
|
||||||
// 原始PE文件头大小
|
|
||||||
pub header_origin_size: u32,
|
|
||||||
// 压缩后的PE文件头大小
|
|
||||||
pub header_compress_size: u32,
|
|
||||||
// 原始PE文件代码段大小
|
|
||||||
pub code_origin_size: u32,
|
|
||||||
// 压缩后的PE文件代码段大小
|
|
||||||
pub code_compress_size: u32,
|
|
||||||
}
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user