Refactored for latest Koalabox

This commit is contained in:
acidicoala
2023-01-07 11:25:37 +03:00
parent 1d36cfb3be
commit b077212d10
43 changed files with 716 additions and 667 deletions

4
.idea/cmake.xml generated
View File

@@ -2,8 +2,8 @@
<project version="4"> <project version="4">
<component name="CMakeSharedSettings"> <component name="CMakeSharedSettings">
<configurations> <configurations>
<configuration PROFILE_NAME="Debug [32] (Template: copy and set the 32-bit toolchain)" ENABLED="false" GENERATION_DIR="build/32/debug" CONFIG_NAME="Debug" GENERATION_OPTIONS="-G &quot;Visual Studio 17 2022&quot; -A Win32" /> <configuration PROFILE_NAME="Debug [32] (Template: copy and set the 32-bit toolchain)" ENABLED="false" GENERATION_DIR="build/32" CONFIG_NAME="Debug" GENERATION_OPTIONS="-G &quot;Visual Studio 17 2022&quot; -A Win32" />
<configuration PROFILE_NAME="Debug [64] (Template: copy and set the 64-bit toolchain)" ENABLED="false" GENERATION_DIR="build/64/debug" CONFIG_NAME="Debug" GENERATION_OPTIONS="-G &quot;Visual Studio 17 2022&quot; -A x64" /> <configuration PROFILE_NAME="Debug [64] (Template: copy and set the 64-bit toolchain)" ENABLED="false" GENERATION_DIR="build/64" CONFIG_NAME="Debug" GENERATION_OPTIONS="-G &quot;Visual Studio 17 2022&quot; -A x64" />
</configurations> </configurations>
</component> </component>
</project> </project>

View File

@@ -9,6 +9,7 @@
</Markdown> </Markdown>
<Objective-C> <Objective-C>
<option name="KEEP_STRUCTURES_IN_ONE_LINE" value="true" /> <option name="KEEP_STRUCTURES_IN_ONE_LINE" value="true" />
<option name="FUNCTION_CALL_ARGUMENTS_ALIGN_MULTILINE" value="false" />
<option name="FUNCTION_CALL_ARGUMENTS_NEW_LINE_AFTER_LPAR" value="true" /> <option name="FUNCTION_CALL_ARGUMENTS_NEW_LINE_AFTER_LPAR" value="true" />
<option name="FUNCTION_CALL_ARGUMENTS_NEW_LINE_BEFORE_RPAR" value="true" /> <option name="FUNCTION_CALL_ARGUMENTS_NEW_LINE_BEFORE_RPAR" value="true" />
<option name="SPACE_BEFORE_POINTER_IN_DECLARATION" value="false" /> <option name="SPACE_BEFORE_POINTER_IN_DECLARATION" value="false" />

View File

@@ -44,6 +44,7 @@ set(
src/core/macros.hpp src/core/macros.hpp
src/core/paths.cpp src/core/paths.cpp
src/core/paths.hpp src/core/paths.hpp
src/core/steam_types.hpp
src/smoke_api/smoke_api.cpp src/smoke_api/smoke_api.cpp
src/smoke_api/smoke_api.hpp src/smoke_api/smoke_api.hpp
src/steam_api_exports/steam_api_flat.cpp src/steam_api_exports/steam_api_flat.cpp
@@ -63,7 +64,6 @@ set(
src/steam_impl/steam_user.hpp src/steam_impl/steam_user.hpp
src/steam_functions/steam_functions.cpp src/steam_functions/steam_functions.cpp
src/steam_functions/steam_functions.hpp src/steam_functions/steam_functions.hpp
src/steam_types/steam_types.hpp
src/steamclient_exports/steamclient.cpp src/steamclient_exports/steamclient.cpp
src/main.cpp src/main.cpp
${GENERATED_LINKER_EXPORTS} ${GENERATED_LINKER_EXPORTS}
@@ -76,7 +76,9 @@ if (CMAKE_SIZEOF_VOID_P EQUAL 4)
src/koalageddon/koalageddon.hpp src/koalageddon/koalageddon.hpp
src/koalageddon/koalageddon.cpp src/koalageddon/koalageddon.cpp
src/koalageddon/vstdlib.cpp src/koalageddon/vstdlib.cpp
src/koalageddon/vstdlib.hpp
src/koalageddon/steamclient.cpp src/koalageddon/steamclient.cpp
src/koalageddon/steamclient.hpp
src/steamclient_virtuals/client_app_manager.cpp src/steamclient_virtuals/client_app_manager.cpp
src/steamclient_virtuals/client_apps.cpp src/steamclient_virtuals/client_apps.cpp
src/steamclient_virtuals/client_inventory.cpp src/steamclient_virtuals/client_inventory.cpp

View File

@@ -1,11 +1,14 @@
#include <core/cache.hpp> #include <core/cache.hpp>
#include <core/paths.hpp> #include <core/paths.hpp>
#include <koalabox/io.hpp> #include <koalabox/io.hpp>
#include <koalabox/logger.hpp>
namespace cache { namespace cache {
Cache read_cache_from_disk() { Cache read_cache_from_disk() {
try { try {
const auto cache_string = io::read_file(paths::get_cache_path()); const auto cache_string = koalabox::io::read_file(paths::get_cache_path());
if (cache_string.empty()) { if (cache_string.empty()) {
return {}; return {};
@@ -13,7 +16,7 @@ namespace cache {
return nlohmann::json::parse(cache_string).get<Cache>(); return nlohmann::json::parse(cache_string).get<Cache>();
} catch (const Exception& e) { } catch (const Exception& e) {
logger->warn("{} -> Failed to read cache from disk: {}", __func__, e.what()); LOG_WARN("{} -> Failed to read cache from disk: {}", __func__, e.what())
return {}; return {};
} }
@@ -23,9 +26,9 @@ namespace cache {
try { try {
const auto cache_string = nlohmann::json(cache).dump(2); const auto cache_string = nlohmann::json(cache).dump(2);
io::write_file(paths::get_cache_path(), cache_string); koalabox::io::write_file(paths::get_cache_path(), cache_string);
} catch (const Exception& e) { } catch (const Exception& e) {
logger->error("{} -> Failed to write cache to disk: {}", __func__, e.what()); LOG_ERROR("{} -> Failed to write cache to disk: {}", __func__, e.what())
} }
} }
@@ -52,7 +55,7 @@ namespace cache {
} }
void save_dlc_ids(AppId_t app_id, const Vector<AppId_t>& dlc_ids) { void save_dlc_ids(AppId_t app_id, const Vector<AppId_t>& dlc_ids) {
logger->debug("{} -> Caching DLC IDs for the app: {}", __func__, app_id); LOG_DEBUG("{} -> Caching DLC IDs for the app: {}", __func__, app_id)
auto cache = read_cache_from_disk(); auto cache = read_cache_from_disk();
@@ -68,7 +71,7 @@ namespace cache {
} }
void save_koalageddon_config(const koalageddon::KoalageddonConfig& config) { void save_koalageddon_config(const koalageddon::KoalageddonConfig& config) {
logger->debug("{} -> Caching koalageddon config", __func__); LOG_DEBUG("{} -> Caching koalageddon config", __func__)
auto cache = read_cache_from_disk(); auto cache = read_cache_from_disk();

View File

@@ -1,16 +1,15 @@
#pragma once #pragma once
#include <koalabox/koalabox.hpp> #include <koalabox/types.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <koalageddon/koalageddon.hpp> #include <koalageddon/koalageddon.hpp>
#include <steam_types/steam_types.hpp> #include <core/steam_types.hpp>
/** /**
* This namespace contains utility functions for reading from and writing to cache file on disk. * This namespace contains utility functions for reading from and writing to cache file on disk.
* All functions are intended to be safe to call, i.e. they should not throw exceptions. * All functions are intended to be safe to call, i.e. they should not throw exceptions.
*/ */
namespace cache { namespace cache {
using namespace koalabox;
struct App { struct App {
Vector<AppId_t> dlc_ids; Vector<AppId_t> dlc_ids;

View File

@@ -7,7 +7,7 @@ namespace config {
// TODO: Reloading via export // TODO: Reloading via export
void init() { void init() {
instance = config_parser::parse<Config>(paths::get_config_path()); instance = koalabox::config_parser::parse<Config>(paths::get_config_path());
} }
AppStatus get_app_status(uint32_t app_id) { AppStatus get_app_status(uint32_t app_id) {
@@ -36,7 +36,7 @@ namespace config {
return instance.default_dlc_status; return instance.default_dlc_status;
} }
bool is_dlc_unlocked(uint32_t app_id, uint32_t dlc_id, const std::function<bool()>& original_function) { bool is_dlc_unlocked(uint32_t app_id, uint32_t dlc_id, const Function<bool()>& original_function) {
const auto app_status = config::get_app_status(app_id); const auto app_status = config::get_app_status(app_id);
const auto dlc_status = config::get_dlc_status(dlc_id); const auto dlc_status = config::get_dlc_status(dlc_id);

View File

@@ -1,11 +1,8 @@
#pragma once #pragma once
#include <cstdint>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <koalabox/koalabox.hpp> #include <koalabox/types.hpp>
namespace config { namespace config {
using namespace koalabox;
enum class AppStatus { enum class AppStatus {
LOCKED, LOCKED,
UNLOCKED, UNLOCKED,
@@ -67,5 +64,5 @@ namespace config {
AppStatus get_app_status(uint32_t app_id); AppStatus get_app_status(uint32_t app_id);
DlcStatus get_dlc_status(uint32_t dlc_id); DlcStatus get_dlc_status(uint32_t dlc_id);
bool is_dlc_unlocked(uint32_t app_id, uint32_t dlc_id, const std::function<bool()>& original_function); bool is_dlc_unlocked(uint32_t app_id, uint32_t dlc_id, const Function<bool()>& original_function);
} }

View File

@@ -5,5 +5,5 @@ namespace globals {
HMODULE steamapi_module = nullptr; HMODULE steamapi_module = nullptr;
HMODULE vstdlib_module = nullptr; HMODULE vstdlib_module = nullptr;
HMODULE steamclient_module = nullptr; HMODULE steamclient_module = nullptr;
Map<String, FunctionAddress> address_map; Map<String, uintptr_t> address_map; // NOLINT(cert-err58-cpp)
} }

View File

@@ -1,12 +1,12 @@
#pragma once #pragma once
#include <koalabox/koalabox.hpp> #include <koalabox/types.hpp>
namespace globals { namespace globals {
using namespace koalabox;
extern HMODULE smokeapi_handle; extern HMODULE smokeapi_handle;
extern HMODULE steamclient_module; extern HMODULE steamclient_module;
extern HMODULE steamapi_module; extern HMODULE steamapi_module;
extern HMODULE vstdlib_module; extern HMODULE vstdlib_module;
extern Map<String, FunctionAddress> address_map; extern Map<String, uintptr_t> address_map;
} }

View File

@@ -3,6 +3,39 @@
#include <core/globals.hpp> #include <core/globals.hpp>
#include <koalabox/hook.hpp> #include <koalabox/hook.hpp>
/**
* By default, virtual functions are declared with __thiscall
* convention, which is normal since they are class members.
* But it presents an issue for us, since we cannot pass *this
* pointer as a function argument. This is because *this
* pointer is passed via register ECX in __thiscall
* convention. Hence, to resolve this issue we declare our
* hooked functions with __fastcall convention, to trick
* the compiler into reading ECX & EDX registers as 1st
* and 2nd function arguments respectively. Similarly, __fastcall
* makes the compiler push the first argument into the ECX register,
* which mimics the __thiscall calling convention. Register EDX
* is not used anywhere in this case, but we still pass it along
* to conform to the __fastcall convention. This all applies
* to the x86 architecture.
*
* In x86-64 however, there is only one calling convention,
* so __fastcall is simply ignored. However, RDX in this case
* will store the 1st actual argument to the function, so we
* have to omit it from the function signature.
*
* The macros below implement the above-mentioned considerations.
*/
#ifdef _WIN64
#define PARAMS(...) void* RCX, ##__VA_ARGS__
#define ARGS(...) RCX, ##__VA_ARGS__
#define THIS RCX
#else
#define PARAMS(...) void* ECX, void* EDX, ##__VA_ARGS__
#define ARGS(...) ECX, EDX, ##__VA_ARGS__
#define THIS ECX
#endif
// Names beginning with $ designate macros that are not meant to be used directly by the sources consuming this file // Names beginning with $ designate macros that are not meant to be used directly by the sources consuming this file
#define DLL_EXPORT(TYPE) extern "C" [[maybe_unused]] __declspec( dllexport ) TYPE __cdecl #define DLL_EXPORT(TYPE) extern "C" [[maybe_unused]] __declspec( dllexport ) TYPE __cdecl
@@ -14,11 +47,12 @@
#define GET_ORIGINAL_FUNCTION_STEAMAPI(FUNC) \ #define GET_ORIGINAL_FUNCTION_STEAMAPI(FUNC) \
static const auto FUNC##_o = koalabox::hook::get_original_function(globals::steamapi_module, #FUNC, FUNC); static const auto FUNC##_o = koalabox::hook::get_original_function(globals::steamapi_module, #FUNC, FUNC);
#define $DETOUR(FUNC, MODULE_HANDLE) \
koalabox::hook::detour_or_warn(globals::address_map, MODULE_HANDLE, #FUNC, reinterpret_cast<FunctionAddress>(FUNC));
#define DETOUR_ADDRESS(FUNC, ADDRESS) \ #define DETOUR_ADDRESS(FUNC, ADDRESS) \
koalabox::hook::detour_or_warn(globals::address_map, ADDRESS, #FUNC, reinterpret_cast<FunctionAddress>(FUNC)); koalabox::hook::detour_or_warn(globals::address_map, ADDRESS, #FUNC, reinterpret_cast<uintptr_t>(FUNC));
#define DETOUR_STEAMCLIENT(FUNC) $DETOUR(FUNC, globals::steamclient_module) #define $DETOUR(FUNC, NAME, MODULE_HANDLE) \
#define DETOUR_VSTDLIB(FUNC) $DETOUR(FUNC, globals::vstdlib_module) koalabox::hook::detour_or_warn(globals::address_map, MODULE_HANDLE, NAME, reinterpret_cast<uintptr_t>(FUNC));
#define DETOUR_STEAMCLIENT(FUNC) $DETOUR(FUNC, #FUNC, globals::steamclient_module)
#define DETOUR_VSTDLIB(FUNC) $DETOUR(vstdlib::FUNC, #FUNC, globals::vstdlib_module)

View File

@@ -1,10 +1,11 @@
#include <koalabox/loader.hpp>
#include <core/paths.hpp> #include <core/paths.hpp>
#include <core/globals.hpp> #include <core/globals.hpp>
#include <koalabox/loader.hpp>
namespace paths { namespace paths {
Path get_self_path() { Path get_self_path() {
static const auto path = loader::get_module_dir(globals::smokeapi_handle); static const auto path = koalabox::loader::get_module_dir(globals::smokeapi_handle);
return path; return path;
} }
@@ -22,4 +23,5 @@ namespace paths {
static const auto path = get_self_path() / "SmokeAPI.log.log"; static const auto path = get_self_path() / "SmokeAPI.log.log";
return path; return path;
} }
} }

View File

@@ -1,10 +1,8 @@
#pragma once #pragma once
#include <koalabox/koalabox.hpp> #include <koalabox/types.hpp>
#include <nlohmann/json.hpp>
namespace paths { namespace paths {
using namespace koalabox;
/** /**
* @return An std::path instance representing the directory containing this DLL * @return An std::path instance representing the directory containing this DLL
@@ -13,4 +11,5 @@ namespace paths {
Path get_config_path(); Path get_config_path();
Path get_cache_path(); Path get_cache_path();
Path get_log_path(); Path get_log_path();
} }

View File

@@ -1,12 +1,15 @@
#pragma once #pragma once
typedef uint32_t SteamInventoryResult_t; #include <cstdint>
typedef uint64_t SteamItemInstanceID_t;
typedef uint32_t SteamItemDef_t; using AppId_t = uint32_t;
typedef uint32_t AppId_t; using SteamInventoryResult_t = uint32_t;
typedef uint32_t HSteamPipe; using SteamItemInstanceID_t = uint64_t;
typedef uint32_t HSteamUser; using SteamItemDef_t = uint32_t;
typedef uint64_t CSteamID; using HSteamPipe = uint32_t;
using HSteamUser = uint32_t;
using CSteamID = uint64_t;
using EResult = uint32_t;
struct SteamItemDetails_t { struct SteamItemDetails_t {
SteamItemInstanceID_t m_itemId; SteamItemInstanceID_t m_itemId;
@@ -22,4 +25,10 @@ enum EUserHasLicenseForAppResult {
k_EUserHasLicenseResultNoAuth = 2, // User has not been authenticated k_EUserHasLicenseResultNoAuth = 2, // User has not been authenticated
}; };
typedef uint32_t EResult; class ISteamClient;
class ISteamApps;
class ISteamUser;
class ISteamInventory;

View File

@@ -1,13 +1,19 @@
#include <koalageddon/koalageddon.hpp> #include <koalageddon/koalageddon.hpp>
#include <koalageddon/vstdlib.hpp>
#include <build_config.h> #include <build_config.h>
#include <core/cache.hpp> #include <core/cache.hpp>
#include <core/config.hpp> #include <core/config.hpp>
#include <steam_functions/steam_functions.hpp>
#include <koalabox/dll_monitor.hpp> #include <koalabox/dll_monitor.hpp>
#include <koalabox/http_client.hpp> #include <koalabox/http_client.hpp>
#include <koalabox/util.hpp> #include <koalabox/util.hpp>
#include <steam_functions/steam_functions.hpp> #include <koalabox/logger.hpp>
#include <koalabox/patcher.hpp>
#include <koalabox/win_util.hpp>
namespace koalageddon { namespace koalageddon {
using namespace koalabox;
KoalageddonConfig config; // NOLINT(cert-err58-cpp) KoalageddonConfig config; // NOLINT(cert-err58-cpp)
/** /**
@@ -21,7 +27,7 @@ namespace koalageddon {
return "local config override"; return "local config override";
} catch (const Exception& ex) { } catch (const Exception& ex) {
logger->error("Failed to get local koalageddon config: {}", ex.what()); LOG_ERROR("Failed to get local koalageddon config: {}", ex.what())
} }
} }
@@ -34,7 +40,7 @@ namespace koalageddon {
return "GitHub repository"; return "GitHub repository";
} catch (const Exception& ex) { } catch (const Exception& ex) {
logger->error("Failed to get remote koalageddon config: {}", ex.what()); LOG_ERROR("Failed to get remote koalageddon config: {}", ex.what())
} }
try { try {
@@ -44,7 +50,7 @@ namespace koalageddon {
return "disk cache"; return "disk cache";
} catch (const Exception& ex) { } catch (const Exception& ex) {
logger->error("Failed to get cached koalageddon config: {}", ex.what()); LOG_ERROR("Failed to get cached koalageddon config: {}", ex.what())
} }
// Finally, fallback on the default config // Finally, fallback on the default config
@@ -53,35 +59,41 @@ namespace koalageddon {
} }
void init() { void init() {
std::thread([]() { std::thread(
const auto kg_config_source = init_koalageddon_config(); []() {
logger->info("Loaded Koalageddon config from the {}", kg_config_source); const auto kg_config_source = init_koalageddon_config();
}).detach(); LOG_INFO("Loaded Koalageddon config from the {}", kg_config_source)
dll_monitor::init({VSTDLIB_DLL, STEAMCLIENT_DLL}, [](const HMODULE& module_handle, const String& name) {
try {
if (util::strings_are_equal(name, VSTDLIB_DLL)) {
// VStdLib DLL handles Family Sharing functions
globals::vstdlib_module = module_handle;
if (config::instance.unlock_family_sharing) {
DETOUR_VSTDLIB(Coroutine_Create)
}
} else if (util::strings_are_equal(name, STEAMCLIENT_DLL)) {
// SteamClient DLL handles unlocking functions
globals::steamclient_module = module_handle;
DETOUR_STEAMCLIENT(CreateInterface)
}
if (globals::vstdlib_module != nullptr && globals::steamclient_module != nullptr) {
dll_monitor::shutdown();
}
} catch (const Exception& ex) {
logger->error("Koalageddon mode dll monitor init error. Module: '{}', Message: {}", name, ex.what());
} }
}); ).detach();
dll_monitor::init(
{VSTDLIB_DLL, STEAMCLIENT_DLL}, [](const HMODULE& module_handle, const String& name) {
try {
if (util::strings_are_equal(name, VSTDLIB_DLL)) {
// VStdLib DLL handles Family Sharing functions
globals::vstdlib_module = module_handle;
if (config::instance.unlock_family_sharing) {
DETOUR_VSTDLIB(Coroutine_Create)
}
} else if (util::strings_are_equal(name, STEAMCLIENT_DLL)) {
// SteamClient DLL handles unlocking functions
globals::steamclient_module = module_handle;
DETOUR_STEAMCLIENT(CreateInterface)
}
if (globals::vstdlib_module != nullptr && globals::steamclient_module != nullptr) {
dll_monitor::shutdown();
}
} catch (const Exception& ex) {
LOG_ERROR(
"Koalageddon mode dll monitor process_interface_selector error. Module: '{}', Message: {}",
name, ex.what())
}
}
);
} }
} }

View File

@@ -1,12 +1,9 @@
#pragma once #pragma once
#include <koalabox/koalabox.hpp> #include <koalabox/types.hpp>
#include <core/macros.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
namespace koalageddon { namespace koalageddon {
using namespace koalabox;
// Offset values are interpreted according to pointer arithmetic rules, i.e. // 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. // 1 unit offset represents 4 and 8 bytes in 32-bit and 64-bit architectures respectively.
struct KoalageddonConfig { struct KoalageddonConfig {
@@ -37,7 +34,4 @@ namespace koalageddon {
void init(); void init();
namespace steamclient {
void init(uintptr_t interface_selector_address);
}
} }

View File

@@ -1,117 +1,83 @@
#include <koalabox/hook.hpp> #include <koalageddon/koalageddon.hpp>
#include <koalabox/patcher.hpp>
#include <steam_functions/steam_functions.hpp> #include <steam_functions/steam_functions.hpp>
#include <koalabox/hook.hpp>
#include <koalabox/logger.hpp>
#include <koalabox/util.hpp>
#include <Zydis/Zydis.h> #include <Zydis/Zydis.h>
#include <Zydis/DecoderTypes.h> #include <Zydis/DecoderTypes.h>
namespace koalageddon::steamclient { namespace koalageddon::steamclient {
using namespace koalabox; using namespace koalabox;
struct InstructionContext {
std::optional<ZydisRegister> base_register;
std::optional<String> function_name;
};
// map<interface name, map<function name, function ordinal>> // map<interface name, map<function name, function ordinal>>
Map<String, Map<String, uint32_t>> ordinal_map; // NOLINT(cert-err58-cpp) Map<String, Map<String, uint32_t>> ordinal_map; // NOLINT(cert-err58-cpp)
const auto MAX_INSTRUCTION_SIZE = 15; const auto MAX_INSTRUCTION_SIZE = 15;
// TODO: Refactor into Koalabox // TODO: Refactor into Koalabox
ZydisDecoder decoder = {}; ZydisDecoder decoder = {};
ZydisFormatter formatter = {}; ZydisFormatter formatter = {};
#define HOOK_FUNCTION(INTERFACE, FUNC) hook::swap_virtual_func_or_throw( \ #define HOOK_FUNCTION(INTERFACE, FUNC) hook::swap_virtual_func_or_throw( \
globals::address_map, \ globals::address_map, \
interface, \ interface, \
#INTERFACE"_"#FUNC, \ #INTERFACE"_"#FUNC, \
ordinal_map[#INTERFACE][#FUNC], \ ordinal_map[#INTERFACE][#FUNC], \
reinterpret_cast<uintptr_t>(INTERFACE##_##FUNC) \ reinterpret_cast<uintptr_t>(INTERFACE##_##FUNC) \
); );
DLL_EXPORT(void) IClientAppManager_Selector( #define SELECTOR_IMPLEMENTATION(INTERFACE, FUNC_BODY) \
const void* interface, DLL_EXPORT(void) INTERFACE##_Selector( \
const void* arg2, const void* interface, \
const void* arg3, const void* arg2, \
const void* arg4 const void* arg3, \
) { const void* arg4 \
static std::once_flag flag; ) { \
std::call_once( CALL_ONCE(FUNC_BODY) \
flag, [&]() { GET_ORIGINAL_HOOKED_FUNCTION(INTERFACE##_Selector) \
HOOK_FUNCTION(IClientAppManager, IsAppDlcInstalled) INTERFACE##_Selector_o(interface, arg2, arg3, arg4); \
}
);
GET_ORIGINAL_HOOKED_FUNCTION(IClientAppManager_Selector)
IClientAppManager_Selector_o(interface, arg2, arg3, arg4);
} }
DLL_EXPORT(void) IClientApps_Selector( SELECTOR_IMPLEMENTATION(IClientAppManager, {
const void* interface, HOOK_FUNCTION(IClientAppManager, IsAppDlcInstalled)
const void* arg2, })
const void* arg3,
const void* arg4
) {
static std::once_flag flag;
std::call_once(
flag, [&]() {
HOOK_FUNCTION(IClientApps, GetDLCCount)
HOOK_FUNCTION(IClientApps, BGetDLCDataByIndex)
}
);
GET_ORIGINAL_HOOKED_FUNCTION(IClientApps_Selector) SELECTOR_IMPLEMENTATION(IClientApps, {
IClientApps_Selector_o(interface, arg2, arg3, arg4); HOOK_FUNCTION(IClientApps, GetDLCCount)
} HOOK_FUNCTION(IClientApps, BGetDLCDataByIndex)
})
DLL_EXPORT(void) IClientInventory_Selector( SELECTOR_IMPLEMENTATION(IClientInventory, {
const void* interface, HOOK_FUNCTION(IClientInventory, GetResultStatus)
const void* arg2, HOOK_FUNCTION(IClientInventory, GetResultItems)
const void* arg3, HOOK_FUNCTION(IClientInventory, GetResultItemProperty)
const void* arg4 HOOK_FUNCTION(IClientInventory, CheckResultSteamID)
) { HOOK_FUNCTION(IClientInventory, GetAllItems)
static std::once_flag flag; HOOK_FUNCTION(IClientInventory, GetItemsByID)
std::call_once( HOOK_FUNCTION(IClientInventory, SerializeResult)
flag, [&]() { HOOK_FUNCTION(IClientInventory, GetItemDefinitionIDs)
HOOK_FUNCTION(IClientInventory, GetResultStatus) })
HOOK_FUNCTION(IClientInventory, GetResultItems)
HOOK_FUNCTION(IClientInventory, GetResultItemProperty)
HOOK_FUNCTION(IClientInventory, CheckResultSteamID)
HOOK_FUNCTION(IClientInventory, GetAllItems)
HOOK_FUNCTION(IClientInventory, GetItemsByID)
HOOK_FUNCTION(IClientInventory, SerializeResult)
HOOK_FUNCTION(IClientInventory, GetItemDefinitionIDs)
}
);
GET_ORIGINAL_HOOKED_FUNCTION(IClientInventory_Selector) SELECTOR_IMPLEMENTATION(IClientUser, {
IClientInventory_Selector_o(interface, arg2, arg3, arg4); HOOK_FUNCTION(IClientUser, BIsSubscribedApp)
} })
DLL_EXPORT(void) IClientUser_Selector(
const void* interface,
const void* arg2,
const void* arg3,
const void* arg4
) {
static std::once_flag flag;
std::call_once(
flag, [&]() {
HOOK_FUNCTION(IClientUser, BIsSubscribedApp)
}
);
GET_ORIGINAL_HOOKED_FUNCTION(IClientUser_Selector)
IClientUser_Selector_o(interface, arg2, arg3, arg4);
}
uintptr_t get_absolute_address(ZydisDecodedInstruction instruction, uintptr_t address) { uintptr_t get_absolute_address(ZydisDecodedInstruction instruction, uintptr_t address) {
const auto op = instruction.operands[0]; const auto operand = instruction.operands[0];
if (op.imm.is_relative) { if (operand.imm.is_relative) {
ZyanU64 absolute_address; ZyanU64 absolute_address;
ZydisCalcAbsoluteAddress(&instruction, &op, address, &absolute_address); ZydisCalcAbsoluteAddress(&instruction, &operand, address, &absolute_address);
return absolute_address; return absolute_address;
} }
return (uintptr_t) op.imm.value.u; return (uintptr_t) operand.imm.value.u;
} }
bool is_push_immediate(const ZydisDecodedInstruction& instruction) { bool is_push_immediate(const ZydisDecodedInstruction& instruction) {
@@ -153,11 +119,6 @@ namespace koalageddon::steamclient {
return std::nullopt; return std::nullopt;
} }
struct InstructionContext {
std::optional<ZydisRegister> base_register;
std::optional<String> function_name;
};
void construct_ordinal_map( // NOLINT(misc-no-recursion) void construct_ordinal_map( // NOLINT(misc-no-recursion)
const String& target_interface, const String& target_interface,
Map<String, uint32_t>& map, Map<String, uint32_t>& map,
@@ -189,15 +150,13 @@ namespace koalageddon::steamclient {
auto current_address = (uintptr_t) start_address; auto current_address = (uintptr_t) start_address;
ZydisDecodedInstruction instruction{}; ZydisDecodedInstruction instruction{};
while (ZYAN_SUCCESS( while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(
ZydisDecoderDecodeBuffer( &decoder,
&decoder, (void*) current_address,
(void*) current_address, MAX_INSTRUCTION_SIZE,
MAX_INSTRUCTION_SIZE, &instruction
&instruction ))) {
) LOG_TRACE(
)) {
TRACE(
"{} -> Visiting {} | {}", "{} -> Visiting {} | {}",
__func__, (void*) current_address, *get_instruction_string(instruction, current_address) __func__, (void*) current_address, *get_instruction_string(instruction, current_address)
) )
@@ -296,10 +255,10 @@ namespace koalageddon::steamclient {
if (offset && is_derived_from_base_reg) { if (offset && is_derived_from_base_reg) {
const auto ordinal = *offset / sizeof(uintptr_t); const auto ordinal = *offset / sizeof(uintptr_t);
logger->debug( LOG_DEBUG(
"{} -> Found function ordinal {}::{}@{}", "{} -> Found function ordinal {}::{}@{}",
__func__, target_interface, *context.function_name, ordinal __func__, target_interface, *context.function_name, ordinal
); )
map[*context.function_name] = ordinal; map[*context.function_name] = ordinal;
break; break;
@@ -320,14 +279,12 @@ namespace koalageddon::steamclient {
std::optional<String> find_interface_name(uintptr_t selector_address) { std::optional<String> find_interface_name(uintptr_t selector_address) {
auto current_address = selector_address; auto current_address = selector_address;
ZydisDecodedInstruction instruction{}; ZydisDecodedInstruction instruction{};
while (ZYAN_SUCCESS( while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(
ZydisDecoderDecodeBuffer( &decoder,
&decoder, (void*) current_address,
(void*) current_address, MAX_INSTRUCTION_SIZE,
MAX_INSTRUCTION_SIZE, &instruction
&instruction ))) {
)
)) {
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)) { if (is_push_immediate(instruction)) {
@@ -343,7 +300,7 @@ namespace koalageddon::steamclient {
current_address += instruction.length; current_address += instruction.length;
} }
// logger->warn("Failed to find any interface names at {}", (void*) selector_address); // LOG_WARN("Failed to find any interface names at {}", (void*) selector_address);
return std::nullopt; return std::nullopt;
} }
@@ -368,26 +325,24 @@ namespace koalageddon::steamclient {
const uintptr_t start_address, const uintptr_t start_address,
Set<uintptr_t>& visited_addresses Set<uintptr_t>& visited_addresses
) { ) {
TRACE("{} -> start_address: {}", __func__, (void*) start_address) LOG_TRACE("{} -> start_address: {}", __func__, (void*) start_address)
if (visited_addresses.contains(start_address)) { if (visited_addresses.contains(start_address)) {
TRACE("{} -> Breaking recursion due to visited address", __func__) LOG_TRACE("{} -> Breaking recursion due to visited address", __func__)
return; return;
} }
auto current_address = start_address; auto current_address = start_address;
ZydisDecodedInstruction instruction{}; ZydisDecodedInstruction instruction{};
while (ZYAN_SUCCESS( while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(
ZydisDecoderDecodeBuffer( &decoder,
&decoder, (void*) current_address,
(void*) current_address, MAX_INSTRUCTION_SIZE,
MAX_INSTRUCTION_SIZE, &instruction
&instruction ))) {
)
)) {
visited_addresses.insert(current_address); visited_addresses.insert(current_address);
TRACE( LOG_TRACE(
"{} -> Visiting {} | {}", "{} -> Visiting {} | {}",
__func__, (void*) current_address, *get_instruction_string(instruction, current_address) __func__, (void*) current_address, *get_instruction_string(instruction, current_address)
) )
@@ -397,7 +352,7 @@ namespace koalageddon::steamclient {
if (instruction.mnemonic == ZYDIS_MNEMONIC_CALL && if (instruction.mnemonic == ZYDIS_MNEMONIC_CALL &&
operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE
) { ) {
TRACE("{} -> Found call instruction at {}", __func__, (void*) current_address) LOG_TRACE("{} -> Found call instruction at {}", __func__, (void*) current_address)
const auto function_selector_address = get_absolute_address(instruction, current_address); const auto function_selector_address = get_absolute_address(instruction, current_address);
@@ -406,7 +361,7 @@ namespace koalageddon::steamclient {
if (interface_name_opt) { if (interface_name_opt) {
const auto& interface_name = *interface_name_opt; const auto& interface_name = *interface_name_opt;
logger->debug("Detected interface: '{}'", interface_name); LOG_DEBUG("Detected interface: '{}'", interface_name)
DETOUR_SELECTOR(IClientAppManager) DETOUR_SELECTOR(IClientAppManager)
DETOUR_SELECTOR(IClientApps) DETOUR_SELECTOR(IClientApps)
@@ -420,7 +375,7 @@ namespace koalageddon::steamclient {
process_interface_selector(jump_taken_destination, visited_addresses); process_interface_selector(jump_taken_destination, visited_addresses);
process_interface_selector(jump_not_taken_destination, visited_addresses); process_interface_selector(jump_not_taken_destination, visited_addresses);
TRACE("breaking recursion due to conditional branch") LOG_TRACE("breaking recursion due to conditional branch")
return; return;
} else if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP && } else if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP &&
operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE
@@ -429,7 +384,7 @@ namespace koalageddon::steamclient {
process_interface_selector(jump_destination, visited_addresses); process_interface_selector(jump_destination, visited_addresses);
TRACE("breaking recursion due to unconditional branch") LOG_TRACE("breaking recursion due to unconditional branch")
return; return;
} else if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP && } else if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP &&
operand.type == ZYDIS_OPERAND_TYPE_MEMORY && operand.type == ZYDIS_OPERAND_TYPE_MEMORY &&
@@ -448,7 +403,7 @@ namespace koalageddon::steamclient {
return; return;
} else if (instruction.mnemonic == ZYDIS_MNEMONIC_RET) { } else if (instruction.mnemonic == ZYDIS_MNEMONIC_RET) {
TRACE("{} -> Breaking recursion due to return instruction", __func__) LOG_TRACE("{} -> Breaking recursion due to return instruction", __func__)
return; return;
} }
@@ -456,14 +411,23 @@ namespace koalageddon::steamclient {
} }
} }
void init(const uintptr_t interface_selector_address) { void process_client_engine(uintptr_t interface) {
const auto* steam_client_internal = ((uintptr_t***) interface)[
koalageddon::config.client_engine_steam_client_internal_ordinal
];
const auto interface_selector_address = (*steam_client_internal)[
koalageddon::config.steam_client_internal_interface_selector_ordinal
];
LOG_DEBUG("Found interface selector at: {}", (void*) interface_selector_address);
if (ZYAN_FAILED(ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_ADDRESS_WIDTH_32))) { if (ZYAN_FAILED(ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_ADDRESS_WIDTH_32))) {
logger->error("Failed to initialize zydis decoder"); LOG_ERROR("Failed to initialize zydis decoder")
return; return;
} }
if (ZYAN_FAILED(ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL))) { if (ZYAN_FAILED(ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL))) {
logger->error("Failed to initialize zydis formatter"); LOG_ERROR("Failed to initialize zydis formatter")
return; return;
} }

View File

@@ -0,0 +1,6 @@
#include <koalabox/types.hpp>
namespace koalageddon::steamclient {
void process_client_engine(uintptr_t interface);
}

View File

@@ -1,88 +1,70 @@
#include <koalageddon/vstdlib.hpp>
#include <core/macros.hpp> #include <core/macros.hpp>
#include <koalageddon/koalageddon.hpp>
#include <steam_functions/steam_functions.hpp>
#include <koalabox/hook.hpp> #include <koalabox/hook.hpp>
#include <koalabox/logger.hpp>
using namespace koalageddon; using namespace koalageddon;
using namespace koalabox;
VIRTUAL(bool) SharedLicensesLockStatus(PARAMS(void* arg)) { // NOLINT(misc-unused-parameters) namespace koalageddon::vstdlib {
logger->debug("{} -> instance: {}, arg: {}", __func__, fmt::ptr(THIS), fmt::ptr(arg)); using namespace koalabox;
return true;
}
VIRTUAL(bool) SharedLibraryStopPlaying(PARAMS(void* arg)) { // NOLINT(misc-unused-parameters) VIRTUAL(bool) SharedLicensesLockStatus(PARAMS(void* arg)) {
logger->debug("{} -> instance: {}, arg: {}", __func__, fmt::ptr(THIS), fmt::ptr(arg)); LOG_DEBUG("{} -> ecx: {}, edx: {}, arg: {}", __func__, ARGS(arg))
return true; return true;
}
struct CallbackData {
FunctionAddress get_callback_intercept_address() {
return reinterpret_cast<FunctionAddress*>(this)[koalageddon::config.vstdlib_callback_interceptor_address_offset];
} }
FunctionAddress get_callback_address() { VIRTUAL(bool) SharedLibraryStopPlaying(PARAMS(void* arg)) {
return reinterpret_cast<FunctionAddress*>(this)[koalageddon::config.vstdlib_callback_address_offset]; LOG_DEBUG("{} -> ecx: {}, edx: {}, arg: {}", __func__, ARGS(arg))
} return true;
};
struct CoroutineData {
CallbackData* get_callback_data() {
return reinterpret_cast<CallbackData**>(this)[koalageddon::config.vstdlib_callback_data_offset];
} }
const char* get_callback_name() { VIRTUAL(void) VStdLib_Callback_Interceptor(PARAMS(const char** name_ptr)) {
return reinterpret_cast<const char**>(this)[koalageddon::config.vstdlib_callback_name_offset]; GET_ORIGINAL_HOOKED_FUNCTION(VStdLib_Callback_Interceptor)
} VStdLib_Callback_Interceptor_o(ARGS(name_ptr));
};
VIRTUAL(void) VStdLib_Callback_Interceptor(PARAMS(const char** p_name)) { static auto lock_status_hooked = false;
GET_ORIGINAL_HOOKED_FUNCTION(VStdLib_Callback_Interceptor) static auto stop_playing_hooked = false;
VStdLib_Callback_Interceptor_o(ARGS(p_name)); if (lock_status_hooked && stop_playing_hooked) {
return;
}
static auto lock_status_hooked = false; auto* const data = (CoroutineData*) THIS;
static auto stop_playing_hooked = false;
if (lock_status_hooked && stop_playing_hooked) { if (data && data->get_callback_name()) {
return; const auto name = String(data->get_callback_name());
} LOG_TRACE("{} -> instance: {}, name: '{}'", __func__, fmt::ptr(THIS), name)
auto* const data = (CoroutineData*) THIS; if (name == "SharedLicensesLockStatus" && !lock_status_hooked) {
DETOUR_ADDRESS(SharedLicensesLockStatus, data->get_callback_data()->get_callback_address())
if (data && data->get_callback_name()) { lock_status_hooked = true;
const auto name = String(data->get_callback_name()); } else if (name == "SharedLibraryStopPlaying" && !stop_playing_hooked) {
TRACE("{} -> instance: {}, name: '{}'", __func__, fmt::ptr(THIS), name) DETOUR_ADDRESS(SharedLibraryStopPlaying, data->get_callback_data()->get_callback_address())
stop_playing_hooked = true;
}
if (name == "SharedLicensesLockStatus" && !lock_status_hooked) {
DETOUR_ADDRESS(SharedLicensesLockStatus, data->get_callback_data()->get_callback_address())
lock_status_hooked = true;
} else if (name == "SharedLibraryStopPlaying" && !stop_playing_hooked) {
DETOUR_ADDRESS(SharedLibraryStopPlaying, data->get_callback_data()->get_callback_address())
stop_playing_hooked = true;
} }
} }
}
/**
/** * Initially, callback data passed into this function is not complete,
* Initially, callback data passed into this function is not complete, * hence we must hook an interface method that sets the callback name.
* hence we must hook an interface method that sets the callback name. */
*/ DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, CoroutineData* data) {
DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, CoroutineData* data) { GET_ORIGINAL_HOOKED_FUNCTION(Coroutine_Create)
GET_ORIGINAL_HOOKED_FUNCTION(Coroutine_Create)
const auto result = Coroutine_Create_o(callback_address, data);
const auto result = Coroutine_Create_o(callback_address, data);
// Coroutine callback appears to be always the same
// Coroutine callback appears to be always the same CALL_ONCE({
static std::once_flag flag; LOG_DEBUG("Coroutine_Create -> callback: {}, data: {}", callback_address, fmt::ptr(data));
std::call_once(
flag, [&]() { DETOUR_ADDRESS(
logger->debug("Coroutine_Create -> callback: {}, data: {}", callback_address, fmt::ptr(data)); VStdLib_Callback_Interceptor,
data->get_callback_data()->get_callback_intercept_address()
DETOUR_ADDRESS(VStdLib_Callback_Interceptor, data->get_callback_data()->get_callback_intercept_address()) )
} })
);
return result;
return result; }
} }

View File

@@ -0,0 +1,29 @@
#include <core/macros.hpp>
#include <koalabox/types.hpp>
#include <koalageddon/koalageddon.hpp>
namespace koalageddon::vstdlib {
struct CallbackData {
uintptr_t get_callback_intercept_address() {
return reinterpret_cast<uintptr_t*>(this)[koalageddon::config.vstdlib_callback_interceptor_address_offset];
}
uintptr_t get_callback_address() {
return reinterpret_cast<uintptr_t*>(this)[koalageddon::config.vstdlib_callback_address_offset];
}
};
struct CoroutineData {
CallbackData* get_callback_data() {
return reinterpret_cast<CallbackData**>(this)[koalageddon::config.vstdlib_callback_data_offset];
}
const char* get_callback_name() {
return reinterpret_cast<const char**>(this)[koalageddon::config.vstdlib_callback_name_offset];
}
};
typedef uint32_t HCoroutine;
DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, CoroutineData* data);
}

View File

@@ -6,7 +6,7 @@
#include <steam_functions/steam_functions.hpp> #include <steam_functions/steam_functions.hpp>
#include <koalabox/config_parser.hpp> #include <koalabox/config_parser.hpp>
#include <koalabox/dll_monitor.hpp> #include <koalabox/dll_monitor.hpp>
#include <koalabox/file_logger.hpp> #include <koalabox/logger.hpp>
#include <koalabox/hook.hpp> #include <koalabox/hook.hpp>
#include <koalabox/loader.hpp> #include <koalabox/loader.hpp>
#include <koalabox/win_util.hpp> #include <koalabox/win_util.hpp>
@@ -20,21 +20,23 @@ namespace smoke_api {
using namespace koalabox; using namespace koalabox;
void init_proxy_mode() { void init_proxy_mode() {
logger->info("🔀 Detected proxy mode"); LOG_INFO("🔀 Detected proxy mode")
globals::steamapi_module = loader::load_original_library(paths::get_self_path(), STEAMAPI_DLL); globals::steamapi_module = loader::load_original_library(paths::get_self_path(), STEAMAPI_DLL);
} }
void init_hook_mode() { void init_hook_mode() {
logger->info("🪝 Detected hook mode"); LOG_INFO("🪝 Detected hook mode")
dll_monitor::init(STEAMCLIENT_DLL, [](const HMODULE& library) { dll_monitor::init(
globals::steamclient_module = library; STEAMCLIENT_DLL, [](const HMODULE& library) {
globals::steamclient_module = library;
DETOUR_STEAMCLIENT(CreateInterface) DETOUR_STEAMCLIENT(CreateInterface)
dll_monitor::shutdown(); dll_monitor::shutdown();
}); }
);
// Hooking steam_api has shown itself to be less desirable than steamclient // Hooking steam_api has shown itself to be less desirable than steamclient
// for the reasons outlined below: // for the reasons outlined below:
@@ -80,41 +82,35 @@ namespace smoke_api {
globals::smokeapi_handle = module_handle; globals::smokeapi_handle = module_handle;
koalabox::project_name = PROJECT_NAME;
config::init(); config::init();
if (config::instance.logging) {
logger::init_file_logger(paths::get_log_path());
}
LOG_INFO("🐨 {} v{}", PROJECT_NAME, PROJECT_VERSION)
const auto exe_path = Path(win_util::get_module_file_name_or_throw(nullptr)); const auto exe_path = Path(win_util::get_module_file_name_or_throw(nullptr));
const auto exe_name = exe_path.filename().string(); const auto exe_name = exe_path.filename().string();
const auto exe_bitness = util::is_x64() ? 64 : 32; const auto exe_bitness = util::is_x64() ? 64 : 32;
if (config::instance.logging) { LOG_DEBUG(R"(Process name: "{}" [{}-bit])", exe_name, exe_bitness)
logger = file_logger::create(paths::get_log_path());
}
logger->info("🐨 {} v{}", PROJECT_NAME, PROJECT_VERSION);
logger->debug(R"(Process name: "{}" [{}-bit])", exe_name, exe_bitness);
if (hook::is_hook_mode(globals::smokeapi_handle, STEAMAPI_DLL)) { if (hook::is_hook_mode(globals::smokeapi_handle, STEAMAPI_DLL)) {
hook::init(true); hook::init(true);
#ifdef _WIN64
init_hook_mode();
#else
// TODO: Check if it's steam from valve
if (is_valve_steam(exe_name)) { if (is_valve_steam(exe_name)) {
logger->info("🐨💥 Detected Koalageddon mode"); #ifndef _WIN64
LOG_INFO("🐨💥 Detected Koalageddon mode")
koalageddon::init(); koalageddon::init();
#endif
} else { } else {
init_hook_mode(); init_hook_mode();
} }
#endif
} else { } else {
init_proxy_mode(); init_proxy_mode();
} }
logger->info("🚀 Initialization complete"); LOG_INFO("🚀 Initialization complete")
} catch (const Exception& ex) { } catch (const Exception& ex) {
util::panic(fmt::format("Initialization error: {}", ex.what())); util::panic(fmt::format("Initialization error: {}", ex.what()));
} }
@@ -126,9 +122,9 @@ namespace smoke_api {
win_util::free_library(globals::steamapi_module); win_util::free_library(globals::steamapi_module);
} }
logger->info("💀 Shutdown complete"); LOG_INFO("💀 Shutdown complete")
} catch (const Exception& ex) { } catch (const Exception& ex) {
logger->error("Shutdown error: {}", ex.what()); LOG_ERROR("Shutdown error: {}", ex.what())
} }
} }
} }

View File

@@ -1,35 +1,43 @@
#include <core/macros.hpp> #include <core/macros.hpp>
#include <core/steam_types.hpp>
#include <steam_impl/steam_apps.hpp> #include <steam_impl/steam_apps.hpp>
#include <steam_impl/steam_client.hpp> #include <steam_impl/steam_client.hpp>
#include <steam_impl/steam_inventory.hpp> #include <steam_impl/steam_inventory.hpp>
#include <steam_impl/steam_user.hpp> #include <steam_impl/steam_user.hpp>
#include <steam_functions/steam_functions.hpp>
using namespace koalabox; using namespace koalabox;
// ISteamApps // ISteamApps
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(ISteamApps* self, AppId_t appID) { DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(ISteamApps* self, AppId_t appID) {
return steam_apps::IsDlcUnlocked(__func__, 0, appID, [&]() { return steam_apps::IsDlcUnlocked(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_BIsSubscribedApp) __func__, 0, appID, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_BIsSubscribedApp)
return SteamAPI_ISteamApps_BIsSubscribedApp_o(self, appID); return SteamAPI_ISteamApps_BIsSubscribedApp_o(self, appID);
}); }
);
} }
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsDlcInstalled(ISteamApps* self, AppId_t appID) { DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsDlcInstalled(ISteamApps* self, AppId_t appID) {
return steam_apps::IsDlcUnlocked(__func__, 0, appID, [&]() { return steam_apps::IsDlcUnlocked(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_BIsDlcInstalled) __func__, 0, appID, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_BIsDlcInstalled)
return SteamAPI_ISteamApps_BIsDlcInstalled_o(self, appID); return SteamAPI_ISteamApps_BIsDlcInstalled_o(self, appID);
}); }
);
} }
DLL_EXPORT(int) SteamAPI_ISteamApps_GetDLCCount(ISteamApps* self) { DLL_EXPORT(int) SteamAPI_ISteamApps_GetDLCCount(ISteamApps* self) {
return steam_apps::GetDLCCount(__func__, 0, [&]() { return steam_apps::GetDLCCount(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_GetDLCCount) __func__, 0, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_GetDLCCount)
return SteamAPI_ISteamApps_GetDLCCount_o(self); return SteamAPI_ISteamApps_GetDLCCount_o(self);
}); }
);
} }
DLL_EXPORT(bool) SteamAPI_ISteamApps_BGetDLCDataByIndex( DLL_EXPORT(bool) SteamAPI_ISteamApps_BGetDLCDataByIndex(
@@ -40,13 +48,15 @@ DLL_EXPORT(bool) SteamAPI_ISteamApps_BGetDLCDataByIndex(
char* pchName, char* pchName,
int cchNameBufferSize int cchNameBufferSize
) { ) {
return steam_apps::GetDLCDataByIndex(__func__, 0, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize, [&]() { return steam_apps::GetDLCDataByIndex(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_BGetDLCDataByIndex) __func__, 0, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_BGetDLCDataByIndex)
return SteamAPI_ISteamApps_BGetDLCDataByIndex_o( return SteamAPI_ISteamApps_BGetDLCDataByIndex_o(
self, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize self, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize
); );
}); }
);
} }
// ISteamUser // ISteamUser
@@ -56,11 +66,13 @@ DLL_EXPORT(EUserHasLicenseForAppResult) SteamAPI_ISteamUser_UserHasLicenseForApp
CSteamID steamID, CSteamID steamID,
AppId_t appID AppId_t appID
) { ) {
return steam_user::UserHasLicenseForApp(__func__, appID, [&]() { return steam_user::UserHasLicenseForApp(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamUser_UserHasLicenseForApp) __func__, appID, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamUser_UserHasLicenseForApp)
return SteamAPI_ISteamUser_UserHasLicenseForApp_o(self, steamID, appID); return SteamAPI_ISteamUser_UserHasLicenseForApp_o(self, steamID, appID);
}); }
);
} }
// ISteamClient // ISteamClient
@@ -71,11 +83,13 @@ DLL_EXPORT(void*) SteamAPI_ISteamClient_GetISteamGenericInterface(
HSteamPipe hSteamPipe, HSteamPipe hSteamPipe,
const char* pchVersion const char* pchVersion
) { ) {
return steam_client::GetGenericInterface(__func__, pchVersion, [&]() { return steam_client::GetGenericInterface(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamClient_GetISteamGenericInterface) __func__, pchVersion, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamClient_GetISteamGenericInterface)
return SteamAPI_ISteamClient_GetISteamGenericInterface_o(self, hSteamUser, hSteamPipe, pchVersion); return SteamAPI_ISteamClient_GetISteamGenericInterface_o(self, hSteamUser, hSteamPipe, pchVersion);
}); }
);
} }
// ISteamInventory // ISteamInventory
@@ -84,11 +98,13 @@ DLL_EXPORT(EResult) SteamAPI_ISteamInventory_GetResultStatus(
ISteamInventory* self, ISteamInventory* self,
SteamInventoryResult_t resultHandle SteamInventoryResult_t resultHandle
) { ) {
return steam_inventory::GetResultStatus(__func__, resultHandle, [&]() { return steam_inventory::GetResultStatus(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetResultStatus) __func__, resultHandle, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetResultStatus)
return SteamAPI_ISteamInventory_GetResultStatus_o(self, resultHandle); return SteamAPI_ISteamInventory_GetResultStatus_o(self, resultHandle);
}); }
);
} }
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItems( DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItems(
@@ -136,22 +152,26 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_CheckResultSteamID(
SteamInventoryResult_t resultHandle, SteamInventoryResult_t resultHandle,
CSteamID steamIDExpected CSteamID steamIDExpected
) { ) {
return steam_inventory::CheckResultSteamID(__func__, resultHandle, steamIDExpected, [&]() { return steam_inventory::CheckResultSteamID(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_CheckResultSteamID) __func__, resultHandle, steamIDExpected, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_CheckResultSteamID)
return SteamAPI_ISteamInventory_CheckResultSteamID_o(self, resultHandle, steamIDExpected); return SteamAPI_ISteamInventory_CheckResultSteamID_o(self, resultHandle, steamIDExpected);
}); }
);
} }
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetAllItems( DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetAllItems(
ISteamInventory* self, ISteamInventory* self,
SteamInventoryResult_t* pResultHandle SteamInventoryResult_t* pResultHandle
) { ) {
return steam_inventory::GetAllItems(__func__, pResultHandle, [&]() { return steam_inventory::GetAllItems(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetAllItems) __func__, pResultHandle, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetAllItems)
return SteamAPI_ISteamInventory_GetAllItems_o(self, pResultHandle); return SteamAPI_ISteamInventory_GetAllItems_o(self, pResultHandle);
}); }
);
} }
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemsByID( DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemsByID(
@@ -160,11 +180,13 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemsByID(
const SteamItemInstanceID_t* pInstanceIDs, const SteamItemInstanceID_t* pInstanceIDs,
uint32_t unCountInstanceIDs uint32_t unCountInstanceIDs
) { ) {
return steam_inventory::GetItemsByID(__func__, pResultHandle, pInstanceIDs, unCountInstanceIDs, [&]() { return steam_inventory::GetItemsByID(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetItemsByID) __func__, pResultHandle, pInstanceIDs, unCountInstanceIDs, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetItemsByID)
return SteamAPI_ISteamInventory_GetItemsByID_o(self, pResultHandle, pInstanceIDs, unCountInstanceIDs); return SteamAPI_ISteamInventory_GetItemsByID_o(self, pResultHandle, pInstanceIDs, unCountInstanceIDs);
}); }
);
} }
DLL_EXPORT(bool) SteamAPI_ISteamInventory_SerializeResult( DLL_EXPORT(bool) SteamAPI_ISteamInventory_SerializeResult(
@@ -173,11 +195,13 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_SerializeResult(
void* pOutBuffer, void* pOutBuffer,
uint32_t* punOutBufferSize uint32_t* punOutBufferSize
) { ) {
return steam_inventory::SerializeResult(__func__, resultHandle, pOutBuffer, punOutBufferSize, [&]() { return steam_inventory::SerializeResult(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_SerializeResult) __func__, resultHandle, pOutBuffer, punOutBufferSize, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_SerializeResult)
return SteamAPI_ISteamInventory_SerializeResult_o(self, resultHandle, pOutBuffer, punOutBufferSize); return SteamAPI_ISteamInventory_SerializeResult_o(self, resultHandle, pOutBuffer, punOutBufferSize);
}); }
);
} }
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemDefinitionIDs( DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemDefinitionIDs(
@@ -185,9 +209,11 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemDefinitionIDs(
SteamItemDef_t* pItemDefIDs, SteamItemDef_t* pItemDefIDs,
uint32_t* punItemDefIDsArraySize uint32_t* punItemDefIDsArraySize
) { ) {
return steam_inventory::GetItemDefinitionIDs(__func__, pItemDefIDs, punItemDefIDsArraySize, [&]() { return steam_inventory::GetItemDefinitionIDs(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetItemDefinitionIDs) __func__, pItemDefIDs, punItemDefIDsArraySize, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetItemDefinitionIDs)
return SteamAPI_ISteamInventory_GetItemDefinitionIDs_o(self, pItemDefIDs, punItemDefIDsArraySize); return SteamAPI_ISteamInventory_GetItemDefinitionIDs_o(self, pItemDefIDs, punItemDefIDsArraySize);
}); }
);
} }

View File

@@ -1,21 +1,26 @@
#include <core/macros.hpp> #include <core/macros.hpp>
#include <koalabox/hook.hpp> #include <core/steam_types.hpp>
#include <steam_impl/steam_client.hpp> #include <steam_impl/steam_client.hpp>
#include <koalabox/hook.hpp>
using namespace koalabox; using namespace koalabox;
DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(HSteamUser hSteamUser, const char* version) { DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(HSteamUser hSteamUser, const char* version) {
return steam_client::GetGenericInterface(__func__, version, [&]() { return steam_client::GetGenericInterface(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamInternal_FindOrCreateUserInterface) __func__, version, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamInternal_FindOrCreateUserInterface)
return SteamInternal_FindOrCreateUserInterface_o(hSteamUser, version); return SteamInternal_FindOrCreateUserInterface_o(hSteamUser, version);
}); }
);
} }
DLL_EXPORT(void*) SteamInternal_CreateInterface(const char* version) { DLL_EXPORT(void*) SteamInternal_CreateInterface(const char* version) {
return steam_client::GetGenericInterface(__func__, version, [&]() { return steam_client::GetGenericInterface(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamInternal_CreateInterface) __func__, version, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamInternal_CreateInterface)
return SteamInternal_CreateInterface_o(version); return SteamInternal_CreateInterface_o(version);
}); }
);
} }

View File

@@ -1,12 +1,12 @@
#include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_client.hpp> #include <steam_impl/steam_client.hpp>
#include <core/macros.hpp>
#include <koalabox/logger.hpp>
#include <koalabox/win_util.hpp> #include <koalabox/win_util.hpp>
#include <koalabox/util.hpp>
#include <steam_functions/steam_functions.hpp>
#include <regex> #include <regex>
using namespace smoke_api; using namespace koalabox;
using namespace steam_functions;
/** /**
* Searches the `.rdata` section of the original dll for the full interface version string * Searches the `.rdata` section of the original dll for the full interface version string
@@ -28,10 +28,10 @@ String get_versioned_interface(const String& version_prefix, const String& fallb
throw util::exception("No match found for '{}'", version_prefix); throw util::exception("No match found for '{}'", version_prefix);
} catch (const Exception& ex) { } catch (const Exception& ex) {
logger->error( LOG_ERROR(
"Failed to get versioned interface: {}." "Failed to get versioned interface: {}."
"Falling back to version {}", ex.what(), fallback "Falling back to version {}", ex.what(), fallback
); )
version_map[version_prefix] = version_prefix + fallback; version_map[version_prefix] = version_prefix + fallback;
} }
@@ -41,41 +41,49 @@ String get_versioned_interface(const String& version_prefix, const String& fallb
} }
DLL_EXPORT(void*) SteamClient() { DLL_EXPORT(void*) SteamClient() {
static auto version = get_versioned_interface(STEAM_CLIENT, "006"); static auto version = get_versioned_interface(steam_functions::STEAM_CLIENT, "006");
return steam_client::GetGenericInterface(__func__, version, [&]() { return steam_client::GetGenericInterface(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamClient) __func__, version, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamClient)
return SteamClient_o(); return SteamClient_o();
}); }
);
} }
DLL_EXPORT(void*) SteamApps() { DLL_EXPORT(void*) SteamApps() {
static auto version = get_versioned_interface(STEAM_APPS, "002"); static auto version = get_versioned_interface(steam_functions::STEAM_APPS, "002");
return steam_client::GetGenericInterface(__func__, version, [&]() { return steam_client::GetGenericInterface(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamApps) __func__, version, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamApps)
return SteamApps_o(); return SteamApps_o();
}); }
);
} }
DLL_EXPORT(void*) SteamUser() { DLL_EXPORT(void*) SteamUser() {
static auto version = get_versioned_interface(STEAM_USER, "012"); static auto version = get_versioned_interface(steam_functions::STEAM_USER, "012");
return steam_client::GetGenericInterface(__func__, version, [&]() { return steam_client::GetGenericInterface(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamUser) __func__, version, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamUser)
return SteamUser_o(); return SteamUser_o();
}); }
);
} }
DLL_EXPORT(void*) SteamInventory() { DLL_EXPORT(void*) SteamInventory() {
static auto version = get_versioned_interface(STEAM_INVENTORY, "001"); static auto version = get_versioned_interface(steam_functions::STEAM_INVENTORY, "001");
return steam_client::GetGenericInterface(__func__, version, [&]() { return steam_client::GetGenericInterface(
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamInventory) __func__, version, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamInventory)
return SteamInventory_o(); return SteamInventory_o();
}); }
);
} }

View File

@@ -1,28 +1,34 @@
#include <steam_impl/steam_apps.hpp> #include <steam_impl/steam_apps.hpp>
#include <core/macros.hpp>
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t appID)) { // NOLINT(misc-unused-parameters) VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t appID)) {
return steam_apps::IsDlcUnlocked(__func__, 0, appID, [&]() { return steam_apps::IsDlcUnlocked(
GET_ORIGINAL_FUNCTION_STEAMAPI(ISteamApps_BIsSubscribedApp) __func__, 0, appID, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(ISteamApps_BIsSubscribedApp)
return ISteamApps_BIsSubscribedApp_o(ARGS(appID)); return ISteamApps_BIsSubscribedApp_o(ARGS(appID));
}); }
);
} }
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(AppId_t appID)) { // NOLINT(misc-unused-parameters) VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(AppId_t appID)) {
return steam_apps::IsDlcUnlocked(__func__, 0, appID, [&]() { return steam_apps::IsDlcUnlocked(
GET_ORIGINAL_FUNCTION_STEAMAPI(ISteamApps_BIsDlcInstalled) __func__, 0, appID, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(ISteamApps_BIsDlcInstalled)
return ISteamApps_BIsDlcInstalled_o(ARGS(appID)); return ISteamApps_BIsDlcInstalled_o(ARGS(appID));
}); }
);
} }
VIRTUAL(int) ISteamApps_GetDLCCount(PARAMS()) { VIRTUAL(int) ISteamApps_GetDLCCount(PARAMS()) {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamApps_GetDLCCount) GET_ORIGINAL_HOOKED_FUNCTION(ISteamApps_GetDLCCount)
return steam_apps::GetDLCCount(__func__, 0, [&]() { return steam_apps::GetDLCCount(
__func__, 0, [&]() {
return ISteamApps_GetDLCCount_o(ARGS()); return ISteamApps_GetDLCCount_o(ARGS());
}); }
);
} }
VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex( VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(
@@ -34,11 +40,13 @@ VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(
int cchNameBufferSize int cchNameBufferSize
) )
) { ) {
return steam_apps::GetDLCDataByIndex(__func__, 0, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize, [&]() { return steam_apps::GetDLCDataByIndex(
GET_ORIGINAL_HOOKED_FUNCTION(ISteamApps_BGetDLCDataByIndex) __func__, 0, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamApps_BGetDLCDataByIndex)
return ISteamApps_BGetDLCDataByIndex_o( return ISteamApps_BGetDLCDataByIndex_o(
ARGS(iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize) ARGS(iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize)
); );
}); }
);
} }

View File

@@ -1,7 +1,5 @@
#include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_client.hpp> #include <steam_impl/steam_client.hpp>
#include <steam_functions/steam_functions.hpp>
using namespace smoke_api;
VIRTUAL(void*) ISteamClient_GetISteamApps( VIRTUAL(void*) ISteamClient_GetISteamApps(
PARAMS( PARAMS(
@@ -10,11 +8,13 @@ VIRTUAL(void*) ISteamClient_GetISteamApps(
const char* version const char* version
) )
) { ) {
return steam_client::GetGenericInterface(__func__, version, [&]() { return steam_client::GetGenericInterface(
GET_ORIGINAL_HOOKED_FUNCTION(ISteamClient_GetISteamApps) __func__, version, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamClient_GetISteamApps)
return ISteamClient_GetISteamApps_o(ARGS(hSteamUser, hSteamPipe, version)); return ISteamClient_GetISteamApps_o(ARGS(hSteamUser, hSteamPipe, version));
}); }
);
} }
VIRTUAL(void*) ISteamClient_GetISteamUser( VIRTUAL(void*) ISteamClient_GetISteamUser(
@@ -24,11 +24,13 @@ VIRTUAL(void*) ISteamClient_GetISteamUser(
const char* version const char* version
) )
) { ) {
return steam_client::GetGenericInterface(__func__, version, [&]() { return steam_client::GetGenericInterface(
GET_ORIGINAL_HOOKED_FUNCTION(ISteamClient_GetISteamUser) __func__, version, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamClient_GetISteamUser)
return ISteamClient_GetISteamUser_o(ARGS(hSteamUser, hSteamPipe, version)); return ISteamClient_GetISteamUser_o(ARGS(hSteamUser, hSteamPipe, version));
}); }
);
} }
VIRTUAL(void*) ISteamClient_GetISteamGenericInterface( VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(
@@ -38,11 +40,13 @@ VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(
const char* pchVersion const char* pchVersion
) )
) { ) {
return steam_client::GetGenericInterface(__func__, pchVersion, [&]() { return steam_client::GetGenericInterface(
GET_ORIGINAL_HOOKED_FUNCTION(ISteamClient_GetISteamGenericInterface) __func__, pchVersion, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamClient_GetISteamGenericInterface)
return ISteamClient_GetISteamGenericInterface_o(ARGS(hSteamUser, hSteamPipe, pchVersion)); return ISteamClient_GetISteamGenericInterface_o(ARGS(hSteamUser, hSteamPipe, pchVersion));
}); }
);
} }
VIRTUAL(void*) ISteamClient_GetISteamInventory( VIRTUAL(void*) ISteamClient_GetISteamInventory(
@@ -52,9 +56,11 @@ VIRTUAL(void*) ISteamClient_GetISteamInventory(
const char* pchVersion const char* pchVersion
) )
) { ) {
return steam_client::GetGenericInterface(__func__, pchVersion, [&]() { return steam_client::GetGenericInterface(
GET_ORIGINAL_HOOKED_FUNCTION(ISteamClient_GetISteamInventory) __func__, pchVersion, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamClient_GetISteamInventory)
return ISteamClient_GetISteamInventory_o(ARGS(hSteamUser, hSteamPipe, pchVersion)); return ISteamClient_GetISteamInventory_o(ARGS(hSteamUser, hSteamPipe, pchVersion));
}); }
);
} }

View File

@@ -1,14 +1,14 @@
#include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_inventory.hpp> #include <steam_impl/steam_inventory.hpp>
#include <steam_functions/steam_functions.hpp>
using namespace smoke_api;
VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(SteamInventoryResult_t resultHandle)) { VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(SteamInventoryResult_t resultHandle)) {
return steam_inventory::GetResultStatus(__func__, resultHandle, [&]() { return steam_inventory::GetResultStatus(
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_GetResultStatus) __func__, resultHandle, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_GetResultStatus)
return ISteamInventory_GetResultStatus_o(ARGS(resultHandle)); return ISteamInventory_GetResultStatus_o(ARGS(resultHandle));
}); }
);
} }
VIRTUAL(bool) ISteamInventory_GetResultItems( VIRTUAL(bool) ISteamInventory_GetResultItems(
@@ -18,7 +18,6 @@ VIRTUAL(bool) ISteamInventory_GetResultItems(
uint32_t * punOutItemsArraySize uint32_t * punOutItemsArraySize
) )
) { ) {
return steam_inventory::GetResultItems( return steam_inventory::GetResultItems(
__func__, resultHandle, pOutItemsArray, punOutItemsArraySize, __func__, resultHandle, pOutItemsArray, punOutItemsArraySize,
[&]() { [&]() {
@@ -60,19 +59,23 @@ VIRTUAL(bool) ISteamInventory_CheckResultSteamID(
CSteamID steamIDExpected CSteamID steamIDExpected
) )
) { ) {
return steam_inventory::CheckResultSteamID(__func__, resultHandle, steamIDExpected, [&]() { return steam_inventory::CheckResultSteamID(
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_CheckResultSteamID) __func__, resultHandle, steamIDExpected, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_CheckResultSteamID)
return ISteamInventory_CheckResultSteamID_o(ARGS(resultHandle, steamIDExpected)); return ISteamInventory_CheckResultSteamID_o(ARGS(resultHandle, steamIDExpected));
}); }
);
} }
VIRTUAL(bool) ISteamInventory_GetAllItems(PARAMS(SteamInventoryResult_t* pResultHandle)) { VIRTUAL(bool) ISteamInventory_GetAllItems(PARAMS(SteamInventoryResult_t* pResultHandle)) {
return steam_inventory::GetAllItems(__func__, pResultHandle, [&]() { return steam_inventory::GetAllItems(
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_GetAllItems) __func__, pResultHandle, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_GetAllItems)
return ISteamInventory_GetAllItems_o(ARGS(pResultHandle)); return ISteamInventory_GetAllItems_o(ARGS(pResultHandle));
}); }
);
} }
VIRTUAL(bool) ISteamInventory_GetItemsByID( VIRTUAL(bool) ISteamInventory_GetItemsByID(
@@ -82,11 +85,13 @@ VIRTUAL(bool) ISteamInventory_GetItemsByID(
uint32_t unCountInstanceIDs uint32_t unCountInstanceIDs
) )
) { ) {
return steam_inventory::GetItemsByID(__func__, pResultHandle, pInstanceIDs, unCountInstanceIDs, [&]() { return steam_inventory::GetItemsByID(
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_GetItemsByID) __func__, pResultHandle, pInstanceIDs, unCountInstanceIDs, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_GetItemsByID)
return ISteamInventory_GetItemsByID_o(ARGS(pResultHandle, pInstanceIDs, unCountInstanceIDs)); return ISteamInventory_GetItemsByID_o(ARGS(pResultHandle, pInstanceIDs, unCountInstanceIDs));
}); }
);
} }
VIRTUAL(bool) ISteamInventory_SerializeResult( VIRTUAL(bool) ISteamInventory_SerializeResult(
@@ -96,11 +101,13 @@ VIRTUAL(bool) ISteamInventory_SerializeResult(
uint32_t * punOutBufferSize uint32_t * punOutBufferSize
) )
) { ) {
return steam_inventory::SerializeResult(__func__, resultHandle, pOutBuffer, punOutBufferSize, [&]() { return steam_inventory::SerializeResult(
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_SerializeResult) __func__, resultHandle, pOutBuffer, punOutBufferSize, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_SerializeResult)
return ISteamInventory_SerializeResult_o(ARGS(resultHandle, pOutBuffer, punOutBufferSize)); return ISteamInventory_SerializeResult_o(ARGS(resultHandle, pOutBuffer, punOutBufferSize));
}); }
);
} }
VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs( VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(
@@ -109,9 +116,11 @@ VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(
uint32_t * punItemDefIDsArraySize uint32_t * punItemDefIDsArraySize
) )
) { ) {
return steam_inventory::GetItemDefinitionIDs(__func__, pItemDefIDs, punItemDefIDsArraySize, [&]() { return steam_inventory::GetItemDefinitionIDs(
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_GetItemDefinitionIDs) __func__, pItemDefIDs, punItemDefIDsArraySize, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_GetItemDefinitionIDs)
return ISteamInventory_GetItemDefinitionIDs_o(ARGS(pItemDefIDs, punItemDefIDsArraySize)); return ISteamInventory_GetItemDefinitionIDs_o(ARGS(pItemDefIDs, punItemDefIDsArraySize));
}); }
);
} }

View File

@@ -1,12 +1,12 @@
#include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_user.hpp> #include <steam_impl/steam_user.hpp>
#include <steam_functions/steam_functions.hpp>
using namespace smoke_api;
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID steamID, AppId_t appID)) { VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID steamID, AppId_t appID)) {
return steam_user::UserHasLicenseForApp(__func__, appID, [&]() { return steam_user::UserHasLicenseForApp(
GET_ORIGINAL_HOOKED_FUNCTION(ISteamUser_UserHasLicenseForApp) __func__, appID, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamUser_UserHasLicenseForApp)
return ISteamUser_UserHasLicenseForApp_o(ARGS(steamID, appID)); return ISteamUser_UserHasLicenseForApp_o(ARGS(steamID, appID));
}); }
);
} }

View File

@@ -1,8 +1,10 @@
#include <steam_functions/steam_functions.hpp> #include <steam_functions/steam_functions.hpp>
#include <koalageddon/steamclient.hpp>
#include <build_config.h> #include <build_config.h>
#include <koalabox/hook.hpp> #include <koalabox/hook.hpp>
#include <koalageddon/koalageddon.hpp>
#include <koalabox/win_util.hpp> #include <koalabox/win_util.hpp>
#include <koalabox/logger.hpp>
#include <koalabox/util.hpp>
#include <polyhook2/Misc.hpp> #include <polyhook2/Misc.hpp>
namespace steam_functions { namespace steam_functions {
@@ -82,20 +84,20 @@ namespace steam_functions {
int min_version, int min_version,
int max_version int max_version
) { ) {
logger->debug("Hooking interface '{}'", version_string); LOG_DEBUG("Hooking interface '{}'", version_string)
try { try {
const auto version_number = stoi(version_string.substr(prefix.length())); const auto version_number = stoi(version_string.substr(prefix.length()));
if (version_number < min_version) { if (version_number < min_version) {
logger->warn("Legacy version of {}: {}", version_string, version_number); LOG_WARN("Legacy version of {}: {}", version_string, version_number)
} }
if (version_number > max_version) { if (version_number > max_version) {
logger->warn( LOG_WARN(
"Unsupported new version of {}: {}. Fallback version {} will be used", "Unsupported new version of {}: {}. Fallback version {} will be used",
version_string, version_number, max_version version_string, version_number, max_version
); )
} }
return version_number; return version_number;
@@ -118,19 +120,19 @@ namespace steam_functions {
util::panic("Invalid interface version ({}) for function {}", interface_version, function_name); util::panic("Invalid interface version ({}) for function {}", interface_version, function_name);
} }
#define HOOK(MAP, FUNC) \ #define HOOK_VIRTUALS(MAP, FUNC) \
hook::swap_virtual_func( \ hook::swap_virtual_func( \
globals::address_map, \ globals::address_map, \
interface, \ interface, \
#FUNC, \ #FUNC, \
get_ordinal(MAP, #FUNC, version_number), \ get_ordinal(MAP, #FUNC, version_number), \
(FunctionAddress) (FUNC) \ reinterpret_cast<uintptr_t>(FUNC) \
); );
#define HOOK_STEAM_CLIENT(FUNC) HOOK(steam_client_ordinal_map, FUNC) #define HOOK_STEAM_CLIENT(FUNC) HOOK_VIRTUALS(steam_client_ordinal_map, FUNC)
#define HOOK_STEAM_APPS(FUNC) HOOK(steam_apps_ordinal_map, FUNC) #define HOOK_STEAM_APPS(FUNC) HOOK_VIRTUALS(steam_apps_ordinal_map, FUNC)
#define HOOK_STEAM_USER(FUNC) HOOK(steam_user_ordinal_map, FUNC) #define HOOK_STEAM_USER(FUNC) HOOK_VIRTUALS(steam_user_ordinal_map, FUNC)
#define HOOK_STEAM_INVENTORY(FUNC) HOOK(steam_inventory_ordinal_map, FUNC) #define HOOK_STEAM_INVENTORY(FUNC) HOOK_VIRTUALS(steam_inventory_ordinal_map, FUNC)
void hook_virtuals(void* interface, const String& version_string) { void hook_virtuals(void* interface, const String& version_string) {
if (interface == nullptr) { if (interface == nullptr) {
@@ -138,17 +140,15 @@ namespace steam_functions {
return; return;
} }
static Set<std::pair<void*, String>> hooked_interfaces; static Set<void*> hooked_interfaces;
const auto interface_pair = std::pair{interface, version_string}; if (hooked_interfaces.contains(interface)) {
if (hooked_interfaces.contains(interface_pair)) {
// This interface is already hooked. Skipping it. // This interface is already hooked. Skipping it.
return; return;
} }
static std::mutex section; static Mutex section;
const std::lock_guard<std::mutex> guard(section); const MutexLockGuard guard(section);
if (version_string.starts_with(STEAM_CLIENT)) { if (version_string.starts_with(STEAM_CLIENT)) {
const auto version_number = extract_version_number(version_string, STEAM_CLIENT, 6, 20); const auto version_number = extract_version_number(version_string, STEAM_CLIENT, 6, 20);
@@ -196,22 +196,12 @@ namespace steam_functions {
} }
} else if (version_string.starts_with(CLIENT_ENGINE)) { } else if (version_string.starts_with(CLIENT_ENGINE)) {
// Koalageddon mode // Koalageddon mode
koalageddon::steamclient::process_client_engine(reinterpret_cast<uintptr_t>(interface));
const auto* steam_client_internal = ((uintptr_t***) interface)[
koalageddon::config.client_engine_steam_client_internal_ordinal
];
const auto interface_selector_address = (*steam_client_internal)[
koalageddon::config.steam_client_internal_interface_selector_ordinal
];
logger->debug("Found interface selector at: {}", (void*) interface_selector_address);
koalageddon::steamclient::init(interface_selector_address);
} else { } else {
return; return;
} }
hooked_interfaces.insert(interface_pair); hooked_interfaces.insert(interface);
} }
HSteamPipe get_steam_pipe_or_throw() { HSteamPipe get_steam_pipe_or_throw() {
@@ -249,7 +239,7 @@ namespace steam_functions {
return function(ARGS(args...)); return function(ARGS(args...));
} }
uint32_t get_app_id_or_throw() { AppId_t get_app_id_or_throw() {
// Get CreateInterface // Get CreateInterface
const auto& steam_client_module = win_util::get_module_handle_or_throw(STEAMCLIENT_DLL); const auto& steam_client_module = win_util::get_module_handle_or_throw(STEAMCLIENT_DLL);
auto* CreateInterface_address = (void*) win_util::get_proc_address_or_throw( auto* CreateInterface_address = (void*) win_util::get_proc_address_or_throw(

View File

@@ -1,46 +1,9 @@
#pragma once #pragma once
#include <koalabox/koalabox.hpp>
#include <steam_types/steam_types.hpp>
#include <core/macros.hpp> #include <core/macros.hpp>
#include <core/steam_types.hpp>
#include <koalabox/types.hpp>
/**
* By default, virtual functions are declared with __thiscall
* convention, which is normal since they are class members.
* But it presents an issue for us, since we cannot pass *this
* pointer as a function argument. This is because *this
* pointer is passed via register ECX in __thiscall
* convention. Hence, to resolve this issue we declare our
* hooked functions with __fastcall convention, to trick
* the compiler into reading ECX & EDX registers as 1st
* and 2nd function arguments respectively. Similarly, __fastcall
* makes the compiler push the first argument into the ECX register,
* which mimics the __thiscall calling convention. Register EDX
* is not used anywhere in this case, but we still pass it along
* to conform to the __fastcall convention. This all applies
* to the x86 architecture.
*
* In x86-64 however, there is only one calling convention,
* so __fastcall is simply ignored. However, RDX in this case
* will store the 1st actual argument to the function, so we
* have to omit it from the function signature.
*
* The macros below implement the above-mentioned considerations.
*/
#ifdef _WIN64
#define PARAMS(...) void* RCX, ##__VA_ARGS__
#define ARGS(...) RCX, ##__VA_ARGS__
#define THIS RCX
#else
#define PARAMS(...) void* ECX, void* EDX, ##__VA_ARGS__
#define ARGS(...) ECX, EDX, ##__VA_ARGS__
#define THIS ECX
#endif
class ISteamClient;
class ISteamApps;
class ISteamUser;
class ISteamInventory;
// TODO: Refactor into multiple headers // TODO: Refactor into multiple headers
@@ -60,7 +23,7 @@ VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(PARAMS(int, AppId_t*, bool*, char*,
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t)); VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t));
// ISteamInventory // ISteamInventory
VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(uint32_t)); VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(SteamInventoryResult_t));
VIRTUAL(bool) ISteamInventory_GetResultItems(PARAMS(SteamInventoryResult_t, SteamItemDetails_t*, uint32_t*)); VIRTUAL(bool) ISteamInventory_GetResultItems(PARAMS(SteamInventoryResult_t, SteamItemDetails_t*, uint32_t*));
VIRTUAL(bool) ISteamInventory_GetResultItemProperty( VIRTUAL(bool) ISteamInventory_GetResultItemProperty(
PARAMS(SteamInventoryResult_t, uint32_t, const char*, char*, uint32_t*) PARAMS(SteamInventoryResult_t, uint32_t, const char*, char*, uint32_t*)
@@ -127,9 +90,6 @@ VIRTUAL(bool) IClientInventory_GetItemsByID(PARAMS(SteamInventoryResult_t*, cons
VIRTUAL(bool) IClientInventory_SerializeResult(PARAMS(SteamInventoryResult_t, void*, uint32_t, uint32_t *)); VIRTUAL(bool) IClientInventory_SerializeResult(PARAMS(SteamInventoryResult_t, void*, uint32_t, uint32_t *));
VIRTUAL(bool) IClientInventory_GetItemDefinitionIDs(PARAMS(SteamItemDef_t*, uint32_t, uint32_t *)); VIRTUAL(bool) IClientInventory_GetItemDefinitionIDs(PARAMS(SteamItemDef_t*, uint32_t, uint32_t *));
typedef uint32_t HCoroutine;
DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, struct CoroutineData* data);
namespace steam_functions { namespace steam_functions {
using namespace koalabox; using namespace koalabox;

View File

@@ -1,13 +1,15 @@
#include <steam_impl/steam_apps.hpp> #include <steam_impl/steam_apps.hpp>
#include <cpr/cpr.h>
#include <koalabox/io.hpp> #include <koalabox/io.hpp>
#include <koalabox/http_client.hpp> #include <koalabox/http_client.hpp>
#include <core/cache.hpp> #include <core/cache.hpp>
#include <core/config.hpp> #include <core/config.hpp>
#include <smoke_api/smoke_api.hpp> #include <koalabox/logger.hpp>
#include <koalabox/util.hpp>
#include <steam_functions/steam_functions.hpp>
#include <core/steam_types.hpp>
namespace steam_apps { namespace steam_apps {
using namespace smoke_api; using namespace koalabox;
/// Steamworks may max GetDLCCount value at 64, depending on how much unowned DLCs the user has. /// 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. /// Despite this limit, some games with more than 64 DLCs still keep using this method.
@@ -27,9 +29,9 @@ namespace steam_apps {
try { try {
app_id = steam_functions::get_app_id_or_throw(); app_id = steam_functions::get_app_id_or_throw();
// TODO: Check what it returns in koalageddon mode // TODO: Check what it returns in koalageddon mode
logger->info("Detected App ID: {}", app_id); LOG_INFO("Detected App ID: {}", app_id)
} catch (const Exception& ex) { } catch (const Exception& ex) {
logger->error("Failed to get app ID: {}", ex.what()); LOG_ERROR("Failed to get app ID: {}", ex.what())
return false; return false;
} }
} }
@@ -54,7 +56,7 @@ namespace steam_apps {
dlcs.emplace_back(std::stoi(app_id)); dlcs.emplace_back(std::stoi(app_id));
} }
} catch (const Exception& e) { } catch (const Exception& e) {
logger->error("Failed to fetch dlc list from steam api: {}", e.what()); LOG_ERROR("Failed to fetch dlc list from steam api: {}", e.what())
total_success = false; total_success = false;
} }
@@ -72,7 +74,7 @@ namespace steam_apps {
dlcs = json[app_id_str].get<decltype(dlcs)>(); dlcs = json[app_id_str].get<decltype(dlcs)>();
} }
} catch (const Exception& e) { } catch (const Exception& e) {
logger->error("Failed to fetch extra dlc list from github api: {}", e.what()); LOG_ERROR("Failed to fetch extra dlc list from github api: {}", e.what())
total_success = false; total_success = false;
} }
@@ -110,34 +112,34 @@ namespace steam_apps {
const String& function_name, const String& function_name,
AppId_t app_id, AppId_t app_id,
AppId_t dlc_id, AppId_t dlc_id,
const std::function<bool()>& original_function const Function<bool()>& original_function
) { ) {
try { try {
const auto unlocked = config::is_dlc_unlocked(app_id, dlc_id, original_function); const auto unlocked = config::is_dlc_unlocked(app_id, dlc_id, original_function);
logger->info("{} -> {}DLC ID: {}, Unlocked: {}", function_name, get_app_id_log(app_id), dlc_id, unlocked); LOG_INFO("{} -> {}DLC ID: {}, Unlocked: {}", function_name, get_app_id_log(app_id), dlc_id, unlocked)
return unlocked; return unlocked;
} catch (const Exception& e) { } catch (const Exception& e) {
logger->error("{} -> Uncaught exception: {}", function_name, e.what()); LOG_ERROR("{} -> Uncaught exception: {}", function_name, e.what())
return false; return false;
} }
} }
int GetDLCCount(const String& function_name, const AppId_t app_id, const std::function<int()>& original_function) { int GetDLCCount(const String& function_name, const AppId_t app_id, const Function<int()>& original_function) {
try { try {
const auto total_count = [&](int count) { const auto total_count = [&](int count) {
logger->info("{} -> Responding with DLC count: {}", function_name, count); LOG_INFO("{} -> Responding with DLC count: {}", function_name, count)
return count; return count;
}; };
if (app_id != 0) { if (app_id != 0) {
logger->debug("{} -> App ID: {}", function_name, app_id); LOG_DEBUG("{} -> App ID: {}", function_name, app_id)
} }
const auto original_count = original_function(); const auto original_count = original_function();
original_dlc_count_map[app_id] = original_count; original_dlc_count_map[app_id] = original_count;
logger->debug("{} -> Original DLC count: {}", function_name, original_count); LOG_DEBUG("{} -> Original DLC count: {}", function_name, original_count)
if (original_count < MAX_DLC) { if (original_count < MAX_DLC) {
return total_count(original_count); return total_count(original_count);
@@ -146,7 +148,7 @@ namespace steam_apps {
// We need to fetch DLC IDs from all possible sources at this point // We need to fetch DLC IDs from all possible sources at this point
const auto injected_count = static_cast<int>(config::instance.extra_dlc_ids.size()); const auto injected_count = static_cast<int>(config::instance.extra_dlc_ids.size());
logger->debug("{} -> Injected DLC count: {}", function_name, injected_count); LOG_DEBUG("{} -> Injected DLC count: {}", function_name, injected_count)
// Maintain a list of app_ids for which we have already fetched and cached DLC IDs // Maintain a list of app_ids for which we have already fetched and cached DLC IDs
static Set<AppId_t> cached_apps; static Set<AppId_t> cached_apps;
@@ -154,7 +156,7 @@ namespace steam_apps {
static std::mutex mutex; static std::mutex mutex;
const std::lock_guard<std::mutex> guard(mutex); const std::lock_guard<std::mutex> guard(mutex);
logger->debug("Game has {} or more DLCs. Fetching DLCs from remote sources.", MAX_DLC); LOG_DEBUG("Game has {} or more DLCs. Fetching DLCs from remote sources.", MAX_DLC)
if (fetch_and_cache_dlcs(app_id)) { if (fetch_and_cache_dlcs(app_id)) {
cached_apps.insert(app_id); cached_apps.insert(app_id);
@@ -162,11 +164,11 @@ namespace steam_apps {
} }
const auto cached_count = static_cast<int>(cached_dlcs.size()); const auto cached_count = static_cast<int>(cached_dlcs.size());
logger->debug("{} -> Cached DLC count: {}", function_name, cached_count); LOG_DEBUG("{} -> Cached DLC count: {}", function_name, cached_count)
return total_count(injected_count + cached_count); return total_count(injected_count + cached_count);
} catch (const Exception& e) { } catch (const Exception& e) {
logger->error("{} -> Uncaught exception: {}", function_name, e.what()); LOG_ERROR("{} -> Uncaught exception: {}", function_name, e.what())
return 0; return 0;
} }
} }
@@ -179,14 +181,14 @@ namespace steam_apps {
bool* pbAvailable, bool* pbAvailable,
char* pchName, char* pchName,
int cchNameBufferSize, int cchNameBufferSize,
const std::function<bool()>& original_function const Function<bool()>& original_function
) { ) {
try { try {
const auto print_dlc_info = [&](const String& tag) { const auto print_dlc_info = [&](const String& tag) {
logger->info( LOG_INFO(
"{} -> [{}] {}index: {}, DLC ID: {}, available: {}, name: '{}'", "{} -> [{}] {}index: {}, DLC ID: {}, available: {}, name: '{}'",
function_name, tag, get_app_id_log(app_id), iDLC, *pDlcId, *pbAvailable, pchName function_name, tag, get_app_id_log(app_id), iDLC, *pDlcId, *pbAvailable, pchName
); )
}; };
const auto inject_dlc = [&](const String& tag, const Vector<AppId_t>& dlc_ids, const int index) { const auto inject_dlc = [&](const String& tag, const Vector<AppId_t>& dlc_ids, const int index) {
@@ -224,7 +226,7 @@ namespace steam_apps {
*pbAvailable = config::is_dlc_unlocked(app_id, *pDlcId, [&]() { return *pbAvailable; }); *pbAvailable = config::is_dlc_unlocked(app_id, *pDlcId, [&]() { return *pbAvailable; });
print_dlc_info("original"); print_dlc_info("original");
} else { } else {
logger->warn("{} -> original call failed for index: {}", function_name, iDLC); LOG_WARN("{} -> original call failed for index: {}", function_name, iDLC)
} }
return success; return success;
} }
@@ -236,7 +238,7 @@ namespace steam_apps {
// [injected-dlc-0, injected-dlc-1, ..., cached-dlc-0, cached-dlc-1, ...] // [injected-dlc-0, injected-dlc-1, ..., cached-dlc-0, cached-dlc-1, ...]
if (iDLC < 0) { if (iDLC < 0) {
logger->warn("{} -> Out of bounds DLC index: {}", function_name, iDLC); LOG_WARN("{} -> Out of bounds DLC index: {}", function_name, iDLC)
} }
const int local_dlc_count = static_cast<int>(config::instance.extra_dlc_ids.size()); const int local_dlc_count = static_cast<int>(config::instance.extra_dlc_ids.size());
@@ -250,14 +252,14 @@ namespace steam_apps {
return inject_dlc("memory cache", cached_dlcs, adjusted_index); return inject_dlc("memory cache", cached_dlcs, adjusted_index);
} }
logger->error( LOG_ERROR(
"{} -> Out of bounds DLC index: {}, local dlc count: {}, cached dlc count: {}", "{} -> Out of bounds DLC index: {}, local dlc count: {}, cached dlc count: {}",
function_name, iDLC, local_dlc_count, cached_dlc_count function_name, iDLC, local_dlc_count, cached_dlc_count
); )
return false; return false;
} catch (const Exception& e) { } catch (const Exception& e) {
logger->error("{} -> Uncaught exception: {}", function_name, e.what()); LOG_ERROR("{} -> Uncaught exception: {}", function_name, e.what())
return false; return false;
} }
} }

View File

@@ -1,19 +1,19 @@
#include <steam_functions/steam_functions.hpp> #include <core/steam_types.hpp>
#include <koalabox/types.hpp>
namespace steam_apps { namespace steam_apps {
using namespace koalabox;
bool IsDlcUnlocked( bool IsDlcUnlocked(
const String& function_name, const String& function_name,
AppId_t app_id, AppId_t app_id,
AppId_t dlc_id, AppId_t dlc_id,
const std::function<bool()>& original_function const Function<bool()>& original_function
); );
int GetDLCCount( int GetDLCCount(
const String& function_name, const String& function_name,
AppId_t app_id, AppId_t app_id,
const std::function<int()>& original_function const Function<int()>& original_function
); );
bool GetDLCDataByIndex( bool GetDLCDataByIndex(
@@ -24,7 +24,7 @@ namespace steam_apps {
bool* pbAvailable, bool* pbAvailable,
char* pchName, char* pchName,
int cchNameBufferSize, int cchNameBufferSize,
const std::function<bool()>& original_function const Function<bool()>& original_function
); );
} }

View File

@@ -1,17 +1,17 @@
#include <steam_impl/steam_client.hpp> #include <steam_impl/steam_client.hpp>
#include <koalabox/logger.hpp>
#include <steam_functions/steam_functions.hpp>
namespace steam_client { namespace steam_client {
void* GetGenericInterface( void* GetGenericInterface(
const String& function_name, const String& function_name,
const String& interface_version, const String& interface_version,
const std::function<void*()>& original_function const Function<void*()>& original_function
) { ) {
logger->debug("{} -> Version: '{}'", function_name, interface_version);
auto* const interface = original_function(); auto* const interface = original_function();
logger->debug("{} -> Result: {}", function_name, fmt::ptr(interface)); LOG_DEBUG("{} -> '{}' @ {}", function_name, interface_version, interface)
steam_functions::hook_virtuals(interface, interface_version); steam_functions::hook_virtuals(interface, interface_version);

View File

@@ -1,13 +1,11 @@
#include <koalabox/koalabox.hpp> #include <koalabox/types.hpp>
#include <steam_functions/steam_functions.hpp>
namespace steam_client { namespace steam_client {
using namespace koalabox;
void* GetGenericInterface( void* GetGenericInterface(
const String& function_name, const String& function_name,
const String& interface_version, const String& interface_version,
const std::function<void*()>& original_function const Function<void*()>& original_function
); );
} }

View File

@@ -1,16 +1,17 @@
#include <steam_impl/steam_inventory.hpp> #include <steam_impl/steam_inventory.hpp>
#include <core/config.hpp> #include <core/config.hpp>
#include <koalabox/logger.hpp>
namespace steam_inventory { namespace steam_inventory {
EResult GetResultStatus( EResult GetResultStatus(
const String& function_name, const String& function_name,
const SteamInventoryResult_t resultHandle, const SteamInventoryResult_t resultHandle,
const std::function<EResult()>& original_function const Function<EResult()>& original_function
) { ) {
const auto status = original_function(); const auto status = original_function();
logger->debug("{} -> handle: {}, status: {}", function_name, resultHandle, (int) status); LOG_DEBUG("{} -> handle: {}, status: {}", function_name, resultHandle, (int) status)
return status; return status;
} }
@@ -20,8 +21,8 @@ namespace steam_inventory {
const SteamInventoryResult_t resultHandle, const SteamInventoryResult_t resultHandle,
SteamItemDetails_t* pOutItemsArray, SteamItemDetails_t* pOutItemsArray,
uint32_t* punOutItemsArraySize, uint32_t* punOutItemsArraySize,
const std::function<bool()>& original_function, const Function<bool()>& original_function,
const std::function<bool(SteamItemDef_t*, uint32_t*)>& get_item_definition_ids const Function<bool(SteamItemDef_t*, uint32_t*)>& get_item_definition_ids
) { ) {
static std::mutex section; static std::mutex section;
const std::lock_guard<std::mutex> guard(section); const std::lock_guard<std::mutex> guard(section);
@@ -29,26 +30,26 @@ namespace steam_inventory {
const auto success = original_function(); const auto success = original_function();
auto print_item = [](const String& tag, const SteamItemDetails_t& item) { auto print_item = [](const String& tag, const SteamItemDetails_t& item) {
logger->debug( LOG_DEBUG(
" [{}] definitionId: {}, itemId: {}, quantity: {}, flags: {}", " [{}] definitionId: {}, itemId: {}, quantity: {}, flags: {}",
tag, item.m_iDefinition, item.m_itemId, item.m_unQuantity, item.m_unFlags tag, item.m_iDefinition, item.m_itemId, item.m_unQuantity, item.m_unFlags
); )
}; };
if (not success) { if (not success) {
logger->debug("{} -> original result is false", function_name); LOG_DEBUG("{} -> original result is false", function_name)
return success; return success;
} }
if (punOutItemsArraySize == nullptr) { if (punOutItemsArraySize == nullptr) {
logger->error("{} -> arraySize pointer is null", function_name); LOG_ERROR("{} -> arraySize pointer is null", function_name)
return success; return success;
} }
logger->debug( LOG_DEBUG(
"{} -> handle: {}, pOutItemsArray: {}, arraySize: {}", "{} -> handle: {}, pOutItemsArray: {}, arraySize: {}",
function_name, resultHandle, fmt::ptr(pOutItemsArray), *punOutItemsArraySize function_name, resultHandle, fmt::ptr(pOutItemsArray), *punOutItemsArraySize
); )
static uint32_t original_count = 0; static uint32_t original_count = 0;
const auto injected_count = config::instance.extra_inventory_items.size(); const auto injected_count = config::instance.extra_inventory_items.size();
@@ -56,14 +57,13 @@ namespace steam_inventory {
// Automatically get inventory items from steam // Automatically get inventory items from steam
static Vector<SteamItemDef_t> auto_inventory_items; static Vector<SteamItemDef_t> auto_inventory_items;
if (config::instance.auto_inject_inventory) { if (config::instance.auto_inject_inventory) {
static std::once_flag flag; CALL_ONCE({
std::call_once(flag, [&]() {
uint32_t count = 0; uint32_t count = 0;
if (get_item_definition_ids(nullptr, &count)) { if (get_item_definition_ids(nullptr, &count)) {
auto_inventory_items.resize(count); auto_inventory_items.resize(count);
get_item_definition_ids(auto_inventory_items.data(), &count); get_item_definition_ids(auto_inventory_items.data(), &count);
} }
}); })
} }
const auto auto_injected_count = auto_inventory_items.size(); const auto auto_injected_count = auto_inventory_items.size();
@@ -72,10 +72,10 @@ namespace steam_inventory {
// If pOutItemsArray is NULL then we must set the array size. // If pOutItemsArray is NULL then we must set the array size.
original_count = *punOutItemsArraySize; original_count = *punOutItemsArraySize;
*punOutItemsArraySize += auto_injected_count + injected_count; *punOutItemsArraySize += auto_injected_count + injected_count;
logger->debug( LOG_DEBUG(
"{} -> Original count: {}, Total count: {}", "{} -> Original count: {}, Total count: {}",
function_name, original_count, *punOutItemsArraySize function_name, original_count, *punOutItemsArraySize
); )
} else { } else {
// Otherwise, we modify the array // Otherwise, we modify the array
for (int i = 0; i < original_count; i++) { for (int i = 0; i < original_count; i++) {
@@ -120,7 +120,7 @@ namespace steam_inventory {
const char* pchPropertyName, const char* pchPropertyName,
char* pchValueBuffer, char* pchValueBuffer,
const uint32_t* punValueBufferSizeOut, const uint32_t* punValueBufferSizeOut,
const std::function<bool()>& original_function const Function<bool()>& original_function
) { ) {
const auto common_info = fmt::format( const auto common_info = fmt::format(
"{} -> Handle: {}, Index: {}, Name: '{}'", function_name, resultHandle, unItemIndex, pchPropertyName "{} -> Handle: {}, Index: {}, Name: '{}'", function_name, resultHandle, unItemIndex, pchPropertyName
@@ -129,11 +129,11 @@ namespace steam_inventory {
const auto success = original_function(); const auto success = original_function();
if (!success) { if (!success) {
logger->warn("{}, Result is false", common_info); LOG_WARN("{}, Result is false", common_info)
return false; return false;
} }
logger->debug("{}, Buffer: '{}'", common_info, String(pchValueBuffer, *punValueBufferSizeOut - 1)); LOG_DEBUG("{}, Buffer: '{}'", common_info, String(pchValueBuffer, *punValueBufferSizeOut - 1))
return success; return success;
} }
@@ -141,11 +141,11 @@ namespace steam_inventory {
bool GetAllItems( bool GetAllItems(
const String& function_name, const String& function_name,
const SteamInventoryResult_t* pResultHandle, const SteamInventoryResult_t* pResultHandle,
const std::function<bool()>& original_function const Function<bool()>& original_function
) { ) {
const auto success = original_function(); const auto success = original_function();
logger->debug("{} -> Handle: {}", function_name, fmt::ptr(pResultHandle)); LOG_DEBUG("{} -> Handle: {}", function_name, fmt::ptr(pResultHandle))
return success; return success;
} }
@@ -156,15 +156,15 @@ namespace steam_inventory {
SteamInventoryResult_t* pResultHandle, SteamInventoryResult_t* pResultHandle,
const SteamItemInstanceID_t* pInstanceIDs, const SteamItemInstanceID_t* pInstanceIDs,
const uint32_t unCountInstanceIDs, const uint32_t unCountInstanceIDs,
const std::function<bool()>& original_function const Function<bool()>& original_function
) { ) {
const auto success = original_function(); const auto success = original_function();
logger->debug("{} -> Handle: {}", function_name, fmt::ptr(pResultHandle)); LOG_DEBUG("{} -> Handle: {}", function_name, fmt::ptr(pResultHandle))
if (success && pInstanceIDs != nullptr) { if (success && pInstanceIDs != nullptr) {
for (int i = 0; i < unCountInstanceIDs; i++) { for (int i = 0; i < unCountInstanceIDs; i++) {
logger->debug(" Index: {}, ItemId: {}", i, pInstanceIDs[i]); LOG_DEBUG(" Index: {}, ItemId: {}", i, pInstanceIDs[i])
} }
} }
@@ -176,15 +176,15 @@ namespace steam_inventory {
SteamInventoryResult_t resultHandle, SteamInventoryResult_t resultHandle,
void* pOutBuffer, void* pOutBuffer,
uint32_t* punOutBufferSize, uint32_t* punOutBufferSize,
const std::function<bool()>& original_function const Function<bool()>& original_function
) { ) {
const auto success = original_function(); const auto success = original_function();
if (pOutBuffer != nullptr) { if (pOutBuffer != nullptr) {
String buffer((char*) pOutBuffer, *punOutBufferSize); String buffer((char*) pOutBuffer, *punOutBufferSize);
logger->debug("{} -> Handle: {}, Buffer: '{}'", function_name, resultHandle, buffer); LOG_DEBUG("{} -> Handle: {}, Buffer: '{}'", function_name, resultHandle, buffer)
} else { } else {
logger->debug("{} -> Handle: {}, Size: '{}'", function_name, resultHandle, *punOutBufferSize); LOG_DEBUG("{} -> Handle: {}, Size: '{}'", function_name, resultHandle, *punOutBufferSize)
} }
return success; return success;
@@ -194,23 +194,23 @@ namespace steam_inventory {
const String& function_name, const String& function_name,
const SteamItemDef_t* pItemDefIDs, const SteamItemDef_t* pItemDefIDs,
uint32_t* punItemDefIDsArraySize, uint32_t* punItemDefIDsArraySize,
const std::function<bool()>& original_function const Function<bool()>& original_function
) { ) {
const auto success = original_function(); const auto success = original_function();
if (!success) { if (!success) {
logger->warn("{} -> Result is false", function_name); LOG_WARN("{} -> Result is false", function_name)
return false; return false;
} }
if (punItemDefIDsArraySize) { if (punItemDefIDsArraySize) {
logger->debug("{} -> Size: {}", function_name, *punItemDefIDsArraySize); LOG_DEBUG("{} -> Size: {}", function_name, *punItemDefIDsArraySize)
} }
if (pItemDefIDs) { // Definitions were copied if (pItemDefIDs) { // Definitions were copied
for (int i = 0; i < *punItemDefIDsArraySize; i++) { for (int i = 0; i < *punItemDefIDsArraySize; i++) {
const auto& def = pItemDefIDs[i]; const auto& def = pItemDefIDs[i];
logger->debug(" Index: {}, ID: {}", i, def); LOG_DEBUG(" Index: {}, ID: {}", i, def)
} }
} }
@@ -221,14 +221,14 @@ namespace steam_inventory {
const String& function_name, const String& function_name,
SteamInventoryResult_t resultHandle, SteamInventoryResult_t resultHandle,
CSteamID steamIDExpected, CSteamID steamIDExpected,
const std::function<bool()>& original_function const Function<bool()>& original_function
) { ) {
const auto result = original_function(); const auto result = original_function();
logger->debug( LOG_DEBUG(
"{} -> handle: {}, steamID: {}, original result: {}", "{} -> handle: {}, steamID: {}, original result: {}",
function_name, resultHandle, steamIDExpected, result function_name, resultHandle, steamIDExpected, result
); )
return true; return true;
} }

View File

@@ -1,13 +1,12 @@
#include <koalabox/koalabox.hpp> #include <core/steam_types.hpp>
#include <steam_functions/steam_functions.hpp> #include <koalabox/types.hpp>
namespace steam_inventory { namespace steam_inventory {
using namespace koalabox;
EResult GetResultStatus( EResult GetResultStatus(
const String& function_name, const String& function_name,
SteamInventoryResult_t resultHandle, SteamInventoryResult_t resultHandle,
const std::function<EResult()>& original_function const Function<EResult()>& original_function
); );
bool GetResultItems( bool GetResultItems(
@@ -15,8 +14,8 @@ namespace steam_inventory {
SteamInventoryResult_t resultHandle, SteamInventoryResult_t resultHandle,
SteamItemDetails_t* pOutItemsArray, SteamItemDetails_t* pOutItemsArray,
uint32_t* punOutItemsArraySize, uint32_t* punOutItemsArraySize,
const std::function<bool()>& original_function, const Function<bool()>& original_function,
const std::function<bool(SteamItemDef_t*, uint32_t*)>& get_item_definition_ids const Function<bool(SteamItemDef_t*, uint32_t*)>& get_item_definition_ids
); );
bool GetResultItemProperty( bool GetResultItemProperty(
@@ -26,13 +25,13 @@ namespace steam_inventory {
const char* pchPropertyName, const char* pchPropertyName,
char* pchValueBuffer, char* pchValueBuffer,
const uint32_t* punValueBufferSizeOut, const uint32_t* punValueBufferSizeOut,
const std::function<bool()>& original_function const Function<bool()>& original_function
); );
bool GetAllItems( bool GetAllItems(
const String& function_name, const String& function_name,
const SteamInventoryResult_t* pResultHandle, const SteamInventoryResult_t* pResultHandle,
const std::function<bool()>& original_function const Function<bool()>& original_function
); );
bool GetItemsByID( bool GetItemsByID(
@@ -40,7 +39,7 @@ namespace steam_inventory {
SteamInventoryResult_t* pResultHandle, SteamInventoryResult_t* pResultHandle,
const SteamItemInstanceID_t* pInstanceIDs, const SteamItemInstanceID_t* pInstanceIDs,
uint32_t unCountInstanceIDs, uint32_t unCountInstanceIDs,
const std::function<bool()>& original_function const Function<bool()>& original_function
); );
bool SerializeResult( bool SerializeResult(
@@ -48,14 +47,14 @@ namespace steam_inventory {
SteamInventoryResult_t resultHandle, SteamInventoryResult_t resultHandle,
void* pOutBuffer, void* pOutBuffer,
uint32_t* punOutBufferSize, uint32_t* punOutBufferSize,
const std::function<bool()>& original_function const Function<bool()>& original_function
); );
bool GetItemDefinitionIDs( bool GetItemDefinitionIDs(
const String& function_name, const String& function_name,
const SteamItemDef_t* pItemDefIDs, const SteamItemDef_t* pItemDefIDs,
uint32_t* punItemDefIDsArraySize, uint32_t* punItemDefIDsArraySize,
const std::function<bool()>& original_function const Function<bool()>& original_function
); );
@@ -63,6 +62,6 @@ namespace steam_inventory {
const String& function_name, const String& function_name,
SteamInventoryResult_t resultHandle, SteamInventoryResult_t resultHandle,
CSteamID steamIDExpected, CSteamID steamIDExpected,
const std::function<bool()>& original_function const Function<bool()>& original_function
); );
} }

View File

@@ -1,25 +1,28 @@
#include <steam_impl/steam_user.hpp> #include <steam_impl/steam_user.hpp>
#include <core/config.hpp> #include <core/config.hpp>
#include <koalabox/logger.hpp>
namespace steam_user { namespace steam_user {
EUserHasLicenseForAppResult UserHasLicenseForApp( EUserHasLicenseForAppResult UserHasLicenseForApp(
const String& function_name, const String& function_name,
AppId_t appID, AppId_t appID,
const std::function<EUserHasLicenseForAppResult()>& original_function const Function<EUserHasLicenseForAppResult()>& original_function
) { ) {
const auto result = original_function(); const auto result = original_function();
if (result == k_EUserHasLicenseResultNoAuth) { if (result == k_EUserHasLicenseResultNoAuth) {
logger->warn("{} -> App ID: {}, Result: NoAuth", function_name, appID); LOG_WARN("{} -> App ID: {}, Result: NoAuth", function_name, appID)
return result; return result;
} }
const auto has_license = config::is_dlc_unlocked(0, appID, [&]() { const auto has_license = config::is_dlc_unlocked(
return result == k_EUserHasLicenseResultHasLicense; 0, appID, [&]() {
}); return result == k_EUserHasLicenseResultHasLicense;
}
);
logger->info("{} -> App ID: {}, HasLicense: {}", function_name, appID, has_license); LOG_INFO("{} -> App ID: {}, HasLicense: {}", function_name, appID, has_license)
return has_license return has_license
? k_EUserHasLicenseResultHasLicense ? k_EUserHasLicenseResultHasLicense

View File

@@ -1,13 +1,12 @@
#include <koalabox/koalabox.hpp> #include <core/steam_types.hpp>
#include <steam_functions/steam_functions.hpp> #include <koalabox/types.hpp>
namespace steam_user { namespace steam_user {
using namespace koalabox;
EUserHasLicenseForAppResult UserHasLicenseForApp( EUserHasLicenseForAppResult UserHasLicenseForApp(
const String& function_name, const String& function_name,
AppId_t appID, AppId_t appID,
const std::function<EUserHasLicenseForAppResult()>& original_function const Function<EUserHasLicenseForAppResult()>& original_function
); );
} }

View File

@@ -1,9 +1,12 @@
#include <core/macros.hpp>
#include <steam_impl/steam_client.hpp> #include <steam_impl/steam_client.hpp>
DLL_EXPORT(void*) CreateInterface(const char* interface_string, int* out_result) { DLL_EXPORT(void*) CreateInterface(const char* interface_string, int* out_result) {
return steam_client::GetGenericInterface(__func__, interface_string, [&]() { return steam_client::GetGenericInterface(
GET_ORIGINAL_HOOKED_FUNCTION(CreateInterface) __func__, interface_string, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(CreateInterface)
return CreateInterface_o(interface_string, out_result); return CreateInterface_o(interface_string, out_result);
}); }
);
} }

View File

@@ -1,12 +1,13 @@
#include <smoke_api/smoke_api.hpp> #include <core/macros.hpp>
#include <core/steam_types.hpp>
#include <steam_impl/steam_apps.hpp> #include <steam_impl/steam_apps.hpp>
using namespace smoke_api;
VIRTUAL(bool) IClientAppManager_IsAppDlcInstalled(PARAMS(AppId_t app_id, AppId_t dlc_id)) { VIRTUAL(bool) IClientAppManager_IsAppDlcInstalled(PARAMS(AppId_t app_id, AppId_t dlc_id)) {
return steam_apps::IsDlcUnlocked(__func__, app_id, dlc_id, [&]() { return steam_apps::IsDlcUnlocked(
GET_ORIGINAL_HOOKED_FUNCTION(IClientAppManager_IsAppDlcInstalled) __func__, app_id, dlc_id, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(IClientAppManager_IsAppDlcInstalled)
return IClientAppManager_IsAppDlcInstalled_o(ARGS(app_id, dlc_id)); return IClientAppManager_IsAppDlcInstalled_o(ARGS(app_id, dlc_id));
}); }
);
} }

View File

@@ -1,14 +1,15 @@
#include <smoke_api/smoke_api.hpp> #include <core/macros.hpp>
#include <core/steam_types.hpp>
#include <steam_impl/steam_apps.hpp> #include <steam_impl/steam_apps.hpp>
using namespace smoke_api;
VIRTUAL(int) IClientApps_GetDLCCount(PARAMS(AppId_t appId)) { VIRTUAL(int) IClientApps_GetDLCCount(PARAMS(AppId_t appId)) {
return steam_apps::GetDLCCount(__func__, appId, [&]() { return steam_apps::GetDLCCount(
GET_ORIGINAL_HOOKED_FUNCTION(IClientApps_GetDLCCount) __func__, appId, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(IClientApps_GetDLCCount)
return IClientApps_GetDLCCount_o(ARGS(appId)); return IClientApps_GetDLCCount_o(ARGS(appId));
}); }
);
} }
VIRTUAL(bool) IClientApps_BGetDLCDataByIndex( VIRTUAL(bool) IClientApps_BGetDLCDataByIndex(
@@ -21,11 +22,13 @@ VIRTUAL(bool) IClientApps_BGetDLCDataByIndex(
int cchNameBufferSize int cchNameBufferSize
) )
) { ) {
return steam_apps::GetDLCDataByIndex(__func__, appID, iDLC, pDlcID, pbAvailable, pchName, cchNameBufferSize, [&]() { return steam_apps::GetDLCDataByIndex(
GET_ORIGINAL_HOOKED_FUNCTION(IClientApps_BGetDLCDataByIndex) __func__, appID, iDLC, pDlcID, pbAvailable, pchName, cchNameBufferSize, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(IClientApps_BGetDLCDataByIndex)
return IClientApps_BGetDLCDataByIndex_o( return IClientApps_BGetDLCDataByIndex_o(
ARGS(appID, iDLC, pDlcID, pbAvailable, pchName, cchNameBufferSize) ARGS(appID, iDLC, pDlcID, pbAvailable, pchName, cchNameBufferSize)
); );
}); }
);
} }

View File

@@ -1,14 +1,16 @@
#include <smoke_api/smoke_api.hpp> #include <core/macros.hpp>
#include <core/steam_types.hpp>
#include <steam_impl/steam_inventory.hpp> #include <steam_impl/steam_inventory.hpp>
#include <steam_functions/steam_functions.hpp>
using namespace smoke_api;
VIRTUAL(EResult) IClientInventory_GetResultStatus(PARAMS(SteamInventoryResult_t resultHandle)) { VIRTUAL(EResult) IClientInventory_GetResultStatus(PARAMS(SteamInventoryResult_t resultHandle)) {
return steam_inventory::GetResultStatus(__func__, resultHandle, [&]() { return steam_inventory::GetResultStatus(
GET_ORIGINAL_HOOKED_FUNCTION(IClientInventory_GetResultStatus) __func__, resultHandle, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(IClientInventory_GetResultStatus)
return IClientInventory_GetResultStatus_o(ARGS(resultHandle)); return IClientInventory_GetResultStatus_o(ARGS(resultHandle));
}); }
);
} }
VIRTUAL(bool) IClientInventory_GetResultItems( VIRTUAL(bool) IClientInventory_GetResultItems(

View File

@@ -1,8 +1,6 @@
#include <smoke_api/smoke_api.hpp> #include <core/macros.hpp>
#include <steam_impl/steam_apps.hpp> #include <steam_impl/steam_apps.hpp>
using namespace smoke_api;
VIRTUAL(bool) IClientUser_BIsSubscribedApp(PARAMS(AppId_t app_id)) { VIRTUAL(bool) IClientUser_BIsSubscribedApp(PARAMS(AppId_t app_id)) {
return steam_apps::IsDlcUnlocked(__func__, 0, app_id, [&]() { return steam_apps::IsDlcUnlocked(__func__, 0, app_id, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(IClientUser_BIsSubscribedApp) GET_ORIGINAL_HOOKED_FUNCTION(IClientUser_BIsSubscribedApp)