diff --git a/KoalaBox b/KoalaBox index d757148..2e44fec 160000 --- a/KoalaBox +++ b/KoalaBox @@ -1 +1 @@ -Subproject commit d75714857d77790a61d3ef9d27b8afbfa49ccd22 +Subproject commit 2e44fecbe5dbb6709e0dacc1bc66b368a63a69f9 diff --git a/res/SmokeAPI.json b/res/SmokeAPI.json index 697dc95..3ce5bc0 100644 --- a/res/SmokeAPI.json +++ b/res/SmokeAPI.json @@ -6,14 +6,5 @@ "dlc_ids": [], "auto_inject_inventory": true, "inventory_items": [], - "koalageddon_config": { - "interface_interceptor_pattern": "55 8B EC 8B ?? ?? ?? ?? ?? 81 EC ?? ?? ?? ?? 53 FF 15", - "function_ordinal_pattern": "8B 80 ?? ?? ?? ?? FF D0", - "callback_interceptor_address_offset": 1, - "callback_address_offset": 20, - "callback_data_offset": 0, - "callback_name_offset": 4, - "steamclient_interceptor_function_address_offset": 2, - "steamclient_interceptor_function_address_offset_client_user": 5 - } + "koalageddon_config": null } diff --git a/src/koalageddon/koalageddon.cpp b/src/koalageddon/koalageddon.cpp index 3717c1c..a96eb84 100644 --- a/src/koalageddon/koalageddon.cpp +++ b/src/koalageddon/koalageddon.cpp @@ -2,9 +2,6 @@ #include #include #include -#include -#include -#include namespace koalageddon { KoalageddonConfig config = {}; @@ -13,12 +10,13 @@ namespace koalageddon { * @return A string representing the source of the config. */ String init_koalageddon_config() { + try { // First try to read a local config override config = smoke_api::config.koalageddon_config.get(); return "local config override"; } catch (const Exception& ex) { - logger->debug("Local config parse exception: {}", ex.what()); + logger->debug("Local koalageddon config parse exception: {}", ex.what()); } // TODO: Remote source with local cache @@ -35,22 +33,18 @@ namespace koalageddon { logger->info("Loaded Koalageddon config from the {}", kg_config_source); dll_monitor::init({VSTDLIB_DLL, STEAMCLIENT_DLL}, [](const HMODULE& library, const String& name) { - smoke_api::original_library = library; - - if (name == VSTDLIB_DLL) { - // Family Sharing functions - DETOUR_ORIGINAL(Coroutine_Create) - } else if (name == STEAMCLIENT_DLL) { - // Unlocking functions - auto interface_interceptor_address = (FunctionAddress) patcher::find_pattern_address( - win_util::get_module_info(library), - "SteamClient_Interface_Interceptor", - config.interface_interceptor_pattern - ); - - if (interface_interceptor_address) { - DETOUR(SteamClient_Interface_Interceptor, interface_interceptor_address) + try { + smoke_api::original_library = library; + + if (name == VSTDLIB_DLL) { + // VStdLib DLL handles Family Sharing functions + init_vstdlib_hooks(); + } else if (name == STEAMCLIENT_DLL) { + // SteamClient DLL handles unlocking functions + init_steamclient_hooks(); } + } catch (const Exception& ex) { + logger->error("Koalageddon mode dll monitor init error. Module: '{}', Message: {}", name, ex.what()); } }); #endif diff --git a/src/koalageddon/koalageddon.hpp b/src/koalageddon/koalageddon.hpp index 04b616a..700cf7d 100644 --- a/src/koalageddon/koalageddon.hpp +++ b/src/koalageddon/koalageddon.hpp @@ -8,16 +8,16 @@ namespace koalageddon { using namespace koalabox; struct KoalageddonConfig { - String interface_interceptor_pattern = "55 8B EC 8B ?? ?? ?? ?? ?? 81 EC ?? ?? ?? ?? 53 FF 15"; - // Offset values are interpreted according to pointer arithmetic rules, i.e. // 1 unit offset represents 4 and 8 bytes in 32-bit and 64-bit architectures respectively. - uint32_t callback_interceptor_address_offset = 1; - 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 = 2; - uint32_t steamclient_interceptor_function_address_offset_client_user = 5; + uint32_t vstdlib_callback_interceptor_address_offset = 1; + uint32_t vstdlib_callback_address_offset = 20; + uint32_t vstdlib_callback_data_offset = 0; + uint32_t vstdlib_callback_name_offset = 4; + + String steamclient_interface_interceptor_pattern = "55 8B EC 8B ?? ?? ?? ?? ?? 81 EC ?? ?? ?? ?? 53 FF 15"; + String steamclient_interface_demux_pattern = "55 8B EC 83 EC ?? ?? ?? ?? 8B ?? ?? B8 ?? ?? ?? ?? 8B D9"; + uint32_t IClientAppManager_IsAppDlcInstalled_ordinal = 8; uint32_t IClientApps_GetDLCCount_ordinal = 8; uint32_t IClientApps_BGetDLCDataByIndex_ordinal = 9; @@ -35,13 +35,14 @@ namespace koalageddon { // the koalageddon config requires definition of all keys NLOHMANN_DEFINE_TYPE_INTRUSIVE( KoalageddonConfig, // NOLINT(misc-const-correctness) - interface_interceptor_pattern, - callback_interceptor_address_offset, - callback_address_offset, - callback_data_offset, - callback_name_offset, - steamclient_interceptor_function_address_offset, - steamclient_interceptor_function_address_offset_client_user, + vstdlib_callback_interceptor_address_offset, + vstdlib_callback_address_offset, + vstdlib_callback_data_offset, + vstdlib_callback_name_offset, + + steamclient_interface_interceptor_pattern, + steamclient_interface_demux_pattern, + IClientAppManager_IsAppDlcInstalled_ordinal, IClientApps_GetDLCCount_ordinal, IClientApps_BGetDLCDataByIndex_ordinal, @@ -60,9 +61,7 @@ namespace koalageddon { extern KoalageddonConfig config; void init(); -} -typedef uint32_t HCoroutine; - -DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, struct CoroutineData* data); -DLL_EXPORT(void) SteamClient_Interface_Interceptor(const char* interface_name, const char* function_name); + void init_steamclient_hooks(); + void init_vstdlib_hooks(); +} diff --git a/src/koalageddon/steamclient.cpp b/src/koalageddon/steamclient.cpp index 0822c39..839de90 100644 --- a/src/koalageddon/steamclient.cpp +++ b/src/koalageddon/steamclient.cpp @@ -5,10 +5,35 @@ #include #include #include +#include +#include using namespace smoke_api; -/* +#define DEMUX_DECL(INTERFACE) \ + constexpr auto INTERFACE = #INTERFACE; \ + DLL_EXPORT(void) INTERFACE##_Demux(const void*, const void*, const void*, const void*); \ + +DEMUX_DECL(IClientAppManager) +DEMUX_DECL(IClientApps) +DEMUX_DECL(IClientInventory) +DEMUX_DECL(IClientUser) + + +DLL_EXPORT(void) SteamClient_Interface_Interceptor(const char* interface_name, const char* function_name); + +namespace koalageddon { + // Maps interface name to interface pointer + Map interface_name_pointer_map{}; // NOLINT(cert-err58-cpp) + std::mutex map_mutex; + + Set hooked_interfaces; // NOLINT(cert-err58-cpp) + + ZydisDecoder decoder = {}; + + constexpr auto INTERFACE_TARGET_COUNT = 4; + + /* * We need an interface=>function ordinal map in order to hook steam interface function * via virtual function pointer swap. We could construct it by exploiting these code chunks: * @@ -33,128 +58,250 @@ using namespace smoke_api; * which itself is constructed over multiple instruction calls, making it non-deterministic. * Until this roadblock is resolved, automatic detection of ordinals remains non-viable. */ -[[maybe_unused]] Map construct_interface_function_ordinal_map() { - auto* const steamclient_handle = win_util::get_module_handle_or_throw(STEAMCLIENT_DLL); - const auto steamclient_module_info = win_util::get_module_info_or_throw(steamclient_handle); - - auto* byte_pointer = (uint8_t*) steamclient_module_info.lpBaseOfDll; - while (byte_pointer) { - // Search until the end of DLL section - auto rva = (DWORD) byte_pointer - (DWORD) steamclient_module_info.lpBaseOfDll; - - // This pattern needs to be parameterized if this method ever gets implemented. - const String interface_function_chunk_pattern = "8B 01 68 ?? ?? ?? ?? 68"; - - byte_pointer = reinterpret_cast( - patcher::find_pattern_address( - byte_pointer, - steamclient_module_info.SizeOfImage - rva, - "interface=>function chunk", - interface_function_chunk_pattern, - false - ) - ); - - // const auto* interface_name = *reinterpret_cast(byte_pointer + 3); - // const auto* function_name = *reinterpret_cast(byte_pointer + 8); + [[maybe_unused]] Map construct_interface_function_ordinal_map() { + auto* const steamclient_handle = win_util::get_module_handle_or_throw(STEAMCLIENT_DLL); + const auto steamclient_module_info = win_util::get_module_info_or_throw(steamclient_handle); + + auto* byte_pointer = (uint8_t*) steamclient_module_info.lpBaseOfDll; + while (byte_pointer) { + // Search until the end of DLL section + auto rva = (DWORD) byte_pointer - (DWORD) steamclient_module_info.lpBaseOfDll; + + // This pattern needs to be parameterized if this method ever gets implemented. + const String interface_function_chunk_pattern = "8B 01 68 ?? ?? ?? ?? 68"; + + byte_pointer = reinterpret_cast( + patcher::find_pattern_address( + byte_pointer, + steamclient_module_info.SizeOfImage - rva, + "interface=>function chunk", + interface_function_chunk_pattern, + false + ) + ); + + // const auto* interface_name = *reinterpret_cast(byte_pointer + 3); + // const auto* function_name = *reinterpret_cast(byte_pointer + 8); + + byte_pointer += interface_function_chunk_pattern.size(); + byte_pointer += interface_function_chunk_pattern.size(); + + static const auto is_epilogue = [](const uint8_t* instruction_byte) { + const uint8_t epilogue[]{ + 0x8B, 0xE5, // mov esp,ebp + 0x5D, // pop ebp + 0xC3, // ret + }; + + for (auto i = 0; i < sizeof(epilogue); i++) { + if (epilogue[i] != instruction_byte[i]) { + return false; + } + } - byte_pointer += interface_function_chunk_pattern.size(); - byte_pointer += interface_function_chunk_pattern.size(); + return true; + }; - static const auto is_epilogue = [](const uint8_t* instruction_byte) { - const uint8_t epilogue[]{ - 0x8B, 0xE5, // mov esp,ebp - 0x5D, // pop ebp - 0xC3, // ret + static const auto is_call_dword = [](const uint8_t* instruction_byte) { + return instruction_byte[0] == 0xFF && instruction_byte[1] == 0x50; }; - for (auto i = 0; i < sizeof(epilogue); i++) { - if (epilogue[i] != instruction_byte[i]) { - return false; + // static const auto is_call_eax = [](const uint8_t* instruction_byte) { + // return instruction_byte[0] == 0x8B && instruction_byte[1] == 0x40 && + // instruction_byte[3] == 0xFF && instruction_byte[4] == 0xD0; + // }; + + while (!is_epilogue(byte_pointer)) { + if (is_call_dword(byte_pointer)) { + // Find a way to determine offset } + + byte_pointer++; } + } - return true; - }; + return {}; + } - static const auto is_call_dword = [](const uint8_t* instruction_byte) { - return instruction_byte[0] == 0xFF && instruction_byte[1] == 0x50; - }; + FunctionAddress get_absolute_address(ZydisDecodedInstruction instruction, FunctionAddress address) { + const auto op = instruction.operands[0]; - // static const auto is_call_eax = [](const uint8_t* instruction_byte) { - // return instruction_byte[0] == 0x8B && instruction_byte[1] == 0x40 && - // instruction_byte[3] == 0xFF && instruction_byte[4] == 0xD0; - // }; + if (op.imm.is_relative) { + ZyanU64 absolute_address; + ZydisCalcAbsoluteAddress(&instruction, &op, address, &absolute_address); - while (!is_epilogue(byte_pointer)) { - if (is_call_dword(byte_pointer)) { - // Find a way to determine offset - } + return absolute_address; + } - byte_pointer++; + return (FunctionAddress) op.imm.value.u; + } + + const char* find_interface_name(FunctionAddress demux_address) { + auto* instruction_pointer = (uint8_t*) demux_address; + ZydisDecodedInstruction instruction{}; + while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, instruction_pointer, 1024, &instruction))) { + if (instruction.mnemonic == ZYDIS_MNEMONIC_PUSH) { + const auto op = instruction.operands[0]; + + if ( + op.type == ZYDIS_OPERAND_TYPE_IMMEDIATE && + op.visibility == ZYDIS_OPERAND_VISIBILITY_EXPLICIT && + op.encoding == ZYDIS_OPERAND_ENCODING_SIMM16_32_32 + ) { + const auto* name_address = reinterpret_cast(op.imm.value.u); + const auto is_valid = util::is_valid_pointer(name_address); + if (is_valid && String(name_address).starts_with("IClient")) { + return name_address; + } + } + } + instruction_pointer += instruction.length; } + + return nullptr; } - return {}; -} + void init_steamclient_hooks() { + ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_ADDRESS_WIDTH_32); -#define DEFINE_INTERFACE(INTERFACE) constexpr auto INTERFACE = #INTERFACE; + const HMODULE module_handle = win_util::get_module_handle_or_throw(STEAMCLIENT_DLL); + const auto module_info = win_util::get_module_info_or_throw(module_handle); -DEFINE_INTERFACE(IClientAppManager) -DEFINE_INTERFACE(IClientApps) -DEFINE_INTERFACE(IClientInventory) -DEFINE_INTERFACE(IClientUser) + const auto start_address = reinterpret_cast(module_info.lpBaseOfDll); + auto* terminal_address = (uint8_t*) (start_address + module_info.SizeOfImage); + // First, find the interface demux + const auto* interface_demux_address = patcher::find_pattern_address( + module_info, + "interface demux", + config.steamclient_interface_demux_pattern + ); + + // Then iterate over each function demux call + + auto* instruction_pointer = (uint8_t*) interface_demux_address; + ZydisDecodedInstruction previous_instruction{}; + ZydisDecodedInstruction instruction{}; + while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, instruction_pointer, 10, &instruction))) { + if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP && previous_instruction.mnemonic == ZYDIS_MNEMONIC_CALL) { + + // For every such call, extract a function demux address + const auto call_demux_address = (FunctionAddress) ( + instruction_pointer - previous_instruction.length + ); + const auto function_demux_address = get_absolute_address( + previous_instruction, call_demux_address + ); + + if (function_demux_address == 0) { + logger->warn("Failed to extract absolute address of call at {}", (void*) call_demux_address); + } else { + // Then use this address to extract the interface name + const char* interface_name_address = find_interface_name(function_demux_address); + + if (interface_name_address == nullptr) { + logger->warn( + "Failed to extract interface name address of function demux at {}", + (void*) function_demux_address + ); + } else { + const String interface_name((char*) interface_name_address); + + logger->debug("Detected interface: '{}'", interface_name); + + // Finally, hook the demux functions of interest + + if (IClientAppManager == interface_name) { + DETOUR(IClientAppManager_Demux, function_demux_address) + } else if (IClientApps == interface_name) { + DETOUR(IClientApps_Demux, function_demux_address) + } else if (IClientInventory == interface_name) { + DETOUR(IClientInventory_Demux, function_demux_address) + } else if (IClientUser == interface_name) { + DETOUR(IClientUser_Demux, function_demux_address) + } + + // Update the terminal address to limit the search scope only to relevant portion of the code + auto* function_epilogue = (uint8_t*) get_absolute_address( + instruction, (FunctionAddress) instruction_pointer + ); + + if (function_epilogue == nullptr) { + logger->warn( + "Failed to extract absolute address of jmp at {}", + (void*) instruction_pointer + ); + } else { + terminal_address = function_epilogue; + } + } + } + } + + previous_instruction = instruction; + instruction_pointer += instruction.length; + if (instruction_pointer >= terminal_address) { + break; + } + } + + auto interface_interceptor_address = (FunctionAddress) patcher::find_pattern_address( + module_info, + "SteamClient_Interface_Interceptor", + config.steamclient_interface_interceptor_pattern + ); + + if (interface_interceptor_address) { + DETOUR(SteamClient_Interface_Interceptor, interface_interceptor_address) + } + } +} + +/** + * This function intercepts interface name and function names, which we need to determine which functions to hook. + * Unfortunately we can't reliably get interface pointer in this function, hence we need to hook corresponding + * parent demux functions which will contain the interface pointer as the first parameter. + */ DLL_EXPORT(void) SteamClient_Interface_Interceptor(const char* interface_name, const char* function_name) { try { - // logger->trace("Intercepted interface function: '{}::{}'", interface_name, function_name); + const std::lock_guard guard(koalageddon::map_mutex); - static Set hooked_interfaces; + const auto needs_hooking = koalageddon::hooked_interfaces.size() < koalageddon::INTERFACE_TARGET_COUNT; + const auto has_interface_pointer = koalageddon::interface_name_pointer_map.contains(interface_name); - if (hooked_interfaces.size() < 4) { - const void***** current_ebp; - __asm mov current_ebp, ebp + // logger->trace( + // "Intercepted interface function: '{}::{}'", + // interface_name, function_name + // ); - auto* const parent_ebp = *current_ebp; - - const auto* interface_address = parent_ebp[ - util::strings_are_equal(interface_name, IClientUser) - ? koalageddon::config.steamclient_interceptor_function_address_offset_client_user - : koalageddon::config.steamclient_interceptor_function_address_offset - ]; + if (needs_hooking && has_interface_pointer) { + const auto* interface_address = koalageddon::interface_name_pointer_map[interface_name]; const auto hook_if_needed = [&](const String& name, const std::function& block) { - const auto is_target_interface = interface_name == name; - const auto is_hooked = hooked_interfaces.contains(name); + const auto is_hooked = koalageddon::hooked_interfaces.contains(name); const auto is_valid_address = interface_address != nullptr; if (is_target_interface && !is_hooked && is_valid_address) { block(); - hooked_interfaces.insert(name); + koalageddon::hooked_interfaces.insert(name); } }; #define HOOK_INTERFACE(FUNC) hook::swap_virtual_func_or_throw( \ - interface_address, \ + (void*) interface_address, \ #FUNC, \ - koalageddon::config.FUNC##_ordinal, \ + koalageddon::config.FUNC##_ordinal, \ (FunctionAddress) FUNC \ ); hook_if_needed(IClientAppManager, [&]() { HOOK_INTERFACE(IClientAppManager_IsAppDlcInstalled) - // TODO: Investigate IClientAppManager::BIsDlcEnabled - // TODO: Investigate IClientAppManager::GetDlcSizes - // TODO: Investigate IClientAppManager::GetInstalledApps }); hook_if_needed(IClientApps, [&]() { HOOK_INTERFACE(IClientApps_GetDLCCount) HOOK_INTERFACE(IClientApps_BGetDLCDataByIndex) - // TODO: Investigate IClientApps::GetAppKVRaw - // TODO: Investigate IClientApps::GetAppDataSection - // TODO: Investigate IClientApps::GetAppData }); hook_if_needed(IClientInventory, [&]() { @@ -169,18 +316,8 @@ DLL_EXPORT(void) SteamClient_Interface_Interceptor(const char* interface_name, c }); hook_if_needed(IClientUser, [&]() { - // NOTE: parent_ebp[function_offset] 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. HOOK_INTERFACE(IClientUser_BIsSubscribedApp) - // 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) @@ -189,3 +326,28 @@ DLL_EXPORT(void) SteamClient_Interface_Interceptor(const char* interface_name, c logger->error("{} -> Error: {}", __func__, ex.what()); } } + + +/** + * This macro will generate a definition of a demux function, + * which will cache the interface pointer in the local map. + */ +#define DEMUX_IMPL(INTERFACE) \ +DLL_EXPORT(void) INTERFACE##_Demux( \ + const void* arg1, \ + const void* arg2, \ + const void* arg3, \ + const void* arg4 \ +) { \ + if(!koalageddon::hooked_interfaces.contains(INTERFACE)){ \ + const std::lock_guard guard(koalageddon::map_mutex); \ + koalageddon::interface_name_pointer_map[INTERFACE] = arg1; \ + } \ + GET_ORIGINAL_FUNCTION(INTERFACE##_Demux) \ + INTERFACE##_Demux_o(arg1, arg2, arg3, arg4); \ +} + +DEMUX_IMPL(IClientAppManager) +DEMUX_IMPL(IClientApps) +DEMUX_IMPL(IClientInventory) +DEMUX_IMPL(IClientUser) diff --git a/src/koalageddon/vstdlib.cpp b/src/koalageddon/vstdlib.cpp index a63012a..7cada98 100644 --- a/src/koalageddon/vstdlib.cpp +++ b/src/koalageddon/vstdlib.cpp @@ -6,7 +6,14 @@ using namespace smoke_api; -//#define DETOUR_STRICT(FUNC, address) hook::detour((FunctionAddress) (address), #FUNC, (FunctionAddress) (FUNC)); +typedef uint32_t HCoroutine; +DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, struct CoroutineData* data); + +namespace koalageddon { + void init_vstdlib_hooks() { + DETOUR_ORIGINAL(Coroutine_Create) + } +} VIRTUAL(bool) SharedLicensesLockStatus(PARAMS(void* arg)) { // NOLINT(misc-unused-parameters) logger->debug("{} -> instance: {}, arg: {}", __func__, fmt::ptr(THIS), fmt::ptr(arg)); @@ -20,21 +27,21 @@ VIRTUAL(bool) SharedLibraryStopPlaying(PARAMS(void* arg)) { // NOLINT(misc-unuse struct CallbackData { FunctionAddress get_callback_intercept_address() { - return reinterpret_cast(this)[koalageddon::config.callback_interceptor_address_offset]; + return reinterpret_cast(this)[koalageddon::config.vstdlib_callback_interceptor_address_offset]; } FunctionAddress get_callback_address() { - return reinterpret_cast(this)[koalageddon::config.callback_data_offset]; + return reinterpret_cast(this)[koalageddon::config.vstdlib_callback_address_offset]; } }; struct CoroutineData { CallbackData* get_callback_data() { - return reinterpret_cast(this)[koalageddon::config.callback_data_offset]; + return reinterpret_cast(this)[koalageddon::config.vstdlib_callback_data_offset]; } const char* get_callback_name() { - return reinterpret_cast(this)[koalageddon::config.callback_name_offset]; + return reinterpret_cast(this)[koalageddon::config.vstdlib_callback_name_offset]; } }; diff --git a/src/smoke_api/smoke_api.cpp b/src/smoke_api/smoke_api.cpp index 6f89d0b..a965e02 100644 --- a/src/smoke_api/smoke_api.cpp +++ b/src/smoke_api/smoke_api.cpp @@ -88,12 +88,16 @@ namespace smoke_api { if (is_hook_mode) { hook::init(true); +#ifdef _WIN64 + init_hook_mode(); +#else // TODO: Check if it's steam from valve - if (util::strings_are_equal(exe_name, "steam.exe") && !util::is_x64()) { + if (util::strings_are_equal(exe_name, "steam.exe")) { koalageddon::init(); } else { init_hook_mode(); } +#endif } else { init_proxy_mode(); } diff --git a/src/steam_impl/steam_inventory.cpp b/src/steam_impl/steam_inventory.cpp index fa08dcc..c7e0509 100644 --- a/src/steam_impl/steam_inventory.cpp +++ b/src/steam_impl/steam_inventory.cpp @@ -1,7 +1,6 @@ #include #include -// TODO: Figure out why it doesn't work in koalageddon mode namespace steam_inventory { EResult GetResultStatus( diff --git a/src/steamclient_virtuals/client_inventory.cpp b/src/steamclient_virtuals/client_inventory.cpp index 1a010d1..8ef4f0d 100644 --- a/src/steamclient_virtuals/client_inventory.cpp +++ b/src/steamclient_virtuals/client_inventory.cpp @@ -39,7 +39,6 @@ VIRTUAL(bool) IClientInventory_GetResultItems( ); } -// TODO: Verify this function [ ] signature, in-game [ ] VIRTUAL(bool) IClientInventory_GetResultItemProperty( PARAMS( SteamInventoryResult_t resultHandle, @@ -62,7 +61,6 @@ VIRTUAL(bool) IClientInventory_GetResultItemProperty( ); } -// TODO: Verify this function [x] signature, in-game [ ] VIRTUAL(bool) IClientInventory_CheckResultSteamID( PARAMS( SteamInventoryResult_t resultHandle, @@ -76,8 +74,6 @@ VIRTUAL(bool) IClientInventory_CheckResultSteamID( }); } - -// TODO: Verify this function [x] signature, in-game [ ] VIRTUAL(bool) IClientInventory_GetAllItems(PARAMS(SteamInventoryResult_t* pResultHandle)) { return steam_inventory::GetAllItems(__func__, pResultHandle, [&]() { GET_ORIGINAL_VIRTUAL_FUNCTION(IClientInventory_GetAllItems) @@ -86,7 +82,6 @@ VIRTUAL(bool) IClientInventory_GetAllItems(PARAMS(SteamInventoryResult_t* pResul }); } -// TODO: Verify this function [x] signature, in-game [ ] VIRTUAL(bool) IClientInventory_GetItemsByID( PARAMS( SteamInventoryResult_t* pResultHandle, @@ -101,7 +96,6 @@ VIRTUAL(bool) IClientInventory_GetItemsByID( }); } -// TODO: Verify this function [x] signature, in-game [ ] VIRTUAL(bool) IClientInventory_SerializeResult( PARAMS( SteamInventoryResult_t resultHandle,