From 1ba84753aa2375acb1e77e3008206969e2eb1809 Mon Sep 17 00:00:00 2001 From: acidicoala <67734819+acidicoala@users.noreply.github.com> Date: Fri, 30 Dec 2022 05:51:07 +0300 Subject: [PATCH] Added `IClientUser_IsSubscribedApp` --- CMakeLists.txt | 2 +- src/koalageddon/steamclient.cpp | 90 +++++++++++++++++------- src/smoke_api/smoke_api.hpp | 32 ++++++++- src/steamclient_virtuals/client_user.cpp | 1 - 4 files changed, 95 insertions(+), 30 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 25b10b2..ea05f41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.24) -project(SmokeAPI VERSION 1.0.3) +project(SmokeAPI VERSION 1.1.0) include(KoalaBox/cmake/KoalaBox.cmake) diff --git a/src/koalageddon/steamclient.cpp b/src/koalageddon/steamclient.cpp index ac0570c..7a29023 100644 --- a/src/koalageddon/steamclient.cpp +++ b/src/koalageddon/steamclient.cpp @@ -5,46 +5,82 @@ using namespace smoke_api; +void hook_function( + const void* interface_address, + const FunctionAddress& hook_function, + const String& name, + const int ordinal +) { + static Set hooked_functions; + + if (interface_address == nullptr) { + return; + } + + if (hooked_functions.contains(name)) { + return; + } + + hook::swap_virtual_func_or_throw(interface_address, name, ordinal, hook_function); + + hooked_functions.insert(name); +} + DLL_EXPORT(void) SteamClient_Interface_Interceptor(const char* interface_name, const char* function_name) { try { void**** parent_ebp; - __asm mov parent_ebp, ebp - auto* interface_address = (*parent_ebp)[2]; - - static Set hooked_functions; - - auto hook_function = [&](const auto hook_function, const String& name, const int ordinal) { - if (hooked_functions.contains(name)) { - return; - } - - hook::swap_virtual_func_or_throw(interface_address, name, ordinal, (FunctionAddress) (hook_function)); - - hooked_functions.insert(name); - }; + const auto offset_one = koalageddon_config.steamclient_interceptor_function_address_offset_one; + auto offset_two = koalageddon_config.steamclient_interceptor_function_address_offset_two; const auto compound_name = interface_name + String("::") + function_name; -#define HOOK(FUNC, ORDINAL) hook_function(FUNC, #FUNC, ORDINAL); - // TODO: Parametrize ordinals +// logger->trace("Intercepted interface function: '{}'", compound_name); + +#define HOOK_INTERFACE(FUNC) hook_function( \ + parent_ebp[offset_one][offset_two], \ + (FunctionAddress) FUNC, \ + #FUNC, \ + koalageddon_config.FUNC##_ordinal \ +); + if (util::strings_are_equal(interface_name, "IClientAppManager")) { - HOOK(IClientAppManager_IsAppDlcInstalled, 8) + HOOK_INTERFACE(IClientAppManager_IsAppDlcInstalled) + // TODO: Investigate IClientAppManager::BIsDlcEnabled + // TODO: Investigate IClientAppManager::GetDlcSizes + // TODO: Investigate IClientAppManager::GetInstalledApps } else if (util::strings_are_equal(interface_name, "IClientApps")) { - HOOK(IClientApps_GetDLCCount, 8) - HOOK(IClientApps_BGetDLCDataByIndex, 9) + HOOK_INTERFACE(IClientApps_GetDLCCount) + HOOK_INTERFACE(IClientApps_BGetDLCDataByIndex) + // TODO: Investigate IClientApps::GetAppKVRaw + // TODO: Investigate IClientApps::GetAppDataSection + // TODO: Investigate IClientApps::GetAppData } else if (util::strings_are_equal(interface_name, "IClientInventory")) { - HOOK(IClientInventory_GetResultStatus, 0) - HOOK(IClientInventory_GetResultItems, 2) - HOOK(IClientInventory_GetResultItemProperty, 3) - HOOK(IClientInventory_CheckResultSteamID, 5) - HOOK(IClientInventory_GetAllItems, 8) - HOOK(IClientInventory_GetItemsByID, 9) - HOOK(IClientInventory_SerializeResult, 6) - HOOK(IClientInventory_GetItemDefinitionIDs, 19) + HOOK_INTERFACE(IClientInventory_GetResultStatus) + HOOK_INTERFACE(IClientInventory_GetResultItems) + HOOK_INTERFACE(IClientInventory_GetResultItemProperty) + HOOK_INTERFACE(IClientInventory_CheckResultSteamID) + HOOK_INTERFACE(IClientInventory_GetAllItems) + HOOK_INTERFACE(IClientInventory_GetItemsByID) + HOOK_INTERFACE(IClientInventory_SerializeResult) + HOOK_INTERFACE(IClientInventory_GetItemDefinitionIDs) + } else if (util::strings_are_equal(interface_name, "IClientUser")) { + // NOTE: parent_ebp[offset_one][offset_two] will always be 0 for IClientUser interface. + // Probably because it actually represents a handle with 0 being the default user. + // However, the real interface is still accessible at a neighboring offset. + offset_two = koalageddon_config.steamclient_interceptor_function_address_offset_two_client_user; + + HOOK_INTERFACE(IClientUser_IsSubscribedApp) + // TODO: Investigate IClientUser::GetConfigString + // TODO: Investigate IClientUser::GetConfigStoreKeyName + // TODO: Investigate IClientUser::GetSubscribedApps + // TODO: Investigate IClientUser::GetUserConfigFolder + // TODO: Investigate IClientUser::GetAppIDForGameID } + // TODO: Investigate IClientDeviceAuth::GetSharedLibraryLockedBy? + GET_ORIGINAL_FUNCTION(SteamClient_Interface_Interceptor) SteamClient_Interface_Interceptor_o(interface_name, function_name); } catch (const Exception& ex) { diff --git a/src/smoke_api/smoke_api.hpp b/src/smoke_api/smoke_api.hpp index e10b1bc..c33001e 100644 --- a/src/smoke_api/smoke_api.hpp +++ b/src/smoke_api/smoke_api.hpp @@ -33,6 +33,21 @@ namespace smoke_api { uint32_t callback_address_offset = 20; uint32_t callback_data_offset = 0; uint32_t callback_name_offset = 4; + uint32_t steamclient_interceptor_function_address_offset_one = 0; + uint32_t steamclient_interceptor_function_address_offset_two = 2; + uint32_t steamclient_interceptor_function_address_offset_two_client_user = 5; + uint32_t IClientAppManager_IsAppDlcInstalled_ordinal = 8; + uint32_t IClientApps_GetDLCCount_ordinal = 8; + uint32_t IClientApps_BGetDLCDataByIndex_ordinal = 9; + uint32_t IClientInventory_GetResultStatus_ordinal = 0; + uint32_t IClientInventory_GetResultItems_ordinal = 2; + uint32_t IClientInventory_GetResultItemProperty_ordinal = 3; + uint32_t IClientInventory_CheckResultSteamID_ordinal = 5; + uint32_t IClientInventory_GetAllItems_ordinal = 8; + uint32_t IClientInventory_GetItemsByID_ordinal = 9; + uint32_t IClientInventory_SerializeResult_ordinal = 6; + uint32_t IClientInventory_GetItemDefinitionIDs_ordinal = 19; + uint32_t IClientUser_IsSubscribedApp_ordinal = 191; // We do not use *_WITH_DEFAULT macro to ensure that overriding // the koalageddon config requires definition of all keys @@ -42,7 +57,22 @@ namespace smoke_api { callback_interceptor_address_offset, callback_address_offset, callback_data_offset, - callback_name_offset + callback_name_offset, + steamclient_interceptor_function_address_offset_one, + steamclient_interceptor_function_address_offset_two, + steamclient_interceptor_function_address_offset_two_client_user, + IClientAppManager_IsAppDlcInstalled_ordinal, + IClientApps_GetDLCCount_ordinal, + IClientApps_BGetDLCDataByIndex_ordinal, + IClientInventory_GetResultStatus_ordinal, + IClientInventory_GetResultItems_ordinal, + IClientInventory_GetResultItemProperty_ordinal, + IClientInventory_CheckResultSteamID_ordinal, + IClientInventory_GetAllItems_ordinal, + IClientInventory_GetItemsByID_ordinal, + IClientInventory_SerializeResult_ordinal, + IClientInventory_GetItemDefinitionIDs_ordinal, + IClientUser_IsSubscribedApp_ordinal ) }; diff --git a/src/steamclient_virtuals/client_user.cpp b/src/steamclient_virtuals/client_user.cpp index 6ff1d42..2b994c2 100644 --- a/src/steamclient_virtuals/client_user.cpp +++ b/src/steamclient_virtuals/client_user.cpp @@ -3,7 +3,6 @@ using namespace smoke_api; -// TODO: Hook? VIRTUAL(bool) IClientUser_IsSubscribedApp(PARAMS(AppId_t app_id)) { // NOLINT(misc-unused-parameters) return steam_apps::IsDlcUnlocked(__func__, 0, app_id); }