在 Windows 平台上增强 DLL 加载支持,添加 hook_dll 配置并更新相关调用逻辑

This commit is contained in:
2025-03-15 17:30:28 +08:00
parent 0d5c6ff8fa
commit 4c9f8588a8
4 changed files with 89 additions and 5 deletions

View File

@@ -10,4 +10,4 @@ subprocess = "0.2.9"
yaml-rust = "0.4.5" yaml-rust = "0.4.5"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["errhandlingapi", "impl-default", "ioapiset", "jobapi2", "wincon", "winuser"] } winapi = { version = "0.3", features = ["errhandlingapi", "impl-default", "ioapiset", "jobapi2", "memoryapi", "wincon", "winuser"] }

View File

@@ -157,4 +157,9 @@ impl Config {
.map(|s| s.to_owned()) .map(|s| s.to_owned())
.unwrap_or(false) .unwrap_or(false)
} }
#[cfg(windows)]
pub fn hook_dll(&self) -> Vec<String> {
self.get_str_vec("hook_dll").unwrap_or(vec![])
}
} }

View File

@@ -116,7 +116,13 @@ impl Main {
#[cfg(windows)] #[cfg(windows)]
fn call(cml: Vec<String>) -> Result<ExitStatus, windows::PopenError> { fn call(cml: Vec<String>) -> Result<ExitStatus, windows::PopenError> {
windows::call(&cml).map(|c| ExitStatus::Exited(c)) let t = Vec::<String>::new();
windows::call(&cml, &t).map(|c| ExitStatus::Exited(c))
}
#[cfg(windows)]
fn call2(cml: Vec<String>, dlls: Vec<String>) -> Result<ExitStatus, windows::PopenError> {
windows::call(&cml, &dlls).map(|c| ExitStatus::Exited(c))
} }
fn restore(&self) -> Result<(), Error> { fn restore(&self) -> Result<(), Error> {
@@ -210,8 +216,11 @@ impl Main {
if need_hide && !hide { if need_hide && !hide {
println!("Failed to hide console window."); println!("Failed to hide console window.");
} }
#[cfg(not(windows))]
let e = Self::call(cml)?; let e = Self::call(cml)?;
#[cfg(windows)] #[cfg(windows)]
let e = Self::call2(cml, self._cfg.hook_dll())?;
#[cfg(windows)]
if hide { if hide {
windows::show_window(); windows::show_window();
} }

View File

@@ -8,16 +8,20 @@ use winapi::shared::minwindef::DWORD;
use winapi::um::errhandlingapi::GetLastError; use winapi::um::errhandlingapi::GetLastError;
use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE}; use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
use winapi::um::ioapiset::{CreateIoCompletionPort, GetQueuedCompletionStatus}; use winapi::um::ioapiset::{CreateIoCompletionPort, GetQueuedCompletionStatus};
use winapi::um::libloaderapi::{GetModuleHandleA, GetProcAddress};
use winapi::um::jobapi2::{AssignProcessToJobObject, SetInformationJobObject}; use winapi::um::jobapi2::{AssignProcessToJobObject, SetInformationJobObject};
use winapi::um::memoryapi::{VirtualAllocEx, WriteProcessMemory, VirtualFreeEx};
use winapi::um::minwinbase::LPOVERLAPPED; use winapi::um::minwinbase::LPOVERLAPPED;
use winapi::um::processthreadsapi::{ use winapi::um::processthreadsapi::{
CreateProcessW, GetExitCodeProcess, ResumeThread, PROCESS_INFORMATION, STARTUPINFOW, CreateProcessW, GetExitCodeProcess, ResumeThread, TerminateProcess, PROCESS_INFORMATION,
STARTUPINFOW, CreateRemoteThread,
}; };
use winapi::um::synchapi::WaitForSingleObject;
use winapi::um::winbase::{CreateJobObjectA, CREATE_SUSPENDED, INFINITE}; use winapi::um::winbase::{CreateJobObjectA, CREATE_SUSPENDED, INFINITE};
use winapi::um::wincon::GetConsoleWindow; use winapi::um::wincon::GetConsoleWindow;
use winapi::um::winnt::{ use winapi::um::winnt::{
JobObjectAssociateCompletionPortInformation, JOBOBJECT_ASSOCIATE_COMPLETION_PORT, JobObjectAssociateCompletionPortInformation, JOBOBJECT_ASSOCIATE_COMPLETION_PORT,
JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, MEM_COMMIT, PAGE_READWRITE, MEM_RELEASE,
}; };
use winapi::um::winuser::{ShowWindow, SW_HIDE, SW_SHOW}; use winapi::um::winuser::{ShowWindow, SW_HIDE, SW_SHOW};
@@ -43,9 +47,10 @@ pub enum PopenError {
CreateJobFailed, CreateJobFailed,
CreateProcessFailed, CreateProcessFailed,
AssignJobFailed, AssignJobFailed,
CreateThreadFailed,
} }
pub fn call<S: AsRef<OsStr>>(argv: &[S]) -> Result<u32, PopenError> { pub fn call<S: AsRef<OsStr>, T: AsRef<OsStr>>(argv: &[S], dlls: &[T]) -> Result<u32, PopenError> {
let job = unsafe { CreateJobObjectA(null_mut(), null()) }; let job = unsafe { CreateJobObjectA(null_mut(), null()) };
if job.is_null() { if job.is_null() {
println!("Failed to create job: {}.", unsafe { GetLastError() }); println!("Failed to create job: {}.", unsafe { GetLastError() });
@@ -129,6 +134,71 @@ pub fn call<S: AsRef<OsStr>>(argv: &[S]) -> Result<u32, PopenError> {
unsafe { CloseHandle(io_port) }; unsafe { CloseHandle(io_port) };
return Err(PopenError::AssignJobFailed); return Err(PopenError::AssignJobFailed);
} }
for i in dlls.iter() {
let dll: Vec<_> = i.as_ref().encode_wide().collect();
let mem_size = (dll.len() + 1) * size_of::<u16>();
let p_dll_path = unsafe {
VirtualAllocEx(
pi.hProcess,
null_mut(),
mem_size,
MEM_COMMIT,
PAGE_READWRITE,
)
};
if p_dll_path.is_null() {
println!("Failed to allocate memory in remote process.");
unsafe { TerminateProcess(pi.hProcess, 1) };
unsafe { CloseHandle(job) };
unsafe { CloseHandle(io_port) };
unsafe { CloseHandle(pi.hProcess) };
unsafe { CloseHandle(pi.hThread) };
return Err(PopenError::CreateProcessFailed);
}
let re = unsafe {
WriteProcessMemory(
pi.hProcess,
p_dll_path,
dll.as_ptr() as *const c_void,
mem_size,
null_mut(),
) != 0
};
if !re {
println!("Failed to write memory in remote process.");
unsafe { VirtualFreeEx(pi.hProcess, p_dll_path, 0, MEM_RELEASE) };
unsafe { TerminateProcess(pi.hProcess, 1) };
unsafe { CloseHandle(job) };
unsafe { CloseHandle(io_port) };
unsafe { CloseHandle(pi.hProcess) };
unsafe { CloseHandle(pi.hThread) };
return Err(PopenError::CreateProcessFailed);
}
let h_thread = unsafe {
CreateRemoteThread(
pi.hProcess,
null_mut(),
0,
Some(std::mem::transmute(GetProcAddress(GetModuleHandleA("kernel32\0".as_ptr() as *const i8), "LoadLibraryW\0".as_ptr() as *const i8))),
p_dll_path,
0,
null_mut(),
)
};
if h_thread.is_null() {
println!("Failed to create remote thread.");
unsafe { VirtualFreeEx(pi.hProcess, p_dll_path, 0, MEM_RELEASE) };
unsafe { TerminateProcess(pi.hProcess, 1) };
unsafe { CloseHandle(job) };
unsafe { CloseHandle(io_port) };
unsafe { CloseHandle(pi.hProcess) };
unsafe { CloseHandle(pi.hThread) };
return Err(PopenError::CreateThreadFailed);
}
unsafe { WaitForSingleObject(h_thread, INFINITE) };
unsafe { VirtualFreeEx(pi.hProcess, p_dll_path, 0, MEM_RELEASE) };
unsafe { CloseHandle(h_thread) };
}
unsafe { ResumeThread(pi.hThread) }; unsafe { ResumeThread(pi.hThread) };
let mut code = DWORD::default(); let mut code = DWORD::default();
let mut key = ULONG_PTR::default(); let mut key = ULONG_PTR::default();