mirror of
https://github.com/lifegpc/game-auto-sync.git
synced 2026-06-06 05:48:58 +08:00
在 Windows 平台上增强 DLL 加载支持,添加 hook_dll 配置并更新相关调用逻辑
This commit is contained in:
@@ -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"] }
|
||||||
|
|||||||
@@ -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![])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/main.rs
11
src/main.rs
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user