mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 14:50:41 -07:00
a9fc6ef1b2
## Link to GitHub Issue, if one exists n/a ## Description of change Adds support for Polaris Chord ## Testing Tested with XIF:J:A:A:2024122300. IO/ICCA works, game successfully connects to server and is playable.
211 lines
7.9 KiB
C++
211 lines
7.9 KiB
C++
#include "execexe.h"
|
|
|
|
#include "util/logging.h"
|
|
#include "util/libutils.h"
|
|
#include "util/utils.h"
|
|
#include "util/detour.h"
|
|
|
|
namespace execexe {
|
|
|
|
static HMODULE execexe_module = nullptr;
|
|
static decltype(&LoadLibraryW) execexe_LoadLibraryW = nullptr;
|
|
static decltype(&GetModuleHandleW) execexe_GetModuleHandleW = nullptr;
|
|
static decltype(&GetProcAddress) execexe_GetProcAddress = nullptr;
|
|
static decltype(&CreateFileA) execexe_CreateFileA = nullptr;
|
|
static decltype(&CreateFileW) execexe_CreateFileW = nullptr;
|
|
static decltype(&CloseHandle) execexe_CloseHandle = nullptr;
|
|
static uint64_t (*execexe_PreLoadLibraries)(const char *) = nullptr;
|
|
|
|
static std::wstring plugins_dir;
|
|
static acioemu::ACIOHandle *acio = nullptr;
|
|
static std::wstring port_name;
|
|
static bool port_opened = false;
|
|
static std::function<void()> deferred_function = nullptr;
|
|
|
|
static HANDLE WINAPI execexe_CreateFileA_hook(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
|
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
|
|
const auto lpFileNameW = s2ws(lpFileName);
|
|
if (lpFileNameW == port_name) {
|
|
if (!port_opened) {
|
|
port_opened = acio->open(port_name.c_str());
|
|
} else {
|
|
log_info("execexe", "ignored handle open. ({})", ws2s(port_name));
|
|
}
|
|
SetLastError(0);
|
|
return (HANDLE) acio;
|
|
}
|
|
return execexe_CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
|
|
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
|
}
|
|
|
|
static HANDLE WINAPI execexe_CreateFileW_hook(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
|
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
|
|
if (lpFileName == port_name && acio->open(lpFileName)) {
|
|
if (!port_opened) {
|
|
port_opened = acio->open(port_name.c_str());
|
|
} else {
|
|
log_info("execexe", "ignored handle open. ({})", ws2s(port_name));
|
|
}
|
|
SetLastError(0);
|
|
return (HANDLE) acio;
|
|
} else {
|
|
return execexe_CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
|
|
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
|
}
|
|
}
|
|
|
|
static WINBOOL WINAPI execexe_CloseHandle_hook(HANDLE hObject) {
|
|
if (hObject == acio && port_opened) {
|
|
log_info("execexe", "ignored handle close. ({})", ws2s(port_name));
|
|
return TRUE;
|
|
}
|
|
return execexe_CloseHandle(hObject);
|
|
}
|
|
|
|
static uint64_t execexe_PreLoadLibraries_hook(const char *libs) {
|
|
static bool init = false;
|
|
|
|
uint64_t result = execexe_PreLoadLibraries(libs);
|
|
if (init) {
|
|
return result;
|
|
}
|
|
|
|
init = true;
|
|
log_info("execexe", "execexe_PreLoadLibraries hook hit");
|
|
|
|
if (deferred_function) {
|
|
deferred_function();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
HMODULE init() {
|
|
execexe_module = libutils::load_library("execexe.dll");
|
|
execexe_LoadLibraryW = libutils::get_proc<decltype(&LoadLibraryW)>(execexe_module, MAKEINTRESOURCE(34));
|
|
execexe_GetModuleHandleW = libutils::get_proc<decltype(&GetModuleHandleW)>(execexe_module, MAKEINTRESOURCE(25));
|
|
execexe_GetProcAddress = libutils::get_proc<decltype(&GetProcAddress)>(execexe_module, MAKEINTRESOURCE(27));
|
|
execexe_CloseHandle = libutils::get_proc<decltype(&CloseHandle)>(execexe_module, MAKEINTRESOURCE(7));
|
|
execexe_CreateFileA = libutils::get_proc<decltype(&CreateFileA)>(execexe_module, MAKEINTRESOURCE(9));
|
|
execexe_CreateFileW = libutils::get_proc<decltype(&CreateFileW)>(execexe_module, MAKEINTRESOURCE(11));
|
|
execexe_PreLoadLibraries = libutils::get_proc<decltype(execexe_PreLoadLibraries)>(execexe_module, MAKEINTRESOURCE(48));
|
|
|
|
auto module_path = libutils::module_file_name(nullptr);
|
|
module_path = module_path.replace_extension("");
|
|
module_path = module_path.replace_filename(module_path.filename().wstring() + L"_Data");
|
|
plugins_dir = (module_path / L"Plugins" / L"x86_64").wstring() + L"\\";
|
|
|
|
return execexe_module;
|
|
}
|
|
|
|
void init_deferred(std::function<void()> init_func) {
|
|
if (deferred_function) {
|
|
log_fatal("execexe", "deferred init function is already set");
|
|
}
|
|
deferred_function = std::move(init_func);
|
|
detour::trampoline("execexe.dll", MAKEINTRESOURCE(48),
|
|
execexe_PreLoadLibraries_hook, &execexe_PreLoadLibraries);
|
|
}
|
|
|
|
void init_port_hook(const std::wstring &portName, acioemu::ACIOHandle *acioHandle) {
|
|
static bool init = false;
|
|
if (init)
|
|
return;
|
|
init = true;
|
|
|
|
port_name = portName;
|
|
acio = acioHandle;
|
|
detour::trampoline_try("execexe.dll", MAKEINTRESOURCE(7),
|
|
execexe_CloseHandle_hook, &execexe_CloseHandle);
|
|
detour::trampoline_try("execexe.dll", MAKEINTRESOURCE(9),
|
|
execexe_CreateFileA_hook, &execexe_CreateFileA);
|
|
detour::trampoline_try("execexe.dll", MAKEINTRESOURCE(11),
|
|
execexe_CreateFileW_hook, &execexe_CreateFileW);
|
|
}
|
|
|
|
HMODULE load_library(const char *module_name, bool fatal) {
|
|
std::wstring module_name_w = s2ws(module_name);
|
|
std::wstring plugin_path = plugins_dir + module_name_w;
|
|
HMODULE module = execexe_LoadLibraryW(plugin_path.c_str());
|
|
if (module != nullptr) {
|
|
return module;
|
|
}
|
|
|
|
module = execexe_LoadLibraryW(module_name_w.c_str());
|
|
if (module != nullptr) {
|
|
return module;
|
|
}
|
|
|
|
if (fatal) {
|
|
log_fatal("execexe", "failed to load library {}", module_name);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
HMODULE get_module(const char *module_name, bool fatal) {
|
|
std::wstring module_name_w = s2ws(module_name);
|
|
std::wstring plugin_path = plugins_dir + module_name_w;
|
|
|
|
HMODULE module = execexe_GetModuleHandleW(plugin_path.c_str());
|
|
if (module != nullptr) {
|
|
return module;
|
|
}
|
|
|
|
module = execexe_GetModuleHandleW(module_name_w.c_str());
|
|
if (module != nullptr) {
|
|
return module;
|
|
}
|
|
|
|
if (fatal) {
|
|
log_fatal("execexe", "failed to get module {}", module_name);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
FARPROC get_proc(HMODULE module, const char *proc_name, bool fatal) {
|
|
FARPROC proc = execexe_GetProcAddress(module, proc_name);
|
|
if (proc != nullptr) {
|
|
return proc;
|
|
}
|
|
|
|
if (fatal) {
|
|
log_fatal("execexe", "proc {} not found", proc_name);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool trampoline(const char *dll, const char *func, void *hook, void **orig) {
|
|
HMODULE module = get_module(dll);
|
|
FARPROC proc = get_proc(module, func);
|
|
|
|
return detour::trampoline(
|
|
reinterpret_cast<void *>(proc),
|
|
hook,
|
|
orig
|
|
);
|
|
}
|
|
|
|
bool trampoline_try(const char *dll, const char *func, void *hook, void **orig) {
|
|
HMODULE module = get_module(dll, false);
|
|
if (module == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
FARPROC proc = get_proc(module, func, false);
|
|
if (proc == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
return detour::trampoline(
|
|
reinterpret_cast<void *>(proc),
|
|
hook,
|
|
orig
|
|
);
|
|
}
|
|
}
|