From 965126c68af3eeedd45c779aa5b42c178e47cc66 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 30 Jun 2024 14:23:20 +0200 Subject: [PATCH] idac: improved compatibility with newer versions --- dist/idac/segatools.ini | 14 ++- idachook/config.c | 11 ++ idachook/config.h | 10 +- idachook/dllmain.c | 7 ++ idachook/indrun.c | 260 ++++++++++++++++++++++++++++++++++++++++ idachook/indrun.h | 9 ++ idachook/meson.build | 2 + 7 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 idachook/indrun.c create mode 100644 idachook/indrun.h diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index eab33e2..f678a77 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -80,8 +80,18 @@ dipsw5=0 ; ----------------------------------------------------------------------------- [led15070] -; Enable emulation of the 15070-02 controlled lights, which handle the cabinet -; and seat LEDs. +; Enable emulation of the 837-15070-02 controlled lights, which handle the +; cabinet and seat LEDs. +enable=1 + +; ----------------------------------------------------------------------------- +; Misc. hooks settings +; ----------------------------------------------------------------------------- + +[indrun] +; Hooks to patch GameProject-Win64-Shipping.exe and IndRun.dll. This is needed +; to boot version 1.60.00 and up. The hooks are not needed for version 1.50.00 +; and below. enable=1 ; ----------------------------------------------------------------------------- diff --git a/idachook/config.c b/idachook/config.c index f3bf349..a4fe392 100644 --- a/idachook/config.c +++ b/idachook/config.c @@ -66,6 +66,16 @@ void idac_dll_config_load( filename); } +void indrun_config_load( + struct indrun_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"indrun", L"enable", 1, filename); +} + void idac_hook_config_load( struct idac_hook_config *cfg, const wchar_t *filename) @@ -80,6 +90,7 @@ void idac_hook_config_load( dvd_config_load(&cfg->dvd, filename); io4_config_load(&cfg->io4, filename); led15070_config_load(&cfg->led15070, filename); + indrun_config_load(&cfg->indrun, filename); } void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename) diff --git a/idachook/config.h b/idachook/config.h index 2ff8d33..b7ca6d3 100644 --- a/idachook/config.h +++ b/idachook/config.h @@ -10,6 +10,7 @@ #include "idachook/idac-dll.h" #include "idachook/zinput.h" +#include "idachook/indrun.h" #include "platform/platform.h" @@ -21,6 +22,7 @@ struct idac_hook_config { struct idac_dll_config dll; struct zinput_config zinput; struct led15070_config led15070; + struct indrun_config indrun; }; void idac_dll_config_load( @@ -31,4 +33,10 @@ void idac_hook_config_load( struct idac_hook_config *cfg, const wchar_t *filename); -void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename); +void zinput_config_load( + struct zinput_config *cfg, + const wchar_t *filename); + +void indrun_config_load( + struct indrun_config *cfg, + const wchar_t *filename); diff --git a/idachook/dllmain.c b/idachook/dllmain.c index d16c175..63b0954 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -91,6 +91,13 @@ static DWORD CALLBACK idac_pre_startup(void) goto fail; } + /* Initialize native plugin DLL hooks + + There seems to be an issue with other DLL hooks if `LoadLibraryW` is + hooked earlier in the initialization. */ + + indrun_hook_init(&idac_hook_cfg.indrun); + /* Initialize debug helpers */ spike_hook_init(L".\\segatools.ini"); diff --git a/idachook/indrun.c b/idachook/indrun.c new file mode 100644 index 0000000..1b9eb77 --- /dev/null +++ b/idachook/indrun.c @@ -0,0 +1,260 @@ +#include +#include + +#include "hook/table.h" + +#include "hooklib/dll.h" + +#include "util/dprintf.h" + +#include "indrun.h" + +static const wchar_t *target_modules[] = { + L"IndRun.dll", +}; + +static const size_t target_modules_len = _countof(target_modules); + +static void dll_hook_insert_hooks(HMODULE target); +static void app_hook_insert_hooks(HMODULE target); + +static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name); +static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name); + +static int WINAPI hook_GetSystemMetrics(int nIndex); +static int (WINAPI *next_GetSystemMetrics)(int nIndex); + +static BOOL WINAPI hook_GetComputerNameW(LPWSTR lpBuffer, LPDWORD nSize); +static DWORD WINAPI hook_GetCurrentDirectoryW( DWORD nBufferLength, LPWSTR lpBuffer); +static BOOL WINAPI hook_GetVersionExW(LPOSVERSIONINFOW lpVersionInformation); +static int (WINAPI *next_GetVersionExW)(LPOSVERSIONINFOW lpVersionInformation); +static BOOL WINAPI hook_VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask); +static BOOL (WINAPI *next_VerifyVersionInfoW)(LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask); +static BOOL WINAPI hook_K32EnumProcesses(DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded); +static BOOL (WINAPI *next_K32EnumProcesses)(DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded); + +static BOOL WINAPI hook_GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer); + +static const struct hook_symbol idac_app_user32_syms[] = { + { + .name = "GetSystemMetrics", + .patch = hook_GetSystemMetrics, + .link = (void **) &next_GetSystemMetrics, + } +}; + +static const struct hook_symbol idac_app_kernel32_syms[] = { + { + .name = "GetComputerNameW", + .patch = hook_GetComputerNameW, + }, + { + .name = "GetCurrentDirectoryW", + .patch = hook_GetCurrentDirectoryW, + }, + { + .name = "GetVersionExW", + .patch = hook_GetVersionExW, + .link = (void **) &next_GetVersionExW, + }, + { + .name = "VerifyVersionInfoW", + .patch = hook_VerifyVersionInfoW, + .link = (void **) &next_VerifyVersionInfoW, + }, + { + .name = "K32EnumProcesses", + .patch = hook_K32EnumProcesses, + .link = (void **) &next_K32EnumProcesses, + } +}; + +static const struct hook_symbol idac_app_advapi32_syms[] = { + { + .name = "GetUserNameW", + .patch = hook_GetUserNameW, + } +}; + +static const struct hook_symbol indrun_kernel32_syms[] = { + { + .name = "LoadLibraryW", + .patch = hook_LoadLibraryW, + .link = (void **) &next_LoadLibraryW, + } +}; + +void indrun_hook_init(struct indrun_config *cfg) +{ + assert(cfg != NULL); + + if (!cfg->enable) { + return; + } + + dprintf("IDAC: Hooks enabled.\n"); + + // GameProject-Win64-Shipping.exe hooks + app_hook_insert_hooks(NULL); + + // IndRun.dll hooks + dll_hook_insert_hooks(NULL); +} + +static void dll_hook_insert_hooks(HMODULE target) { + hook_table_apply( + target, + "kernel32.dll", + indrun_kernel32_syms, + _countof(indrun_kernel32_syms)); +} + +void app_hook_insert_hooks(HMODULE target) { + hook_table_apply( + target, + "user32.dll", + idac_app_user32_syms, + _countof(idac_app_user32_syms)); + + hook_table_apply( + target, + "kernel32.dll", + idac_app_kernel32_syms, + _countof(idac_app_kernel32_syms)); + + hook_table_apply( + target, + "advapi32.dll", + idac_app_advapi32_syms, + _countof(idac_app_advapi32_syms)); +} + +static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name) +{ + const wchar_t *name_end; + const wchar_t *target_module; + bool already_loaded; + HMODULE result; + size_t name_len; + size_t target_module_len; + + if (name == NULL) { + SetLastError(ERROR_INVALID_PARAMETER); + + return NULL; + } + + // Check if the module is already loaded + already_loaded = GetModuleHandleW(name) != NULL; + + // Must call the next handler so the DLL reference count is incremented + result = next_LoadLibraryW(name); + + if (!already_loaded && result != NULL) { + name_len = wcslen(name); + + for (size_t i = 0; i < target_modules_len; i++) { + target_module = target_modules[i]; + target_module_len = wcslen(target_module); + + // Check if the newly loaded library is at least the length of + // the name of the target module + if (name_len < target_module_len) { + continue; + } + + name_end = &name[name_len - target_module_len]; + + // Check if the name of the newly loaded library is one of the + // modules the path hooks should be injected into + if (_wcsicmp(name_end, target_module) != 0) { + continue; + } + + dprintf("IDAC: Hooked %S\n", target_module); + + dll_hook_insert_hooks(result); + app_hook_insert_hooks(result); + } + } + + return result; +} + +static int WINAPI hook_GetSystemMetrics(int nIndex) { + int ret = next_GetSystemMetrics(nIndex); + + // Disable mouse buttons detection + if (nIndex == SM_CMOUSEBUTTONS) { + dprintf("IDAC: GetSystemMetrics(%d) -> 0\n", nIndex); + return 0; + } + + return ret; +} + +static BOOL WINAPI hook_GetComputerNameW(LPWSTR lpBuffer, LPDWORD nSize) { + dprintf("IDAC: GetComputerNameW -> ACAE01A99999999\n"); + + // Fake the computer name as ACAE01A999999999 + wcscpy(lpBuffer, L"ACAE01A999999999"); + *nSize = _countof(L"ACAE01A99999999"); + + return TRUE; +} + +static DWORD WINAPI hook_GetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer) { + dprintf("IDAC: GetCurrentDirectoryW -> X:\\\n"); + + // Fake the current diretory as X: + wcscpy(lpBuffer, L"X"); + return 1; +} + +static BOOL WINAPI hook_GetVersionExW(LPOSVERSIONINFOW lpVersionInformation) { + int result = next_GetVersionExW(lpVersionInformation); + + // Fake the version as Windows 10 1809 + if (result) { + dprintf("IDAC: GetVersionExW -> Windows 10 1809\n"); + lpVersionInformation->dwMajorVersion = 10; + lpVersionInformation->dwMinorVersion = 0; + lpVersionInformation->dwBuildNumber = 17763; + return TRUE; + } + + return result; +} + +static BOOL WINAPI hook_GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer) { + dprintf("IDAC: GetUserNameW -> AppUser\n"); + + // Fake the user name as AppUser + wcscpy(lpBuffer, L"AppUser"); + *pcbBuffer = _countof(L"AppUser"); + + return TRUE; +} + +static BOOL WINAPI hook_VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask) { + BOOL result = next_VerifyVersionInfoW(lpVersionInformation, dwTypeMask, dwlConditionMask); + + // Fake the version as Windows 10 1809 + if (lpVersionInformation->dwBuildNumber == 17763) { + dprintf("IDAC: VerifyVersionInfoW -> Windows 10 1809\n"); + return TRUE; + } + + return result; +} + +static BOOL WINAPI hook_K32EnumProcesses(DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded) { + BOOL result = next_K32EnumProcesses(lpidProcess, cb, lpcbNeeded); + + // Rteurn an empy process list + dprintf("IDAC: K32EnumProcesses -> NULL\n"); + lpidProcess = NULL; + *lpcbNeeded = 0; + + return TRUE; +} diff --git a/idachook/indrun.h b/idachook/indrun.h new file mode 100644 index 0000000..4605285 --- /dev/null +++ b/idachook/indrun.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +struct indrun_config { + bool enable; +}; + +void indrun_hook_init(struct indrun_config *cfg); diff --git a/idachook/meson.build b/idachook/meson.build index 72214ac..8de655e 100644 --- a/idachook/meson.build +++ b/idachook/meson.build @@ -28,5 +28,7 @@ shared_library( 'io4.h', 'zinput.c', 'zinput.h', + 'indrun.c', + 'indrun.h', ], )