diff --git a/src/config.cpp b/src/config.cpp index d630005..87870a9 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -57,7 +57,7 @@ namespace config { std::string make_default_config_json() { return "{\r\n" - " \"force_http\": false,\r\n" + " \"force_http\": true,\r\n" " \"api_url\": \"apis.game.starlight-stage.jp/\",\r\n" " \"asset_url\": \"asset-starlight-stage.akamaized.net/\",\r\n" " \"launch_borderless_helper\": true\r\n" diff --git a/src/helper_main.cpp b/src/helper_main.cpp index 3995c78..132cf5c 100644 --- a/src/helper_main.cpp +++ b/src/helper_main.cpp @@ -17,6 +17,7 @@ namespace { HWND g_main_window = nullptr; bool g_borderless_active = false; bool g_saved_state_valid = false; + bool g_borderless_drift_logged = false; RECT g_saved_window_rect = {}; LONG_PTR g_saved_style = 0; LONG_PTR g_saved_exstyle = 0; @@ -298,11 +299,13 @@ namespace { if (g_borderless_active) { g_borderless_active = false; + g_borderless_drift_logged = false; restore_window(hwnd); return; } g_borderless_active = true; + g_borderless_drift_logged = false; helper_logf( "[cgss-borderless-helper] borderless enabled monitor=%ls rect=(%ld,%ld)-(%ld,%ld)", monitor_info.szDevice, @@ -370,8 +373,13 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { DWORD now = GetTickCount(); if (g_borderless_active && now - last_maintain_tick >= kMaintainIntervalMs) { if (needs_borderless_reapply(g_main_window)) { - helper_logf("[cgss-borderless-helper] detected borderless drift, reapplying"); + if (!g_borderless_drift_logged) { + helper_logf("[cgss-borderless-helper] detected borderless drift, reapplying"); + g_borderless_drift_logged = true; + } apply_borderless_once(g_main_window); + } else { + g_borderless_drift_logged = false; } last_maintain_tick = now; } diff --git a/src/hook.cpp b/src/hook.cpp index 5b733da..1545fae 100644 --- a/src/hook.cpp +++ b/src/hook.cpp @@ -5,7 +5,6 @@ namespace { using GetSchemeTypeFn = int (*)(const MethodInfo*); - using GetStringFn = void* (*)(const MethodInfo*); using SetStringFn = void (*)(void*, const MethodInfo*); using SetSchemeModeFn = void (*)(int, const MethodInfo*); constexpr int kHttpSchemeType = 0; @@ -15,36 +14,33 @@ namespace { volatile LONG g_hook_installed = 0; GetSchemeTypeFn g_orig_get_scheme_type = nullptr; - GetStringFn g_orig_get_application_server_url = nullptr; - GetStringFn g_orig_get_tele_scope_server_url = nullptr; - GetStringFn g_orig_get_concert_server_url = nullptr; - GetStringFn g_orig_get_resource_server_url = nullptr; - GetStringFn g_orig_custom_preference_get_application_server_url = nullptr; - GetStringFn g_orig_custom_preference_get_tele_scope_server_url = nullptr; - GetStringFn g_orig_custom_preference_get_concert_server_url = nullptr; - GetStringFn g_orig_custom_preference_get_resource_server_url = nullptr; - SetStringFn g_orig_custom_preference_set_application_server_url = nullptr; - SetStringFn g_orig_custom_preference_set_tele_scope_server_url = nullptr; - SetStringFn g_orig_custom_preference_set_concert_server_url = nullptr; - SetStringFn g_orig_custom_preference_set_resource_server_url = nullptr; SetSchemeModeFn g_orig_custom_preference_set_scheme_mode = nullptr; volatile LONG g_logged_gameassembly = 0; volatile LONG g_exports_state = 0; ULONGLONG g_gameassembly_seen_tick = 0; volatile LONG g_scheme_hook_called = 0; - volatile LONG g_application_hook_called = 0; - volatile LONG g_tele_scope_hook_called = 0; - volatile LONG g_concert_hook_called = 0; - volatile LONG g_resource_hook_called = 0; - volatile LONG g_cp_application_hook_called = 0; - volatile LONG g_cp_tele_scope_hook_called = 0; - volatile LONG g_cp_concert_hook_called = 0; - volatile LONG g_cp_resource_hook_called = 0; - volatile LONG g_cp_set_application_hook_called = 0; - volatile LONG g_cp_set_tele_scope_hook_called = 0; - volatile LONG g_cp_set_concert_hook_called = 0; - volatile LONG g_cp_set_resource_hook_called = 0; volatile LONG g_cp_set_scheme_hook_called = 0; + void* g_cached_api_url_string = nullptr; + void* g_cached_asset_url_string = nullptr; + + void prepare_cached_override_strings() { + const auto& urls = config::get(); + if (urls.api_url.empty() && urls.asset_url.empty()) { + return; + } + if (!urls.api_url.empty() && !g_cached_api_url_string) { + g_cached_api_url_string = il2cpp_symbols::new_string(urls.api_url.c_str()); + if (!g_cached_api_url_string) { + hook_log("[cgss-dmm-hook] failed to cache api_url string"); + } + } + if (!urls.asset_url.empty() && !g_cached_asset_url_string) { + g_cached_asset_url_string = il2cpp_symbols::new_string(urls.asset_url.c_str()); + if (!g_cached_asset_url_string) { + hook_log("[cgss-dmm-hook] failed to cache asset_url string"); + } + } + } int get_scheme_type_hook(const MethodInfo*) { if (InterlockedCompareExchange(&g_scheme_hook_called, 1, 0) == 0) { @@ -53,154 +49,6 @@ namespace { return kHttpSchemeType; } - void* get_application_server_url_hook(const MethodInfo* method) { - const auto& urls = config::get(); - if (InterlockedCompareExchange(&g_application_hook_called, 1, 0) == 0) { - hook_log("[cgss-dmm-hook] GetApplicationServerUrl hook invoked"); - } - if (!urls.api_url.empty()) { - return il2cpp_symbols::new_string(urls.api_url.c_str()); - } - return g_orig_get_application_server_url ? g_orig_get_application_server_url(method) : nullptr; - } - - void* get_tele_scope_server_url_hook(const MethodInfo* method) { - const auto& urls = config::get(); - if (InterlockedCompareExchange(&g_tele_scope_hook_called, 1, 0) == 0) { - hook_log("[cgss-dmm-hook] GetTeleScopeServerUrl hook invoked"); - } - if (!urls.api_url.empty()) { - return il2cpp_symbols::new_string(urls.api_url.c_str()); - } - return g_orig_get_tele_scope_server_url ? g_orig_get_tele_scope_server_url(method) : nullptr; - } - - void* get_concert_server_url_hook(const MethodInfo* method) { - const auto& urls = config::get(); - if (InterlockedCompareExchange(&g_concert_hook_called, 1, 0) == 0) { - hook_log("[cgss-dmm-hook] GetConcertServerUrl hook invoked"); - } - if (!urls.api_url.empty()) { - return il2cpp_symbols::new_string(urls.api_url.c_str()); - } - return g_orig_get_concert_server_url ? g_orig_get_concert_server_url(method) : nullptr; - } - - void* get_resource_server_url_hook(const MethodInfo* method) { - const auto& urls = config::get(); - if (InterlockedCompareExchange(&g_resource_hook_called, 1, 0) == 0) { - hook_log("[cgss-dmm-hook] GetResourceServerUrl hook invoked"); - } - if (!urls.asset_url.empty()) { - return il2cpp_symbols::new_string(urls.asset_url.c_str()); - } - return g_orig_get_resource_server_url ? g_orig_get_resource_server_url(method) : nullptr; - } - - void* custom_preference_get_application_server_url_hook(const MethodInfo* method) { - const auto& urls = config::get(); - if (InterlockedCompareExchange(&g_cp_application_hook_called, 1, 0) == 0) { - hook_log("[cgss-dmm-hook] Cute.CustomPreference.GetApplicationServerURL hook invoked"); - } - if (!urls.api_url.empty()) { - return il2cpp_symbols::new_string(urls.api_url.c_str()); - } - return g_orig_custom_preference_get_application_server_url - ? g_orig_custom_preference_get_application_server_url(method) - : nullptr; - } - - void* custom_preference_get_tele_scope_server_url_hook(const MethodInfo* method) { - const auto& urls = config::get(); - if (InterlockedCompareExchange(&g_cp_tele_scope_hook_called, 1, 0) == 0) { - hook_log("[cgss-dmm-hook] Cute.CustomPreference.GetTeleScopeServerURL hook invoked"); - } - if (!urls.api_url.empty()) { - return il2cpp_symbols::new_string(urls.api_url.c_str()); - } - return g_orig_custom_preference_get_tele_scope_server_url - ? g_orig_custom_preference_get_tele_scope_server_url(method) - : nullptr; - } - - void* custom_preference_get_concert_server_url_hook(const MethodInfo* method) { - const auto& urls = config::get(); - if (InterlockedCompareExchange(&g_cp_concert_hook_called, 1, 0) == 0) { - hook_log("[cgss-dmm-hook] Cute.CustomPreference.GetConcertServerURL hook invoked"); - } - if (!urls.api_url.empty()) { - return il2cpp_symbols::new_string(urls.api_url.c_str()); - } - return g_orig_custom_preference_get_concert_server_url - ? g_orig_custom_preference_get_concert_server_url(method) - : nullptr; - } - - void* custom_preference_get_resource_server_url_hook(const MethodInfo* method) { - const auto& urls = config::get(); - if (InterlockedCompareExchange(&g_cp_resource_hook_called, 1, 0) == 0) { - hook_log("[cgss-dmm-hook] Cute.CustomPreference.GetResourceServerURL hook invoked"); - } - if (!urls.asset_url.empty()) { - return il2cpp_symbols::new_string(urls.asset_url.c_str()); - } - return g_orig_custom_preference_get_resource_server_url - ? g_orig_custom_preference_get_resource_server_url(method) - : nullptr; - } - - void custom_preference_set_application_server_url_hook(void* value, const MethodInfo* method) { - const auto& urls = config::get(); - if (InterlockedCompareExchange(&g_cp_set_application_hook_called, 1, 0) == 0) { - hook_log("[cgss-dmm-hook] Cute.CustomPreference.SetApplicationServerURL hook invoked"); - } - if (g_orig_custom_preference_set_application_server_url) { - if (!urls.api_url.empty()) { - value = il2cpp_symbols::new_string(urls.api_url.c_str()); - } - g_orig_custom_preference_set_application_server_url(value, method); - } - } - - void custom_preference_set_tele_scope_server_url_hook(void* value, const MethodInfo* method) { - const auto& urls = config::get(); - if (InterlockedCompareExchange(&g_cp_set_tele_scope_hook_called, 1, 0) == 0) { - hook_log("[cgss-dmm-hook] Cute.CustomPreference.SetTeleScopeServerURL hook invoked"); - } - if (g_orig_custom_preference_set_tele_scope_server_url) { - if (!urls.api_url.empty()) { - value = il2cpp_symbols::new_string(urls.api_url.c_str()); - } - g_orig_custom_preference_set_tele_scope_server_url(value, method); - } - } - - void custom_preference_set_concert_server_url_hook(void* value, const MethodInfo* method) { - const auto& urls = config::get(); - if (InterlockedCompareExchange(&g_cp_set_concert_hook_called, 1, 0) == 0) { - hook_log("[cgss-dmm-hook] Cute.CustomPreference.SetConcertServerURL hook invoked"); - } - if (g_orig_custom_preference_set_concert_server_url) { - if (!urls.api_url.empty()) { - value = il2cpp_symbols::new_string(urls.api_url.c_str()); - } - g_orig_custom_preference_set_concert_server_url(value, method); - } - } - - void custom_preference_set_resource_server_url_hook(void* value, const MethodInfo* method) { - const auto& urls = config::get(); - if (InterlockedCompareExchange(&g_cp_set_resource_hook_called, 1, 0) == 0) { - hook_log("[cgss-dmm-hook] Cute.CustomPreference.SetResourceServerURL hook invoked"); - } - if (g_orig_custom_preference_set_resource_server_url) { - if (!urls.asset_url.empty()) { - value = il2cpp_symbols::new_string(urls.asset_url.c_str()); - } - g_orig_custom_preference_set_resource_server_url(value, method); - } - } - void custom_preference_set_scheme_mode_hook(int scheme_type, const MethodInfo* method) { if (InterlockedCompareExchange(&g_cp_set_scheme_hook_called, 1, 0) == 0) { hook_log("[cgss-dmm-hook] Cute.CustomPreference.SetScemeMode hook invoked"); @@ -213,8 +61,7 @@ namespace { } void patch_custom_preference_scheme() { - const auto& urls = config::get(); - if (!urls.force_http) { + if (!config::get().force_http) { hook_log("[cgss-dmm-hook] force_http disabled, skipping CustomPreference scheme patch"); return; } @@ -235,6 +82,11 @@ namespace { } void apply_custom_preference_url_overrides() { + const auto& urls = config::get(); + if (urls.api_url.empty() && urls.asset_url.empty()) { + return; + } + auto custom_preference = il2cpp_symbols::get_class( "Assembly-CSharp.dll", "Cute", "CustomPreference" ); @@ -244,9 +96,9 @@ namespace { } il2cpp_symbols::il2cpp_runtime_class_init(custom_preference); + prepare_cached_override_strings(); - const auto& urls = config::get(); - if (urls.force_http) { + if (config::get().force_http) { auto set_scheme_mode_addr = il2cpp_symbols::get_method_pointer( "Assembly-CSharp.dll", "Cute", "CustomPreference", "SetScemeMode", 1 ); @@ -267,7 +119,7 @@ namespace { auto set_concert_addr = il2cpp_symbols::get_method_pointer( "Assembly-CSharp.dll", "Cute", "CustomPreference", "SetConcertServerURL", 1 ); - auto api_value = il2cpp_symbols::new_string(urls.api_url.c_str()); + auto api_value = g_cached_api_url_string; if (set_application_addr && api_value) { reinterpret_cast(set_application_addr)(api_value, nullptr); hook_log("[cgss-dmm-hook] applied Cute.CustomPreference.SetApplicationServerURL"); @@ -286,7 +138,7 @@ namespace { auto set_resource_addr = il2cpp_symbols::get_method_pointer( "Assembly-CSharp.dll", "Cute", "CustomPreference", "SetResourceServerURL", 1 ); - auto asset_value = il2cpp_symbols::new_string(urls.asset_url.c_str()); + auto asset_value = g_cached_asset_url_string; if (set_resource_addr && asset_value) { reinterpret_cast(set_resource_addr)(asset_value, nullptr); hook_log("[cgss-dmm-hook] applied Cute.CustomPreference.SetResourceServerURL"); @@ -324,55 +176,28 @@ namespace { hook_log("[cgss-dmm-hook] il2cpp exports ready"); } - patch_custom_preference_scheme(); + if (config::get().force_http) { + patch_custom_preference_scheme(); + } + const auto& urls = config::get(); + if (!urls.api_url.empty() || !urls.asset_url.empty()) { + prepare_cached_override_strings(); + apply_custom_preference_url_overrides(); + } - auto addr = il2cpp_symbols::get_method_pointer( - "Assembly-CSharp.dll", "Stage", "NetworkUtil", "GetSchemeType", 0 - ); - if (!addr) { - hook_log("[cgss-dmm-hook] failed to resolve Stage.NetworkUtil.GetSchemeType"); + if (!urls.force_http) { + InterlockedExchange(&g_hook_installed, 1); + hook_log("[cgss-dmm-hook] force_http disabled, keeping original scheme"); return; } - auto get_application_server_url_addr = il2cpp_symbols::get_method_pointer( - "Assembly-CSharp.dll", "Stage", "NetworkUtil", "GetApplicationServerUrl", 0 - ); - auto get_tele_scope_server_url_addr = il2cpp_symbols::get_method_pointer( - "Assembly-CSharp.dll", "Stage", "NetworkUtil", "GetTeleScopeServerUrl", 0 - ); - auto get_concert_server_url_addr = il2cpp_symbols::get_method_pointer( - "Assembly-CSharp.dll", "Stage", "NetworkUtil", "GetConcertServerUrl", 0 - ); - auto get_resource_server_url_addr = il2cpp_symbols::get_method_pointer( - "Assembly-CSharp.dll", "Stage", "NetworkUtil", "GetResourceServerUrl", 0 - ); - auto cp_get_application_server_url_addr = il2cpp_symbols::get_method_pointer( - "Assembly-CSharp.dll", "Cute", "CustomPreference", "GetApplicationServerURL", 0 - ); - auto cp_get_tele_scope_server_url_addr = il2cpp_symbols::get_method_pointer( - "Assembly-CSharp.dll", "Cute", "CustomPreference", "GetTeleScopeServerURL", 0 - ); - auto cp_get_concert_server_url_addr = il2cpp_symbols::get_method_pointer( - "Assembly-CSharp.dll", "Cute", "CustomPreference", "GetConcertServerURL", 0 - ); - auto cp_get_resource_server_url_addr = il2cpp_symbols::get_method_pointer( - "Assembly-CSharp.dll", "Cute", "CustomPreference", "GetResourceServerURL", 0 - ); - auto cp_set_application_server_url_addr = il2cpp_symbols::get_method_pointer( - "Assembly-CSharp.dll", "Cute", "CustomPreference", "SetApplicationServerURL", 1 - ); - auto cp_set_tele_scope_server_url_addr = il2cpp_symbols::get_method_pointer( - "Assembly-CSharp.dll", "Cute", "CustomPreference", "SetTeleScopeServerURL", 1 - ); - auto cp_set_concert_server_url_addr = il2cpp_symbols::get_method_pointer( - "Assembly-CSharp.dll", "Cute", "CustomPreference", "SetConcertServerURL", 1 - ); - auto cp_set_resource_server_url_addr = il2cpp_symbols::get_method_pointer( - "Assembly-CSharp.dll", "Cute", "CustomPreference", "SetResourceServerURL", 1 - ); - auto cp_set_scheme_mode_addr = il2cpp_symbols::get_method_pointer( - "Assembly-CSharp.dll", "Cute", "CustomPreference", "SetScemeMode", 1 + auto get_scheme_type_addr = il2cpp_symbols::get_method_pointer( + "Assembly-CSharp.dll", "Stage", "NetworkUtil", "GetSchemeType", 0 ); + if (!get_scheme_type_addr) { + hook_log("[cgss-dmm-hook] failed to resolve Stage.NetworkUtil.GetSchemeType"); + return; + } auto mh_status = MH_Initialize(); if (mh_status != MH_OK && mh_status != MH_ERROR_ALREADY_INITIALIZED) { @@ -380,126 +205,24 @@ namespace { return; } - const auto& urls = config::get(); - if (urls.force_http) { - auto create_status = MH_CreateHook( - reinterpret_cast(addr), - reinterpret_cast(&get_scheme_type_hook), - reinterpret_cast(&g_orig_get_scheme_type) - ); - if (create_status != MH_OK && create_status != MH_ERROR_ALREADY_CREATED) { - hook_log("[cgss-dmm-hook] MH_CreateHook failed"); - return; - } - - auto enable_status = MH_EnableHook(reinterpret_cast(addr)); - if (enable_status != MH_OK && enable_status != MH_ERROR_ENABLED) { - hook_log("[cgss-dmm-hook] MH_EnableHook failed"); - return; - } - } else { - hook_log("[cgss-dmm-hook] force_http disabled, keeping original scheme"); + auto create_status = MH_CreateHook( + reinterpret_cast(get_scheme_type_addr), + reinterpret_cast(&get_scheme_type_hook), + reinterpret_cast(&g_orig_get_scheme_type) + ); + if (create_status != MH_OK && create_status != MH_ERROR_ALREADY_CREATED) { + hook_log("[cgss-dmm-hook] MH_CreateHook failed"); + return; } - auto hook_method = [](uintptr_t address, void* detour, void** original, const char* name) { - if (!address) { - return; - } - auto create_status = MH_CreateHook(reinterpret_cast(address), detour, original); - if (create_status != MH_OK && create_status != MH_ERROR_ALREADY_CREATED) { - return; - } - auto enable_status = MH_EnableHook(reinterpret_cast(address)); - if (enable_status == MH_OK || enable_status == MH_ERROR_ENABLED) { - hook_logf("[cgss-dmm-hook] hooked %s", name); - } - }; - - hook_method( - get_application_server_url_addr, - reinterpret_cast(&get_application_server_url_hook), - reinterpret_cast(&g_orig_get_application_server_url), - "Stage.NetworkUtil.GetApplicationServerUrl" - ); - hook_method( - get_resource_server_url_addr, - reinterpret_cast(&get_resource_server_url_hook), - reinterpret_cast(&g_orig_get_resource_server_url), - "Stage.NetworkUtil.GetResourceServerUrl" - ); - hook_method( - get_tele_scope_server_url_addr, - reinterpret_cast(&get_tele_scope_server_url_hook), - reinterpret_cast(&g_orig_get_tele_scope_server_url), - "Stage.NetworkUtil.GetTeleScopeServerUrl" - ); - hook_method( - get_concert_server_url_addr, - reinterpret_cast(&get_concert_server_url_hook), - reinterpret_cast(&g_orig_get_concert_server_url), - "Stage.NetworkUtil.GetConcertServerUrl" - ); - hook_method( - cp_get_application_server_url_addr, - reinterpret_cast(&custom_preference_get_application_server_url_hook), - reinterpret_cast(&g_orig_custom_preference_get_application_server_url), - "Cute.CustomPreference.GetApplicationServerURL" - ); - hook_method( - cp_get_tele_scope_server_url_addr, - reinterpret_cast(&custom_preference_get_tele_scope_server_url_hook), - reinterpret_cast(&g_orig_custom_preference_get_tele_scope_server_url), - "Cute.CustomPreference.GetTeleScopeServerURL" - ); - hook_method( - cp_get_concert_server_url_addr, - reinterpret_cast(&custom_preference_get_concert_server_url_hook), - reinterpret_cast(&g_orig_custom_preference_get_concert_server_url), - "Cute.CustomPreference.GetConcertServerURL" - ); - hook_method( - cp_get_resource_server_url_addr, - reinterpret_cast(&custom_preference_get_resource_server_url_hook), - reinterpret_cast(&g_orig_custom_preference_get_resource_server_url), - "Cute.CustomPreference.GetResourceServerURL" - ); - hook_method( - cp_set_application_server_url_addr, - reinterpret_cast(&custom_preference_set_application_server_url_hook), - reinterpret_cast(&g_orig_custom_preference_set_application_server_url), - "Cute.CustomPreference.SetApplicationServerURL" - ); - hook_method( - cp_set_tele_scope_server_url_addr, - reinterpret_cast(&custom_preference_set_tele_scope_server_url_hook), - reinterpret_cast(&g_orig_custom_preference_set_tele_scope_server_url), - "Cute.CustomPreference.SetTeleScopeServerURL" - ); - hook_method( - cp_set_concert_server_url_addr, - reinterpret_cast(&custom_preference_set_concert_server_url_hook), - reinterpret_cast(&g_orig_custom_preference_set_concert_server_url), - "Cute.CustomPreference.SetConcertServerURL" - ); - hook_method( - cp_set_resource_server_url_addr, - reinterpret_cast(&custom_preference_set_resource_server_url_hook), - reinterpret_cast(&g_orig_custom_preference_set_resource_server_url), - "Cute.CustomPreference.SetResourceServerURL" - ); - hook_method( - cp_set_scheme_mode_addr, - reinterpret_cast(&custom_preference_set_scheme_mode_hook), - reinterpret_cast(&g_orig_custom_preference_set_scheme_mode), - "Cute.CustomPreference.SetScemeMode" - ); - - apply_custom_preference_url_overrides(); + auto enable_status = MH_EnableHook(reinterpret_cast(get_scheme_type_addr)); + if (enable_status != MH_OK && enable_status != MH_ERROR_ENABLED) { + hook_log("[cgss-dmm-hook] MH_EnableHook failed"); + return; + } InterlockedExchange(&g_hook_installed, 1); - if (urls.force_http) { - hook_log("[cgss-dmm-hook] hooked Stage.NetworkUtil.GetSchemeType"); - } + hook_log("[cgss-dmm-hook] hooked Stage.NetworkUtil.GetSchemeType"); } DWORD WINAPI init_thread(void*) { diff --git a/src/proxy.cpp b/src/proxy.cpp index 172eb8b..9db6990 100644 --- a/src/proxy.cpp +++ b/src/proxy.cpp @@ -3,36 +3,178 @@ #include "config.hpp" #include "hook.hpp" +namespace { + void load_original_version_dll(); + void ensure_runtime_init_started(); + + template + Result forward_version_export(void*& original, Result failure_result, Args... args) { + if (!original) { + load_original_version_dll(); + } + if (!original) { + SetLastError(ERROR_PROC_NOT_FOUND); + return failure_result; + } + + Result result = reinterpret_cast(original)(args...); + ensure_runtime_init_started(); + return result; + } +} + extern "C" { void* GetFileVersionInfoA_Original = nullptr; + void* GetFileVersionInfoW_Original = nullptr; + void* GetFileVersionInfoExA_Original = nullptr; + void* GetFileVersionInfoExW_Original = nullptr; void* GetFileVersionInfoSizeA_Original = nullptr; + void* GetFileVersionInfoSizeW_Original = nullptr; + void* GetFileVersionInfoSizeExA_Original = nullptr; + void* GetFileVersionInfoSizeExW_Original = nullptr; void* VerQueryValueA_Original = nullptr; + void* VerQueryValueW_Original = nullptr; + void* VerFindFileA_Original = nullptr; + void* VerFindFileW_Original = nullptr; + void* VerInstallFileA_Original = nullptr; + void* VerInstallFileW_Original = nullptr; + void* VerLanguageNameA_Original = nullptr; + void* VerLanguageNameW_Original = nullptr; BOOL WINAPI GetFileVersionInfoA_EXPORT(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData) { using Fn = BOOL(WINAPI*)(LPCSTR, DWORD, DWORD, LPVOID); - if (!GetFileVersionInfoA_Original) { - SetLastError(ERROR_PROC_NOT_FOUND); - return FALSE; - } - return reinterpret_cast(GetFileVersionInfoA_Original)(lptstrFilename, dwHandle, dwLen, lpData); + return forward_version_export( + GetFileVersionInfoA_Original, FALSE, lptstrFilename, dwHandle, dwLen, lpData + ); + } + + BOOL WINAPI GetFileVersionInfoW_EXPORT(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData) { + using Fn = BOOL(WINAPI*)(LPCWSTR, DWORD, DWORD, LPVOID); + return forward_version_export( + GetFileVersionInfoW_Original, FALSE, lptstrFilename, dwHandle, dwLen, lpData + ); + } + + BOOL WINAPI GetFileVersionInfoExA_EXPORT( + DWORD dwFlags, LPCSTR lpwstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData + ) { + using Fn = BOOL(WINAPI*)(DWORD, LPCSTR, DWORD, DWORD, LPVOID); + return forward_version_export( + GetFileVersionInfoExA_Original, FALSE, dwFlags, lpwstrFilename, dwHandle, dwLen, lpData + ); + } + + BOOL WINAPI GetFileVersionInfoExW_EXPORT( + DWORD dwFlags, LPCWSTR lpwstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData + ) { + using Fn = BOOL(WINAPI*)(DWORD, LPCWSTR, DWORD, DWORD, LPVOID); + return forward_version_export( + GetFileVersionInfoExW_Original, FALSE, dwFlags, lpwstrFilename, dwHandle, dwLen, lpData + ); } DWORD WINAPI GetFileVersionInfoSizeA_EXPORT(LPCSTR lptstrFilename, LPDWORD lpdwHandle) { using Fn = DWORD(WINAPI*)(LPCSTR, LPDWORD); - if (!GetFileVersionInfoSizeA_Original) { - SetLastError(ERROR_PROC_NOT_FOUND); - return 0; - } - return reinterpret_cast(GetFileVersionInfoSizeA_Original)(lptstrFilename, lpdwHandle); + return forward_version_export( + GetFileVersionInfoSizeA_Original, 0, lptstrFilename, lpdwHandle + ); + } + + DWORD WINAPI GetFileVersionInfoSizeW_EXPORT(LPCWSTR lptstrFilename, LPDWORD lpdwHandle) { + using Fn = DWORD(WINAPI*)(LPCWSTR, LPDWORD); + return forward_version_export( + GetFileVersionInfoSizeW_Original, 0, lptstrFilename, lpdwHandle + ); + } + + DWORD WINAPI GetFileVersionInfoSizeExA_EXPORT(DWORD dwFlags, LPCSTR lpwstrFilename, LPDWORD lpdwHandle) { + using Fn = DWORD(WINAPI*)(DWORD, LPCSTR, LPDWORD); + return forward_version_export( + GetFileVersionInfoSizeExA_Original, 0, dwFlags, lpwstrFilename, lpdwHandle + ); + } + + DWORD WINAPI GetFileVersionInfoSizeExW_EXPORT(DWORD dwFlags, LPCWSTR lpwstrFilename, LPDWORD lpdwHandle) { + using Fn = DWORD(WINAPI*)(DWORD, LPCWSTR, LPDWORD); + return forward_version_export( + GetFileVersionInfoSizeExW_Original, 0, dwFlags, lpwstrFilename, lpdwHandle + ); } BOOL WINAPI VerQueryValueA_EXPORT(LPCVOID pBlock, LPCSTR lpSubBlock, LPVOID* lplpBuffer, PUINT puLen) { using Fn = BOOL(WINAPI*)(LPCVOID, LPCSTR, LPVOID*, PUINT); - if (!VerQueryValueA_Original) { - SetLastError(ERROR_PROC_NOT_FOUND); - return FALSE; - } - return reinterpret_cast(VerQueryValueA_Original)(pBlock, lpSubBlock, lplpBuffer, puLen); + return forward_version_export( + VerQueryValueA_Original, FALSE, pBlock, lpSubBlock, lplpBuffer, puLen + ); + } + + BOOL WINAPI VerQueryValueW_EXPORT(LPCVOID pBlock, LPCWSTR lpSubBlock, LPVOID* lplpBuffer, PUINT puLen) { + using Fn = BOOL(WINAPI*)(LPCVOID, LPCWSTR, LPVOID*, PUINT); + return forward_version_export( + VerQueryValueW_Original, FALSE, pBlock, lpSubBlock, lplpBuffer, puLen + ); + } + + DWORD WINAPI VerFindFileA_EXPORT( + DWORD uFlags, LPSTR szFileName, LPSTR szWinDir, LPSTR szAppDir, + LPSTR szCurDir, PUINT lpuCurDirLen, LPSTR szDestDir, PUINT lpuDestDirLen + ) { + using Fn = DWORD(WINAPI*)(DWORD, LPSTR, LPSTR, LPSTR, LPSTR, PUINT, LPSTR, PUINT); + return forward_version_export( + VerFindFileA_Original, + 0, + uFlags, szFileName, szWinDir, szAppDir, szCurDir, lpuCurDirLen, szDestDir, lpuDestDirLen + ); + } + + DWORD WINAPI VerFindFileW_EXPORT( + DWORD uFlags, LPWSTR szFileName, LPWSTR szWinDir, LPWSTR szAppDir, + LPWSTR szCurDir, PUINT lpuCurDirLen, LPWSTR szDestDir, PUINT lpuDestDirLen + ) { + using Fn = DWORD(WINAPI*)(DWORD, LPWSTR, LPWSTR, LPWSTR, LPWSTR, PUINT, LPWSTR, PUINT); + return forward_version_export( + VerFindFileW_Original, + 0, + uFlags, szFileName, szWinDir, szAppDir, szCurDir, lpuCurDirLen, szDestDir, lpuDestDirLen + ); + } + + DWORD WINAPI VerInstallFileA_EXPORT( + DWORD uFlags, LPSTR szSrcFileName, LPSTR szDestFileName, LPSTR szSrcDir, + LPSTR szDestDir, LPSTR szCurDir, LPSTR szTmpFile, PUINT lpuTmpFileLen + ) { + using Fn = DWORD(WINAPI*)(DWORD, LPSTR, LPSTR, LPSTR, LPSTR, LPSTR, LPSTR, PUINT); + return forward_version_export( + VerInstallFileA_Original, + 0, + uFlags, szSrcFileName, szDestFileName, szSrcDir, szDestDir, szCurDir, szTmpFile, lpuTmpFileLen + ); + } + + DWORD WINAPI VerInstallFileW_EXPORT( + DWORD uFlags, LPWSTR szSrcFileName, LPWSTR szDestFileName, LPWSTR szSrcDir, + LPWSTR szDestDir, LPWSTR szCurDir, LPWSTR szTmpFile, PUINT lpuTmpFileLen + ) { + using Fn = DWORD(WINAPI*)(DWORD, LPWSTR, LPWSTR, LPWSTR, LPWSTR, LPWSTR, LPWSTR, PUINT); + return forward_version_export( + VerInstallFileW_Original, + 0, + uFlags, szSrcFileName, szDestFileName, szSrcDir, szDestDir, szCurDir, szTmpFile, lpuTmpFileLen + ); + } + + DWORD WINAPI VerLanguageNameA_EXPORT(DWORD wLang, LPSTR szLang, DWORD nSize) { + using Fn = DWORD(WINAPI*)(DWORD, LPSTR, DWORD); + return forward_version_export( + VerLanguageNameA_Original, 0, wLang, szLang, nSize + ); + } + + DWORD WINAPI VerLanguageNameW_EXPORT(DWORD wLang, LPWSTR szLang, DWORD nSize) { + using Fn = DWORD(WINAPI*)(DWORD, LPWSTR, DWORD); + return forward_version_export( + VerLanguageNameW_Original, 0, wLang, szLang, nSize + ); } } @@ -42,11 +184,19 @@ namespace { constexpr const char* kGameExeName = "imascgstage.exe"; HMODULE g_original = nullptr; volatile LONG g_helper_started = 0; + volatile LONG g_runtime_init_started = 0; + volatile LONG g_process_type = 0; bool is_game_process() { + LONG process_type = InterlockedCompareExchange(&g_process_type, 0, 0); + if (process_type != 0) { + return process_type == 1; + } + char path[MAX_PATH] = {}; DWORD len = GetModuleFileNameA(nullptr, path, MAX_PATH); if (len == 0 || len >= MAX_PATH) { + InterlockedCompareExchange(&g_process_type, -1, 0); return false; } @@ -56,7 +206,9 @@ namespace { base_name = p + 1; } } - return lstrcmpiA(base_name, kGameExeName) == 0; + bool is_game = lstrcmpiA(base_name, kGameExeName) == 0; + InterlockedCompareExchange(&g_process_type, is_game ? 1 : -1, 0); + return is_game; } std::string get_game_directory() { @@ -81,9 +233,13 @@ namespace { return; } - char system_dir[MAX_PATH] = {}; - GetSystemDirectoryA(system_dir, MAX_PATH); char path[MAX_PATH] = {}; + char system_dir[MAX_PATH] = {}; + UINT system_dir_len = GetSystemDirectoryA(system_dir, MAX_PATH); + if (system_dir_len == 0 || system_dir_len >= MAX_PATH) { + hook_log("[cgss-dmm-hook] failed to resolve system directory"); + return; + } lstrcpynA(path, system_dir, MAX_PATH); lstrcatA(path, "\\version.dll"); @@ -94,10 +250,30 @@ namespace { } GetFileVersionInfoA_Original = reinterpret_cast(GetProcAddress(g_original, "GetFileVersionInfoA")); + GetFileVersionInfoW_Original = reinterpret_cast(GetProcAddress(g_original, "GetFileVersionInfoW")); + GetFileVersionInfoExA_Original = reinterpret_cast(GetProcAddress(g_original, "GetFileVersionInfoExA")); + GetFileVersionInfoExW_Original = reinterpret_cast(GetProcAddress(g_original, "GetFileVersionInfoExW")); GetFileVersionInfoSizeA_Original = reinterpret_cast(GetProcAddress(g_original, "GetFileVersionInfoSizeA")); + GetFileVersionInfoSizeW_Original = reinterpret_cast(GetProcAddress(g_original, "GetFileVersionInfoSizeW")); + GetFileVersionInfoSizeExA_Original = reinterpret_cast(GetProcAddress(g_original, "GetFileVersionInfoSizeExA")); + GetFileVersionInfoSizeExW_Original = reinterpret_cast(GetProcAddress(g_original, "GetFileVersionInfoSizeExW")); VerQueryValueA_Original = reinterpret_cast(GetProcAddress(g_original, "VerQueryValueA")); + VerQueryValueW_Original = reinterpret_cast(GetProcAddress(g_original, "VerQueryValueW")); + VerFindFileA_Original = reinterpret_cast(GetProcAddress(g_original, "VerFindFileA")); + VerFindFileW_Original = reinterpret_cast(GetProcAddress(g_original, "VerFindFileW")); + VerInstallFileA_Original = reinterpret_cast(GetProcAddress(g_original, "VerInstallFileA")); + VerInstallFileW_Original = reinterpret_cast(GetProcAddress(g_original, "VerInstallFileW")); + VerLanguageNameA_Original = reinterpret_cast(GetProcAddress(g_original, "VerLanguageNameA")); + VerLanguageNameW_Original = reinterpret_cast(GetProcAddress(g_original, "VerLanguageNameW")); - if (!GetFileVersionInfoA_Original || !GetFileVersionInfoSizeA_Original || !VerQueryValueA_Original) { + if (!GetFileVersionInfoA_Original || !GetFileVersionInfoW_Original || + !GetFileVersionInfoExA_Original || !GetFileVersionInfoExW_Original || + !GetFileVersionInfoSizeA_Original || !GetFileVersionInfoSizeW_Original || + !GetFileVersionInfoSizeExA_Original || !GetFileVersionInfoSizeExW_Original || + !VerQueryValueA_Original || !VerQueryValueW_Original || + !VerFindFileA_Original || !VerFindFileW_Original || + !VerInstallFileA_Original || !VerInstallFileW_Original || + !VerLanguageNameA_Original || !VerLanguageNameW_Original) { hook_log("[cgss-dmm-hook] failed to resolve version exports"); return; } @@ -164,22 +340,38 @@ namespace { DWORD WINAPI init_thread(void*) { Sleep(kProxyInitDelayMs); if (!is_game_process()) { - load_original_version_dll(); hook_log("[cgss-dmm-hook] non-game process detected, skipping hook/helper startup"); return 0; } config::load(); - load_original_version_dll(); start_borderless_helper(); start_hook_thread(); return 0; } + + void ensure_runtime_init_started() { + if (!is_game_process()) { + return; + } + if (InterlockedCompareExchange(&g_runtime_init_started, 1, 0) != 0) { + return; + } + + HANDLE thread = CreateThread(nullptr, 0, init_thread, nullptr, 0, nullptr); + if (!thread) { + hook_logf( + "[cgss-dmm-hook] failed to create init thread, error=%lu", + static_cast(GetLastError()) + ); + return; + } + CloseHandle(thread); + } } BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID) { if (reason == DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls(module); - CreateThread(nullptr, 0, init_thread, nullptr, 0, nullptr); } return TRUE; } diff --git a/src/version.def b/src/version.def index b9e0cdf..2f1ba5b 100644 --- a/src/version.def +++ b/src/version.def @@ -1,4 +1,17 @@ EXPORTS GetFileVersionInfoA=GetFileVersionInfoA_EXPORT + GetFileVersionInfoW=GetFileVersionInfoW_EXPORT + GetFileVersionInfoExA=GetFileVersionInfoExA_EXPORT + GetFileVersionInfoExW=GetFileVersionInfoExW_EXPORT GetFileVersionInfoSizeA=GetFileVersionInfoSizeA_EXPORT + GetFileVersionInfoSizeW=GetFileVersionInfoSizeW_EXPORT + GetFileVersionInfoSizeExA=GetFileVersionInfoSizeExA_EXPORT + GetFileVersionInfoSizeExW=GetFileVersionInfoSizeExW_EXPORT VerQueryValueA=VerQueryValueA_EXPORT + VerQueryValueW=VerQueryValueW_EXPORT + VerFindFileA=VerFindFileA_EXPORT + VerFindFileW=VerFindFileW_EXPORT + VerInstallFileA=VerInstallFileA_EXPORT + VerInstallFileW=VerInstallFileW_EXPORT + VerLanguageNameA=VerLanguageNameA_EXPORT + VerLanguageNameW=VerLanguageNameW_EXPORT