From 3978006e12d5e6226729181f13b2eae2a8195402 Mon Sep 17 00:00:00 2001 From: acidicoala <67734819+acidicoala@users.noreply.github.com> Date: Tue, 19 Aug 2025 00:40:42 +0500 Subject: [PATCH] Fixed build errors --- .idea/dictionaries/project.xml | 1 + CMakeLists.txt | 5 + KoalaBox | 2 +- src/common/steamclient_exports.cpp | 3 +- src/core/types.hpp | 4 +- src/game_mode/exports/steam_api.cpp | 14 +- src/game_mode/exports/steam_api_flat.cpp | 4 +- src/game_mode/exports/steam_api_internal.cpp | 1 + .../exports/steam_api_unversioned.cpp | 13 +- src/smoke_api/smoke_api.cpp | 4 +- src/steam_impl/steam_apps.cpp | 14 +- src/store_mode/steamclient/client_user.cpp | 2 +- src/store_mode/steamclient/steamclient.cpp | 257 +++++++++++------- src/store_mode/store.cpp | 102 ++++--- src/store_mode/store_api.cpp | 2 +- src/store_mode/store_cache.cpp | 6 +- src/store_mode/vstdlib/vstdlib.cpp | 6 +- 17 files changed, 257 insertions(+), 183 deletions(-) diff --git a/.idea/dictionaries/project.xml b/.idea/dictionaries/project.xml index 6c4624c..9efa2c9 100644 --- a/.idea/dictionaries/project.xml +++ b/.idea/dictionaries/project.xml @@ -5,6 +5,7 @@ indicies koalabox koaloader + wstr \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index ad17912..1a52075 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,6 +93,11 @@ endif () add_library(SmokeAPI SHARED ${SMOKE_API_SOURCES} ${VERSION_RESOURCE}) +# There is a weird bug where c++23 features are not enabled in x64 builds, +# while they are available in x86. I've no idea what causes this discrepancy, +# but manually setting the MSVC compiler option fixes this issue. +target_compile_options(SmokeAPI PRIVATE /std:c++latest) + configure_linker_exports( TARGET SmokeAPI FORWARDED_DLL "${STEAMAPI_DLL}_o" diff --git a/KoalaBox b/KoalaBox index afb0998..63837c4 160000 --- a/KoalaBox +++ b/KoalaBox @@ -1 +1 @@ -Subproject commit afb09983ca0384e404fd79d0e52c97ae4a95aff3 +Subproject commit 63837c420c5e972f254b1630316d96186f5b96ef diff --git a/src/common/steamclient_exports.cpp b/src/common/steamclient_exports.cpp index a6c1be3..d5fab59 100644 --- a/src/common/steamclient_exports.cpp +++ b/src/common/steamclient_exports.cpp @@ -1,9 +1,10 @@ +#include #include #include DLL_EXPORT(void*) CreateInterface(const char* interface_string, int* out_result) { return steam_client::GetGenericInterface( - __func__, interface_string, [&]() { + __func__, interface_string, [&] { GET_ORIGINAL_HOOKED_FUNCTION(CreateInterface) return CreateInterface_o(interface_string, out_result); diff --git a/src/core/types.hpp b/src/core/types.hpp index 7e8438b..0217a4e 100644 --- a/src/core/types.hpp +++ b/src/core/types.hpp @@ -1,8 +1,8 @@ #pragma once -#include #include -#include +// ReSharper disable once CppUnusedIncludeDirective +#include // Used by several macros #include #include diff --git a/src/game_mode/exports/steam_api.cpp b/src/game_mode/exports/steam_api.cpp index 3ec612b..83e3ea3 100644 --- a/src/game_mode/exports/steam_api.cpp +++ b/src/game_mode/exports/steam_api.cpp @@ -1,17 +1,5 @@ #include - - -// DLL_EXPORT(void) SteamAPI_Shutdown1() { -// LOG_INFO("{} -> Game requested shutdown", __func__); -// -// ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_Shutdown)(); -// } - -/*DLL_EXPORT(void) SteamAPI_Shutdown2() { - LOG_INFO("{} -> Game requested shutdown", __func__); - - ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_Shutdown)(); -}*/ +#include // TODO: Detour in hook mode DLL_EXPORT(bool) SteamAPI_RestartAppIfNecessary( diff --git a/src/game_mode/exports/steam_api_flat.cpp b/src/game_mode/exports/steam_api_flat.cpp index 3fe5e45..fabe006 100644 --- a/src/game_mode/exports/steam_api_flat.cpp +++ b/src/game_mode/exports/steam_api_flat.cpp @@ -1,9 +1,11 @@ +#include + +#include #include #include #include #include #include -#include // ISteamApps diff --git a/src/game_mode/exports/steam_api_internal.cpp b/src/game_mode/exports/steam_api_internal.cpp index fad9d51..9a58eb0 100644 --- a/src/game_mode/exports/steam_api_internal.cpp +++ b/src/game_mode/exports/steam_api_internal.cpp @@ -1,3 +1,4 @@ +#include #include DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(HSteamUser hSteamUser, const char* version) { diff --git a/src/game_mode/exports/steam_api_unversioned.cpp b/src/game_mode/exports/steam_api_unversioned.cpp index 2c5eb5a..e628c7d 100644 --- a/src/game_mode/exports/steam_api_unversioned.cpp +++ b/src/game_mode/exports/steam_api_unversioned.cpp @@ -1,8 +1,11 @@ -#include +#include + #include #include #include -#include + +#include +#include /** * Searches the `.rdata` section of the original dll for the full interface version string @@ -40,7 +43,7 @@ DLL_EXPORT(void*) SteamClient() { static auto version = get_versioned_interface(STEAM_CLIENT, "006"); return steam_client::GetGenericInterface( - __func__, version, [&]() { + __func__, version, [&] { GET_ORIGINAL_FUNCTION_STEAMAPI(SteamClient) return SteamClient_o(); @@ -64,7 +67,7 @@ DLL_EXPORT(void*) SteamUser() { static auto version = get_versioned_interface(STEAM_USER, "012"); return steam_client::GetGenericInterface( - __func__, version, [&]() { + __func__, version, [&] { GET_ORIGINAL_FUNCTION_STEAMAPI(SteamUser) return SteamUser_o(); @@ -76,7 +79,7 @@ DLL_EXPORT(void*) SteamInventory() { static auto version = get_versioned_interface(STEAM_INVENTORY, "001"); return steam_client::GetGenericInterface( - __func__, version, [&]() { + __func__, version, [&] { GET_ORIGINAL_FUNCTION_STEAMAPI(SteamInventory) return SteamInventory_o(); diff --git a/src/smoke_api/smoke_api.cpp b/src/smoke_api/smoke_api.cpp index 2daa2f3..1373c41 100644 --- a/src/smoke_api/smoke_api.cpp +++ b/src/smoke_api/smoke_api.cpp @@ -80,8 +80,8 @@ namespace { return false; } - // Verify that it's steam from valve, and not some other executable coincidentally named - // steam + // Verify that it's steam from valve, + // and not some other executable coincidentally named steam const HMODULE steam_handle = koalabox::win_util::get_module_handle_or_throw(nullptr); const auto manifest = koalabox::win_util::get_module_manifest(steam_handle); diff --git a/src/steam_impl/steam_apps.cpp b/src/steam_impl/steam_apps.cpp index 29a82c2..209d3fc 100644 --- a/src/steam_impl/steam_apps.cpp +++ b/src/steam_impl/steam_apps.cpp @@ -6,7 +6,7 @@ #include #include -namespace steam_apps { +namespace { /// Steamworks may max GetDLCCount value at 64, depending on how much unowned DLCs the user has. /// Despite this limit, some games with more than 64 DLCs still keep using this method. /// This means we have to get extra DLC IDs from local config, remote config, or cache. @@ -43,9 +43,10 @@ namespace steam_apps { // by aggregating results from all the sources into a single set. Vector aggregated_dlcs; - const auto append_dlcs = [&](const Vector& source, const String& source_name) { - LOG_DEBUG("App ID {} has {} DLCs defined in {}", app_id, source.size(), source_name); - aggregated_dlcs < append > source; + const auto append_dlcs = [&](const Vector& dlc_list, const String& source_name) { + LOG_DEBUG("App ID {} has {} DLCs defined in {}", app_id, dlc_list.size(), source_name); + // Append DLCs to aggregated DLCs + std::ranges::copy(dlc_list, std::back_inserter(aggregated_dlcs)); }; append_dlcs(smoke_api::config::get_extra_dlcs(app_id), "local config"); @@ -71,6 +72,9 @@ namespace steam_apps { smoke_api::app_cache::save_dlcs(app_id, aggregated_dlcs); } +} + +namespace steam_apps { bool IsDlcUnlocked( const String& function_name, @@ -114,7 +118,7 @@ namespace steam_apps { return total_count(static_cast(app_dlcs[app_id].size())); } catch (const Exception& e) { - LOG_ERROR(" Uncaught exception: {}", function_name, e.what()); + LOG_ERROR("Uncaught exception: {}", function_name, e.what()); return 0; } } diff --git a/src/store_mode/steamclient/client_user.cpp b/src/store_mode/steamclient/client_user.cpp index 52c4ef6..8adfa65 100644 --- a/src/store_mode/steamclient/client_user.cpp +++ b/src/store_mode/steamclient/client_user.cpp @@ -13,7 +13,7 @@ VIRTUAL(bool) IClientUser_BIsSubscribedApp(PARAMS(AppId_t dlc_id)) { return IClientUser_BIsSubscribedApp_o(ARGS(dlc_id)); }); } catch (const Exception& e) { - LOG_ERROR("{} -> Error: {}", __func__, e.what()) + LOG_ERROR("{} -> Error: {}", __func__, e.what()); return false; } } diff --git a/src/store_mode/steamclient/steamclient.cpp b/src/store_mode/steamclient/steamclient.cpp index 0478ccb..5b5e563 100644 --- a/src/store_mode/steamclient/steamclient.cpp +++ b/src/store_mode/steamclient/steamclient.cpp @@ -1,11 +1,11 @@ -#include -#include #include #include #include +#include +#include -#include #include +#include namespace store::steamclient { using namespace koalabox; @@ -31,6 +31,7 @@ namespace store::steamclient { uintptr_t start_address ); + // clang-format off #define CONSTRUCT_ORDINAL_MAP(INTERFACE) \ construct_ordinal_map(#INTERFACE, ordinal_map[#INTERFACE], function_selector_address); @@ -38,11 +39,11 @@ namespace store::steamclient { interface, \ #INTERFACE"_"#FUNC, \ ordinal_map[#INTERFACE][#FUNC], \ - reinterpret_cast(INTERFACE##_##FUNC) \ + reinterpret_cast(INTERFACE## _## FUNC) \ ); #define SELECTOR_IMPLEMENTATION(INTERFACE, FUNC_BODY) \ - DLL_EXPORT(void) INTERFACE##_Selector( \ + DLL_EXPORT(void) INTERFACE## _Selector( \ void* interface, \ void* arg2, \ void* arg3, \ @@ -52,8 +53,8 @@ namespace store::steamclient { interface_name_to_address_map[#INTERFACE] = interface; \ [&]()FUNC_BODY(); \ }) \ - GET_ORIGINAL_HOOKED_FUNCTION(INTERFACE##_Selector) \ - INTERFACE##_Selector_o(interface, arg2, arg3, arg4); \ + GET_ORIGINAL_HOOKED_FUNCTION(INTERFACE## _Selector) \ + INTERFACE## _Selector_o(interface, arg2, arg3, arg4); \ } SELECTOR_IMPLEMENTATION(IClientAppManager, { @@ -87,10 +88,12 @@ namespace store::steamclient { #define DETOUR_SELECTOR(INTERFACE) \ if(interface_name == #INTERFACE){ \ CONSTRUCT_ORDINAL_MAP(INTERFACE) \ - DETOUR_ADDRESS(INTERFACE##_Selector, function_selector_address) \ + DETOUR_ADDRESS(INTERFACE## _Selector, function_selector_address) \ } + // clang-format on - void detour_interface_selector(const String& interface_name, uintptr_t function_selector_address) { + void + detour_interface_selector(const String& interface_name, uintptr_t function_selector_address) { LOG_DEBUG("Detected interface: '{}'", interface_name); DETOUR_SELECTOR(IClientAppManager) @@ -100,8 +103,12 @@ namespace store::steamclient { DETOUR_SELECTOR(IClientUtils) } - uintptr_t get_absolute_address(ZydisDecodedInstruction instruction, uintptr_t address) { - const auto operand = instruction.operands[0]; + uintptr_t get_absolute_address( + const ZydisDecodedInstruction instruction, // + const ZydisDecodedOperand operands[], // + const uintptr_t address + ) { + const auto operand = operands[0]; if (operand.imm.is_relative) { ZyanU64 absolute_address; @@ -110,11 +117,14 @@ namespace store::steamclient { return absolute_address; } - return (uintptr_t) operand.imm.value.u; + return (uintptr_t)operand.imm.value.u; } - bool is_push_immediate(const ZydisDecodedInstruction& instruction) { - const auto& operand = instruction.operands[0]; + bool is_push_immediate( + const ZydisDecodedInstruction& instruction, // + const ZydisDecodedOperand operands[] + ) { + const auto& operand = operands[0]; return instruction.mnemonic == ZYDIS_MNEMONIC_PUSH && operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE && @@ -122,8 +132,11 @@ namespace store::steamclient { operand.encoding == ZYDIS_OPERAND_ENCODING_SIMM16_32_32; } - std::optional get_string_argument(const ZydisDecodedInstruction& instruction) { - const auto* name_address = reinterpret_cast(instruction.operands[0].imm.value.u); + std::optional get_string_argument( + const ZydisDecodedInstruction& instruction, // + const ZydisDecodedOperand operands[] + ) { + const auto* name_address = reinterpret_cast(operands[0].imm.value.u); if (util::is_valid_pointer(name_address)) { return name_address; } @@ -132,20 +145,22 @@ namespace store::steamclient { std::optional get_instruction_string( const ZydisDecodedInstruction& instruction, + const ZydisDecodedOperand operands[], const uintptr_t address ) { const auto buffer_size = 64; char buffer[buffer_size] = {}; - if (ZYAN_SUCCESS( - ZydisFormatterFormatInstruction( + if (ZYAN_SUCCESS(ZydisFormatterFormatInstruction( &formatter, &instruction, + operands, + instruction.operand_count, buffer, buffer_size, - address - ) - )) { + address, + ZYAN_NULL + ))) { return buffer; } @@ -155,16 +170,18 @@ namespace store::steamclient { std::optional find_interface_name(uintptr_t selector_address) { auto current_address = selector_address; ZydisDecodedInstruction instruction{}; - while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer( - &decoder, - (void*) current_address, - MAX_INSTRUCTION_SIZE, - &instruction + ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT]; + while (ZYAN_SUCCESS(ZydisDecoderDecodeFull( + &decoder, // decoder + reinterpret_cast(current_address), // buffer + MAX_INSTRUCTION_SIZE, // length + &instruction, // instruction + operands // operands ))) { - const auto debug_str = get_instruction_string(instruction, current_address); + // const auto debug_str = get_instruction_string(instruction, current_address); - if (is_push_immediate(instruction)) { - auto string_opt = get_string_argument(instruction); + if (is_push_immediate(instruction, operands)) { + auto string_opt = get_string_argument(instruction, operands); if (string_opt && string_opt->starts_with("IClient")) { return string_opt; @@ -181,24 +198,29 @@ namespace store::steamclient { return std::nullopt; } + struct full_instruction { + const ZydisDecodedInstruction instruction; + const std::vector operands; + }; + /** * Recursively walks through the code, until a return instruction is reached. * Recursion occurs whenever a jump/branch is encountered. */ template void visit_code( // NOLINT(misc-no-recursion) - Set& visited_addresses, + std::set& visited_addresses, uintptr_t start_address, T context, - const Function& instruction_list + const std::list& instruction_list )>& callback ) { - LOG_TRACE("{} -> start_address: {}", __func__, (void*) start_address); + LOG_TRACE("{} -> start_address: {}", __func__, reinterpret_cast(start_address)); if (visited_addresses.contains(start_address)) { LOG_TRACE("Breaking recursion due to visited address"); @@ -206,34 +228,36 @@ namespace store::steamclient { } auto current_address = start_address; - std::list instruction_list{ZydisDecodedInstruction{}}; + std::list instruction_list; ZydisDecodedInstruction instruction{}; - while ( - ZYAN_SUCCESS( - ZydisDecoderDecodeBuffer( - &decoder, - (void*) current_address, - MAX_INSTRUCTION_SIZE, - &instruction - ) - )) { + ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT]; + while (ZYAN_SUCCESS(ZydisDecoderDecodeFull( + &decoder, // decoder + (void*)current_address, // buffer + MAX_INSTRUCTION_SIZE, // length + &instruction, // instructions + operands // operands + ))) { visited_addresses.insert(current_address); + LOG_TRACE( "{} -> visiting {} │ {}", - __func__, (void*) current_address, *get_instruction_string(instruction, current_address) + __func__, + reinterpret_cast(current_address), + *get_instruction_string(instruction, operands, current_address) ); - const auto operand = instruction.operands[0]; - - const auto should_return = callback(instruction, operand, current_address, context, instruction_list); + const auto should_return = + callback(instruction, operands, current_address, context, instruction_list); if (should_return) { return; } if (instruction.meta.category == ZYDIS_CATEGORY_COND_BR) { - const auto jump_taken_destination = get_absolute_address(instruction, current_address); + const auto jump_taken_destination = + get_absolute_address(instruction, operands, current_address); const auto jump_not_taken_destination = current_address + instruction.length; visit_code(visited_addresses, jump_taken_destination, context, callback); @@ -243,24 +267,28 @@ namespace store::steamclient { return; } - if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP && operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE) { - const auto jump_destination = get_absolute_address(instruction, current_address); + const auto& operand = operands[0]; + + if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP && + operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE) { + const auto jump_destination = + get_absolute_address(instruction, operands, current_address); visit_code(visited_addresses, jump_destination, context, callback); - LOG_TRACE("{} -> Breaking recursion due to an unconditional jump", __func__) + LOG_TRACE("{} -> Breaking recursion due to an unconditional jump", __func__); return; } if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP && operand.type == ZYDIS_OPERAND_TYPE_MEMORY && - operand.mem.scale == sizeof(uintptr_t) && - operand.mem.disp.has_displacement) { - // Special handling for jump tables. Guaranteed to be present in the interface selector. - const auto* table = (uintptr_t*) operand.mem.disp.value; + operand.mem.scale == sizeof(uintptr_t) && operand.mem.disp.has_displacement) { + // Special handling for jump tables. Guaranteed to be present in the interface + // selector. + const auto* table = (uintptr_t*)operand.mem.disp.value; const auto* table_entry = table; - while (util::is_valid_pointer((void*) *table_entry)) { + while (util::is_valid_pointer((void*)*table_entry)) { visit_code(visited_addresses, *table_entry, context, callback); table_entry++; @@ -275,10 +303,16 @@ namespace store::steamclient { return; } - // We push items to the front so that it becomes easy to iterate over instructions // in reverse order of addition. - instruction_list.push_front(instruction); + + std::vector operand_list; + for (auto i = 0U; i < instruction.operand_count; i++) { + operand_list.emplace_back(operands[i]); + } + instruction_list.push_front( + {.instruction = instruction, .operands = std::move(operand_list)} + ); current_address += instruction.length; } } @@ -289,35 +323,39 @@ namespace store::steamclient { uintptr_t start_address ) { Set visited_addresses; - visit_code(visited_addresses, start_address, {}, [&]( - const ZydisDecodedInstruction& instruction, - const ZydisDecodedOperand& operand, + visit_code( + visited_addresses, + start_address, + {}, + [&](const ZydisDecodedInstruction& instruction, + const ZydisDecodedOperand operands[], const auto&, InstructionContext& context, - const std::list& instruction_list - ) { - if (context.function_name && function_name_to_ordinal_map.contains(*context.function_name)) { + const std::list& instruction_list) { + if (context.function_name && + function_name_to_ordinal_map.contains(*context.function_name)) { // Avoid duplicate work return true; } - const auto& last_instruction = instruction_list.front(); + const auto& last = instruction_list.front(); const auto is_mov_base_esp = instruction.mnemonic == ZYDIS_MNEMONIC_MOV && instruction.operand_count == 2 && - instruction.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && - instruction.operands[1].reg.value == ZYDIS_REGISTER_ESP; + operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && + operands[1].reg.value == ZYDIS_REGISTER_ESP; if (!context.base_register && is_mov_base_esp) { // Save base register - context.base_register = instruction.operands[0].reg.value; - } else if (is_push_immediate(last_instruction) && - is_push_immediate(instruction) && - !context.function_name) { + context.base_register = operands[0].reg.value; + } else if ( // + is_push_immediate( last.instruction, last.operands.data() ) && + is_push_immediate(instruction, operands) && !context.function_name) { // The very first 2 consecutive pushes indicate interface and function names. // However, subsequent pushes may contain irrelevant strings. - const auto push_string_1 = get_string_argument(last_instruction); - const auto push_string_2 = get_string_argument(instruction); + const auto push_string_1 = + get_string_argument(last.instruction, last.operands.data()); + const auto push_string_2 = get_string_argument(instruction, operands); if (push_string_1 && push_string_2) { if (*push_string_1 == target_interface) { @@ -326,7 +364,8 @@ namespace store::steamclient { context.function_name = push_string_1; } - if (context.function_name && function_name_to_ordinal_map.contains(*context.function_name)) { + if (context.function_name && + function_name_to_ordinal_map.contains(*context.function_name)) { // Bail early to avoid duplicate work return true; } @@ -338,28 +377,30 @@ namespace store::steamclient { const auto& base_register = *(context.base_register); const auto& function_name = *(context.function_name); - std::optional offset; auto last_destination_reg = ZYDIS_REGISTER_NONE; bool is_derived_from_base_reg = false; + const auto& operand = operands[0]; + // Sometimes the offset is present in the call instruction itself, // hence we can immediately obtain it. - if (operand.type == ZYDIS_OPERAND_TYPE_MEMORY && operand.mem.base != ZYDIS_REGISTER_NONE) { + if (operand.type == ZYDIS_OPERAND_TYPE_MEMORY && + operand.mem.base != ZYDIS_REGISTER_NONE) { offset = static_cast(operand.mem.disp.value); last_destination_reg = operand.mem.base; } else if (operand.type == ZYDIS_OPERAND_TYPE_REGISTER) { last_destination_reg = operand.reg.value; } - for (const auto& previous_instruction: instruction_list) { - const auto& destination_operand = previous_instruction.operands[0]; - const auto& source_operand = previous_instruction.operands[1]; + for (const auto& previous : instruction_list) { + const auto& destination_operand = previous.operands[0]; + const auto& source_operand = previous.operands[1]; // Extract offset if necessary - if (previous_instruction.mnemonic == ZYDIS_MNEMONIC_MOV && - previous_instruction.operand_count == 2 && + if (previous.instruction.mnemonic == ZYDIS_MNEMONIC_MOV && + previous.instruction.operand_count == 2 && destination_operand.reg.value == last_destination_reg && source_operand.type == ZYDIS_OPERAND_TYPE_MEMORY) { @@ -367,8 +408,9 @@ namespace store::steamclient { if (source_mem.base == base_register && source_mem.disp.has_displacement && source_mem.disp.value == 8) { - // We have verified that the chain eventually leads up to the base register. - // Hence, we can conclude that the offset is valid. + // We have verified that the chain eventually leads up to the + // base register. Hence, we can conclude that the offset is + // valid. is_derived_from_base_reg = true; break; } @@ -385,7 +427,12 @@ namespace store::steamclient { if (offset && is_derived_from_base_reg) { const auto ordinal = *offset / sizeof(uintptr_t); - LOG_DEBUG("Found function ordinal {}::{}@{}", target_interface, function_name, ordinal); + LOG_DEBUG( + "Found function ordinal {}::{}@{}", + target_interface, + function_name, + ordinal + ); function_name_to_ordinal_map[function_name] = ordinal; return true; @@ -402,17 +449,21 @@ namespace store::steamclient { const uintptr_t start_address, Set& visited_addresses ) { - visit_code(visited_addresses, start_address, nullptr, []( - const ZydisDecodedInstruction& instruction, - const ZydisDecodedOperand& operand, - const auto& current_address, - auto, - const auto& - ) { - if (instruction.mnemonic == ZYDIS_MNEMONIC_CALL && operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE) { - LOG_TRACE("Found call instruction at {}", (void*) current_address); + visit_code( + visited_addresses, + start_address, + nullptr, + [](const ZydisDecodedInstruction& instruction, + const ZydisDecodedOperand operands[], + const auto& current_address, + auto, + const auto&) { + if (instruction.mnemonic == ZYDIS_MNEMONIC_CALL && + operands[0].type == ZYDIS_OPERAND_TYPE_IMMEDIATE) { + LOG_TRACE("Found call instruction at {}", (void*)current_address); - const auto function_selector_address = get_absolute_address(instruction, current_address); + const auto function_selector_address = + get_absolute_address(instruction, operands, current_address); const auto interface_name_opt = find_interface_name(function_selector_address); @@ -429,16 +480,16 @@ namespace store::steamclient { } void process_client_engine(uintptr_t interface) { - const auto* steam_client_internal = ((uintptr_t***) interface)[ - store::config.client_engine_steam_client_internal_ordinal - ]; - const auto interface_selector_address = (*steam_client_internal)[ - store::config.steam_client_internal_interface_selector_ordinal - ]; + const auto* steam_client_internal = + ((uintptr_t***)interface)[store::config.client_engine_steam_client_internal_ordinal]; + const auto interface_selector_address = (*steam_client_internal + )[store::config.steam_client_internal_interface_selector_ordinal]; - LOG_DEBUG("Found interface selector at: {}", (void*) interface_selector_address); + LOG_DEBUG("Found interface selector at: {}", (void*)interface_selector_address); - if (ZYAN_FAILED(ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_STACK_WIDTH_32))) { + if (ZYAN_FAILED( + ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_STACK_WIDTH_32) + )) { LOG_ERROR("Failed to initialize zydis decoder"); return; } diff --git a/src/store_mode/store.cpp b/src/store_mode/store.cpp index 4d09ab1..fc69f47 100644 --- a/src/store_mode/store.cpp +++ b/src/store_mode/store.cpp @@ -10,14 +10,14 @@ #include #include #include +#include -namespace store { - - StoreConfig config; // NOLINT(cert-err58-cpp) +namespace { + using namespace store; /** - * @return A string representing the source of the config. - */ + * @return A string representing the source of the config. + */ void init_store_config() { const auto print_source = [](const String& source) { LOG_INFO("Loaded Store config from the {}", source); @@ -50,47 +50,62 @@ namespace store { config = {}; } - // Finally, fetch the remote config from GitHub, and inform user about the need to restart Steam, - // if a new config has been fetched - NEW_THREAD({ + // Finally, fetch the remote config from GitHub, and inform user about the need to restart + // Steam, if a new config has been fetched + std::thread([] { try { const auto github_config_opt = api::fetch_store_config(); if (!github_config_opt) { return; } - const auto github_config = *github_config_opt; - store_cache::save_store_config(github_config); - if (github_config == config) { - LOG_DEBUG("Fetched Store config is equal to existing config"); - + (spdlog::default_logger_raw()) + ->log( + spdlog::source_loc{ + "store.cpp", 66, static_cast(__FUNCTION__) + }, + spdlog::level::debug, + "Fetched Store config is equal to existing config" + ); return; } - - LOG_DEBUG("Fetched a new Store config") - - ::MessageBox( + (spdlog::default_logger_raw()) + ->log( + spdlog::source_loc{"store.cpp", 66, static_cast(__FUNCTION__)}, + spdlog::level::debug, + "Fetched a new Store config" + ); + MessageBoxW( nullptr, - TEXT( - "SmokeAPI has downloaded an updated config for Store mode. " - "Please restart Steam in order to apply the new Store config. " - ), - TEXT("SmokeAPI - Store"), - MB_SETFOREGROUND | MB_ICONINFORMATION | MB_OK + L"SmokeAPI has downloaded an updated config for Store mode. " + "Please restart Steam in order to apply the new Store config. ", + L"SmokeAPI - Store", + 0x00010000L | 0x00000040L | 0x00000000L ); } catch (const Exception& ex) { - LOG_ERROR("Failed to get remote store_mode config: {}", ex.what()); + (spdlog::default_logger_raw()) + ->log( + spdlog::source_loc{"store.cpp", 66, static_cast(__FUNCTION__)}, + spdlog::level::err, + "Failed to get remote store_mode config: {}", + ex.what() + ); } - }) + }).detach(); } +} + +namespace store { + StoreConfig config; // NOLINT(cert-err58-cpp) void init_store_mode() { init_store_config(); koalabox::dll_monitor::init_listener( - {VSTDLIB_DLL, STEAMCLIENT_DLL}, [](const HMODULE& module_handle, const String& name) { + {VSTDLIB_DLL, STEAMCLIENT_DLL}, + [](const HMODULE& module_handle, const String& name) { try { if (koalabox::str::eq(name, VSTDLIB_DLL)) { // VStdLib DLL handles Family Sharing functions @@ -108,32 +123,35 @@ namespace store { DETOUR_STEAMCLIENT(CreateInterface) } - if (globals::vstdlib_module != nullptr && globals::steamclient_module != nullptr) { + if (globals::vstdlib_module != nullptr && + globals::steamclient_module != nullptr) { koalabox::dll_monitor::shutdown_listener(); } } catch (const Exception& ex) { LOG_ERROR( "Error listening to DLL load events. Module: '{}', Message: {}", - name, ex.what() + name, + ex.what() ); } } ); - NEW_THREAD({ - koalabox::ipc::init_pipe_server("smokeapi.store.steam", [](const koalabox::ipc::Request& request) { - koalabox::ipc::Response response; - - if (request.name < equals > "config::reload") { - smoke_api::config::ReloadConfig(); - response.success = true; - } else { - response.success = false; - response.data["error_message"] = "Invalid request name: " + request.name; + std::thread([=] { + koalabox::ipc::init_pipe_server( + "smokeapi.store.steam", + [](const koalabox::ipc::Request& request) { + koalabox::ipc::Response response; + if (koalabox::str::eq(request.name, "config::reload")) { + smoke_api::config::ReloadConfig(); + response.success = true; + } else { + response.success = false; + response.data["error_message"] = "Invalid request name: " + request.name; + } + return response; } - - return response; - }); - }) + ); + }).detach(); } } diff --git a/src/store_mode/store_api.cpp b/src/store_mode/store_api.cpp index 7db481c..8da1f81 100644 --- a/src/store_mode/store_api.cpp +++ b/src/store_mode/store_api.cpp @@ -11,7 +11,7 @@ namespace store::api { return kg_config_json.get(); } catch (const Exception& e) { - LOG_ERROR("Failed to fetch Store config from GitHub: {}", e.what()) + LOG_ERROR("Failed to fetch Store config from GitHub: {}", e.what()); return std::nullopt; } } diff --git a/src/store_mode/store_cache.cpp b/src/store_mode/store_cache.cpp index 1faa4f1..7a935dc 100644 --- a/src/store_mode/store_cache.cpp +++ b/src/store_mode/store_cache.cpp @@ -9,7 +9,7 @@ namespace store::store_cache { try { return koalabox::cache::get(KEY_KG_CONFIG, Json(nullptr)).get(); } catch (const Exception& e) { - LOG_ERROR("Failed to get cached store_mode config: {}", e.what()) + LOG_ERROR("Failed to get cached store_mode config: {}", e.what()); return std::nullopt; } @@ -17,11 +17,11 @@ namespace store::store_cache { bool save_store_config(const StoreConfig& config) { try { - LOG_DEBUG("Caching store_mode config") + LOG_DEBUG("Caching store_mode config"); return koalabox::cache::put(KEY_KG_CONFIG, Json(config)); } catch (const Exception& e) { - LOG_ERROR("Failed to cache store_mode config: {}", e.what()) + LOG_ERROR("Failed to cache store_mode config: {}", e.what()); return false; } diff --git a/src/store_mode/vstdlib/vstdlib.cpp b/src/store_mode/vstdlib/vstdlib.cpp index 0c4d694..27bb158 100644 --- a/src/store_mode/vstdlib/vstdlib.cpp +++ b/src/store_mode/vstdlib/vstdlib.cpp @@ -2,13 +2,13 @@ namespace store::vstdlib { VIRTUAL(bool) SharedLicensesLockStatus(PARAMS(void* arg)) { - LOG_DEBUG("{}(this={}, arg={})", __func__, THIS, arg) + LOG_DEBUG("{}(this={}, arg={})", __func__, THIS, arg); ARGS(); return true; } VIRTUAL(bool) SharedLibraryStopPlaying(PARAMS(void* arg)) { - LOG_DEBUG("{}(this={}, arg={})", __func__, THIS, arg) + LOG_DEBUG("{}(this={}, arg={})", __func__, THIS, arg); ARGS(); return true; } @@ -28,7 +28,7 @@ namespace store::vstdlib { if (data && data->get_callback_name()) { const auto name = String(data->get_callback_name()); - LOG_TRACE("{}(ecx={}, edx={}, name='{}')", __func__, ARGS(), name) + LOG_TRACE("{}(ecx={}, edx={}, name='{}')", __func__, ARGS(), name); if (name == "SharedLicensesLockStatus" && !lock_status_hooked) { DETOUR_ADDRESS(SharedLicensesLockStatus, data->get_callback_data()->get_callback_address()) lock_status_hooked = true;