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">
<component name="CMakeSharedSettings">
<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 [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 [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" CONFIG_NAME="Debug" GENERATION_OPTIONS="-G &quot;Visual Studio 17 2022&quot; -A x64" />
</configurations>
</component>
</project>

View File

@@ -9,6 +9,7 @@
</Markdown>
<Objective-C>
<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_BEFORE_RPAR" value="true" />
<option name="SPACE_BEFORE_POINTER_IN_DECLARATION" value="false" />

View File

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

View File

@@ -1,11 +1,14 @@
#include <core/cache.hpp>
#include <core/paths.hpp>
#include <koalabox/io.hpp>
#include <koalabox/logger.hpp>
namespace cache {
Cache read_cache_from_disk() {
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()) {
return {};
@@ -13,7 +16,7 @@ namespace cache {
return nlohmann::json::parse(cache_string).get<Cache>();
} 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 {};
}
@@ -23,9 +26,9 @@ namespace cache {
try {
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) {
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) {
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();
@@ -68,7 +71,7 @@ namespace cache {
}
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();

View File

@@ -1,16 +1,15 @@
#pragma once
#include <koalabox/koalabox.hpp>
#include <koalabox/types.hpp>
#include <nlohmann/json.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.
* All functions are intended to be safe to call, i.e. they should not throw exceptions.
*/
namespace cache {
using namespace koalabox;
struct App {
Vector<AppId_t> dlc_ids;

View File

@@ -7,7 +7,7 @@ namespace config {
// TODO: Reloading via export
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) {
@@ -36,7 +36,7 @@ namespace config {
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 dlc_status = config::get_dlc_status(dlc_id);

View File

@@ -1,11 +1,8 @@
#pragma once
#include <cstdint>
#include <nlohmann/json.hpp>
#include <koalabox/koalabox.hpp>
#include <koalabox/types.hpp>
namespace config {
using namespace koalabox;
enum class AppStatus {
LOCKED,
UNLOCKED,
@@ -67,5 +64,5 @@ namespace config {
AppStatus get_app_status(uint32_t app_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 vstdlib_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
#include <koalabox/koalabox.hpp>
#include <koalabox/types.hpp>
namespace globals {
using namespace koalabox;
extern HMODULE smokeapi_handle;
extern HMODULE steamclient_module;
extern HMODULE steamapi_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 <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
#define DLL_EXPORT(TYPE) extern "C" [[maybe_unused]] __declspec( dllexport ) TYPE __cdecl
@@ -14,11 +47,12 @@
#define GET_ORIGINAL_FUNCTION_STEAMAPI(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) \
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_VSTDLIB(FUNC) $DETOUR(FUNC, globals::vstdlib_module)
#define $DETOUR(FUNC, NAME, MODULE_HANDLE) \
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/globals.hpp>
#include <koalabox/loader.hpp>
namespace paths {
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;
}
@@ -22,4 +23,5 @@ namespace paths {
static const auto path = get_self_path() / "SmokeAPI.log.log";
return path;
}
}

View File

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

View File

@@ -1,12 +1,15 @@
#pragma once
typedef uint32_t SteamInventoryResult_t;
typedef uint64_t SteamItemInstanceID_t;
typedef uint32_t SteamItemDef_t;
typedef uint32_t AppId_t;
typedef uint32_t HSteamPipe;
typedef uint32_t HSteamUser;
typedef uint64_t CSteamID;
#include <cstdint>
using AppId_t = uint32_t;
using SteamInventoryResult_t = uint32_t;
using SteamItemInstanceID_t = uint64_t;
using SteamItemDef_t = uint32_t;
using HSteamPipe = uint32_t;
using HSteamUser = uint32_t;
using CSteamID = uint64_t;
using EResult = uint32_t;
struct SteamItemDetails_t {
SteamItemInstanceID_t m_itemId;
@@ -22,4 +25,10 @@ enum EUserHasLicenseForAppResult {
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/vstdlib.hpp>
#include <build_config.h>
#include <core/cache.hpp>
#include <core/config.hpp>
#include <steam_functions/steam_functions.hpp>
#include <koalabox/dll_monitor.hpp>
#include <koalabox/http_client.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 {
using namespace koalabox;
KoalageddonConfig config; // NOLINT(cert-err58-cpp)
/**
@@ -21,7 +27,7 @@ namespace koalageddon {
return "local config override";
} 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";
} 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 {
@@ -44,7 +50,7 @@ namespace koalageddon {
return "disk cache";
} 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
@@ -53,35 +59,41 @@ namespace koalageddon {
}
void init() {
std::thread([]() {
const auto kg_config_source = init_koalageddon_config();
logger->info("Loaded Koalageddon config from the {}", kg_config_source);
}).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) {
logger->error("Koalageddon mode dll monitor init error. Module: '{}', Message: {}", name, ex.what());
std::thread(
[]() {
const auto kg_config_source = init_koalageddon_config();
LOG_INFO("Loaded Koalageddon config from the {}", kg_config_source)
}
});
).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
#include <koalabox/koalabox.hpp>
#include <core/macros.hpp>
#include <koalabox/types.hpp>
#include <nlohmann/json.hpp>
namespace koalageddon {
using namespace koalabox;
// 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.
struct KoalageddonConfig {
@@ -37,7 +34,4 @@ namespace koalageddon {
void init();
namespace steamclient {
void init(uintptr_t interface_selector_address);
}
}

View File

@@ -1,117 +1,83 @@
#include <koalabox/hook.hpp>
#include <koalabox/patcher.hpp>
#include <koalageddon/koalageddon.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/DecoderTypes.h>
namespace koalageddon::steamclient {
using namespace koalabox;
struct InstructionContext {
std::optional<ZydisRegister> base_register;
std::optional<String> function_name;
};
// map<interface name, map<function name, function ordinal>>
Map<String, Map<String, uint32_t>> ordinal_map; // NOLINT(cert-err58-cpp)
const auto MAX_INSTRUCTION_SIZE = 15;
// TODO: Refactor into Koalabox
ZydisDecoder decoder = {};
ZydisFormatter formatter = {};
#define HOOK_FUNCTION(INTERFACE, FUNC) hook::swap_virtual_func_or_throw( \
globals::address_map, \
interface, \
#INTERFACE"_"#FUNC, \
ordinal_map[#INTERFACE][#FUNC], \
reinterpret_cast<uintptr_t>(INTERFACE##_##FUNC) \
#define HOOK_FUNCTION(INTERFACE, FUNC) hook::swap_virtual_func_or_throw( \
globals::address_map, \
interface, \
#INTERFACE"_"#FUNC, \
ordinal_map[#INTERFACE][#FUNC], \
reinterpret_cast<uintptr_t>(INTERFACE##_##FUNC) \
);
DLL_EXPORT(void) IClientAppManager_Selector(
const void* interface,
const void* arg2,
const void* arg3,
const void* arg4
) {
static std::once_flag flag;
std::call_once(
flag, [&]() {
HOOK_FUNCTION(IClientAppManager, IsAppDlcInstalled)
}
);
GET_ORIGINAL_HOOKED_FUNCTION(IClientAppManager_Selector)
IClientAppManager_Selector_o(interface, arg2, arg3, arg4);
#define SELECTOR_IMPLEMENTATION(INTERFACE, FUNC_BODY) \
DLL_EXPORT(void) INTERFACE##_Selector( \
const void* interface, \
const void* arg2, \
const void* arg3, \
const void* arg4 \
) { \
CALL_ONCE(FUNC_BODY) \
GET_ORIGINAL_HOOKED_FUNCTION(INTERFACE##_Selector) \
INTERFACE##_Selector_o(interface, arg2, arg3, arg4); \
}
DLL_EXPORT(void) IClientApps_Selector(
const void* interface,
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)
}
);
SELECTOR_IMPLEMENTATION(IClientAppManager, {
HOOK_FUNCTION(IClientAppManager, IsAppDlcInstalled)
})
GET_ORIGINAL_HOOKED_FUNCTION(IClientApps_Selector)
IClientApps_Selector_o(interface, arg2, arg3, arg4);
}
SELECTOR_IMPLEMENTATION(IClientApps, {
HOOK_FUNCTION(IClientApps, GetDLCCount)
HOOK_FUNCTION(IClientApps, BGetDLCDataByIndex)
})
DLL_EXPORT(void) IClientInventory_Selector(
const void* interface,
const void* arg2,
const void* arg3,
const void* arg4
) {
static std::once_flag flag;
std::call_once(
flag, [&]() {
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)
}
);
SELECTOR_IMPLEMENTATION(IClientInventory, {
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)
IClientInventory_Selector_o(interface, arg2, arg3, arg4);
}
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);
}
SELECTOR_IMPLEMENTATION(IClientUser, {
HOOK_FUNCTION(IClientUser, BIsSubscribedApp)
})
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;
ZydisCalcAbsoluteAddress(&instruction, &op, address, &absolute_address);
ZydisCalcAbsoluteAddress(&instruction, &operand, address, &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) {
@@ -153,11 +119,6 @@ namespace koalageddon::steamclient {
return std::nullopt;
}
struct InstructionContext {
std::optional<ZydisRegister> base_register;
std::optional<String> function_name;
};
void construct_ordinal_map( // NOLINT(misc-no-recursion)
const String& target_interface,
Map<String, uint32_t>& map,
@@ -189,15 +150,13 @@ namespace koalageddon::steamclient {
auto current_address = (uintptr_t) start_address;
ZydisDecodedInstruction instruction{};
while (ZYAN_SUCCESS(
ZydisDecoderDecodeBuffer(
&decoder,
(void*) current_address,
MAX_INSTRUCTION_SIZE,
&instruction
)
)) {
TRACE(
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(
&decoder,
(void*) current_address,
MAX_INSTRUCTION_SIZE,
&instruction
))) {
LOG_TRACE(
"{} -> Visiting {} | {}",
__func__, (void*) current_address, *get_instruction_string(instruction, current_address)
)
@@ -296,10 +255,10 @@ namespace koalageddon::steamclient {
if (offset && is_derived_from_base_reg) {
const auto ordinal = *offset / sizeof(uintptr_t);
logger->debug(
LOG_DEBUG(
"{} -> Found function ordinal {}::{}@{}",
__func__, target_interface, *context.function_name, ordinal
);
)
map[*context.function_name] = ordinal;
break;
@@ -320,14 +279,12 @@ namespace koalageddon::steamclient {
std::optional<String> find_interface_name(uintptr_t selector_address) {
auto current_address = selector_address;
ZydisDecodedInstruction instruction{};
while (ZYAN_SUCCESS(
ZydisDecoderDecodeBuffer(
&decoder,
(void*) current_address,
MAX_INSTRUCTION_SIZE,
&instruction
)
)) {
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(
&decoder,
(void*) current_address,
MAX_INSTRUCTION_SIZE,
&instruction
))) {
const auto debug_str = get_instruction_string(instruction, current_address);
if (is_push_immediate(instruction)) {
@@ -343,7 +300,7 @@ namespace koalageddon::steamclient {
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;
}
@@ -368,26 +325,24 @@ namespace koalageddon::steamclient {
const uintptr_t start_address,
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)) {
TRACE("{} -> Breaking recursion due to visited address", __func__)
LOG_TRACE("{} -> Breaking recursion due to visited address", __func__)
return;
}
auto current_address = start_address;
ZydisDecodedInstruction instruction{};
while (ZYAN_SUCCESS(
ZydisDecoderDecodeBuffer(
&decoder,
(void*) current_address,
MAX_INSTRUCTION_SIZE,
&instruction
)
)) {
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(
&decoder,
(void*) current_address,
MAX_INSTRUCTION_SIZE,
&instruction
))) {
visited_addresses.insert(current_address);
TRACE(
LOG_TRACE(
"{} -> Visiting {} | {}",
__func__, (void*) current_address, *get_instruction_string(instruction, current_address)
)
@@ -397,7 +352,7 @@ namespace koalageddon::steamclient {
if (instruction.mnemonic == ZYDIS_MNEMONIC_CALL &&
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);
@@ -406,7 +361,7 @@ namespace koalageddon::steamclient {
if (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(IClientApps)
@@ -420,7 +375,7 @@ namespace koalageddon::steamclient {
process_interface_selector(jump_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;
} else if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP &&
operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE
@@ -429,7 +384,7 @@ namespace koalageddon::steamclient {
process_interface_selector(jump_destination, visited_addresses);
TRACE("breaking recursion due to unconditional branch")
LOG_TRACE("breaking recursion due to unconditional branch")
return;
} else if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP &&
operand.type == ZYDIS_OPERAND_TYPE_MEMORY &&
@@ -448,7 +403,7 @@ namespace koalageddon::steamclient {
return;
} 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;
}
@@ -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))) {
logger->error("Failed to initialize zydis decoder");
LOG_ERROR("Failed to initialize zydis decoder")
return;
}
if (ZYAN_FAILED(ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL))) {
logger->error("Failed to initialize zydis formatter");
LOG_ERROR("Failed to initialize zydis formatter")
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 <koalageddon/koalageddon.hpp>
#include <steam_functions/steam_functions.hpp>
#include <koalabox/hook.hpp>
#include <koalabox/logger.hpp>
using namespace koalageddon;
using namespace koalabox;
VIRTUAL(bool) SharedLicensesLockStatus(PARAMS(void* arg)) { // NOLINT(misc-unused-parameters)
logger->debug("{} -> instance: {}, arg: {}", __func__, fmt::ptr(THIS), fmt::ptr(arg));
return true;
}
namespace koalageddon::vstdlib {
using namespace koalabox;
VIRTUAL(bool) SharedLibraryStopPlaying(PARAMS(void* arg)) { // NOLINT(misc-unused-parameters)
logger->debug("{} -> instance: {}, arg: {}", __func__, fmt::ptr(THIS), fmt::ptr(arg));
return true;
}
struct CallbackData {
FunctionAddress get_callback_intercept_address() {
return reinterpret_cast<FunctionAddress*>(this)[koalageddon::config.vstdlib_callback_interceptor_address_offset];
VIRTUAL(bool) SharedLicensesLockStatus(PARAMS(void* arg)) {
LOG_DEBUG("{} -> ecx: {}, edx: {}, arg: {}", __func__, ARGS(arg))
return true;
}
FunctionAddress get_callback_address() {
return reinterpret_cast<FunctionAddress*>(this)[koalageddon::config.vstdlib_callback_address_offset];
}
};
struct CoroutineData {
CallbackData* get_callback_data() {
return reinterpret_cast<CallbackData**>(this)[koalageddon::config.vstdlib_callback_data_offset];
VIRTUAL(bool) SharedLibraryStopPlaying(PARAMS(void* arg)) {
LOG_DEBUG("{} -> ecx: {}, edx: {}, arg: {}", __func__, ARGS(arg))
return true;
}
const char* get_callback_name() {
return reinterpret_cast<const char**>(this)[koalageddon::config.vstdlib_callback_name_offset];
}
};
VIRTUAL(void) VStdLib_Callback_Interceptor(PARAMS(const char** name_ptr)) {
GET_ORIGINAL_HOOKED_FUNCTION(VStdLib_Callback_Interceptor)
VStdLib_Callback_Interceptor_o(ARGS(name_ptr));
VIRTUAL(void) VStdLib_Callback_Interceptor(PARAMS(const char** p_name)) {
GET_ORIGINAL_HOOKED_FUNCTION(VStdLib_Callback_Interceptor)
static auto lock_status_hooked = false;
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;
static auto stop_playing_hooked = false;
auto* const data = (CoroutineData*) THIS;
if (lock_status_hooked && stop_playing_hooked) {
return;
}
if (data && data->get_callback_name()) {
const auto name = String(data->get_callback_name());
LOG_TRACE("{} -> instance: {}, name: '{}'", __func__, fmt::ptr(THIS), name)
auto* const data = (CoroutineData*) THIS;
if (data && data->get_callback_name()) {
const auto name = String(data->get_callback_name());
TRACE("{} -> instance: {}, name: '{}'", __func__, fmt::ptr(THIS), name)
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;
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,
* hence we must hook an interface method that sets the callback name.
*/
DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, CoroutineData* data) {
GET_ORIGINAL_HOOKED_FUNCTION(Coroutine_Create)
const auto result = Coroutine_Create_o(callback_address, data);
// Coroutine callback appears to be always the same
static std::once_flag flag;
std::call_once(
flag, [&]() {
logger->debug("Coroutine_Create -> callback: {}, data: {}", callback_address, fmt::ptr(data));
DETOUR_ADDRESS(VStdLib_Callback_Interceptor, data->get_callback_data()->get_callback_intercept_address())
}
);
return result;
/**
* Initially, callback data passed into this function is not complete,
* hence we must hook an interface method that sets the callback name.
*/
DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, CoroutineData* data) {
GET_ORIGINAL_HOOKED_FUNCTION(Coroutine_Create)
const auto result = Coroutine_Create_o(callback_address, data);
// Coroutine callback appears to be always the same
CALL_ONCE({
LOG_DEBUG("Coroutine_Create -> callback: {}, data: {}", callback_address, fmt::ptr(data));
DETOUR_ADDRESS(
VStdLib_Callback_Interceptor,
data->get_callback_data()->get_callback_intercept_address()
)
})
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 <koalabox/config_parser.hpp>
#include <koalabox/dll_monitor.hpp>
#include <koalabox/file_logger.hpp>
#include <koalabox/logger.hpp>
#include <koalabox/hook.hpp>
#include <koalabox/loader.hpp>
#include <koalabox/win_util.hpp>
@@ -20,21 +20,23 @@ namespace smoke_api {
using namespace koalabox;
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);
}
void init_hook_mode() {
logger->info("🪝 Detected hook mode");
LOG_INFO("🪝 Detected hook mode")
dll_monitor::init(STEAMCLIENT_DLL, [](const HMODULE& library) {
globals::steamclient_module = library;
dll_monitor::init(
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
// for the reasons outlined below:
@@ -80,41 +82,35 @@ namespace smoke_api {
globals::smokeapi_handle = module_handle;
koalabox::project_name = PROJECT_NAME;
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_name = exe_path.filename().string();
const auto exe_bitness = util::is_x64() ? 64 : 32;
if (config::instance.logging) {
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);
LOG_DEBUG(R"(Process name: "{}" [{}-bit])", exe_name, exe_bitness)
if (hook::is_hook_mode(globals::smokeapi_handle, STEAMAPI_DLL)) {
hook::init(true);
#ifdef _WIN64
init_hook_mode();
#else
// TODO: Check if it's steam from valve
if (is_valve_steam(exe_name)) {
logger->info("🐨💥 Detected Koalageddon mode");
#ifndef _WIN64
LOG_INFO("🐨💥 Detected Koalageddon mode")
koalageddon::init();
#endif
} else {
init_hook_mode();
}
#endif
} else {
init_proxy_mode();
}
logger->info("🚀 Initialization complete");
LOG_INFO("🚀 Initialization complete")
} catch (const Exception& ex) {
util::panic(fmt::format("Initialization error: {}", ex.what()));
}
@@ -126,9 +122,9 @@ namespace smoke_api {
win_util::free_library(globals::steamapi_module);
}
logger->info("💀 Shutdown complete");
LOG_INFO("💀 Shutdown complete")
} 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/steam_types.hpp>
#include <steam_impl/steam_apps.hpp>
#include <steam_impl/steam_client.hpp>
#include <steam_impl/steam_inventory.hpp>
#include <steam_impl/steam_user.hpp>
#include <steam_functions/steam_functions.hpp>
using namespace koalabox;
// ISteamApps
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(ISteamApps* self, AppId_t appID) {
return steam_apps::IsDlcUnlocked(__func__, 0, appID, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_BIsSubscribedApp)
return steam_apps::IsDlcUnlocked(
__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) {
return steam_apps::IsDlcUnlocked(__func__, 0, appID, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_BIsDlcInstalled)
return steam_apps::IsDlcUnlocked(
__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) {
return steam_apps::GetDLCCount(__func__, 0, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_GetDLCCount)
return steam_apps::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(
@@ -40,13 +48,15 @@ DLL_EXPORT(bool) SteamAPI_ISteamApps_BGetDLCDataByIndex(
char* pchName,
int cchNameBufferSize
) {
return steam_apps::GetDLCDataByIndex(__func__, 0, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_BGetDLCDataByIndex)
return steam_apps::GetDLCDataByIndex(
__func__, 0, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_BGetDLCDataByIndex)
return SteamAPI_ISteamApps_BGetDLCDataByIndex_o(
self, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize
);
});
return SteamAPI_ISteamApps_BGetDLCDataByIndex_o(
self, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize
);
}
);
}
// ISteamUser
@@ -56,11 +66,13 @@ DLL_EXPORT(EUserHasLicenseForAppResult) SteamAPI_ISteamUser_UserHasLicenseForApp
CSteamID steamID,
AppId_t appID
) {
return steam_user::UserHasLicenseForApp(__func__, appID, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamUser_UserHasLicenseForApp)
return steam_user::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
@@ -71,11 +83,13 @@ DLL_EXPORT(void*) SteamAPI_ISteamClient_GetISteamGenericInterface(
HSteamPipe hSteamPipe,
const char* pchVersion
) {
return steam_client::GetGenericInterface(__func__, pchVersion, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamClient_GetISteamGenericInterface)
return steam_client::GetGenericInterface(
__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
@@ -84,11 +98,13 @@ DLL_EXPORT(EResult) SteamAPI_ISteamInventory_GetResultStatus(
ISteamInventory* self,
SteamInventoryResult_t resultHandle
) {
return steam_inventory::GetResultStatus(__func__, resultHandle, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetResultStatus)
return steam_inventory::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(
@@ -136,22 +152,26 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_CheckResultSteamID(
SteamInventoryResult_t resultHandle,
CSteamID steamIDExpected
) {
return steam_inventory::CheckResultSteamID(__func__, resultHandle, steamIDExpected, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_CheckResultSteamID)
return steam_inventory::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(
ISteamInventory* self,
SteamInventoryResult_t* pResultHandle
) {
return steam_inventory::GetAllItems(__func__, pResultHandle, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetAllItems)
return steam_inventory::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(
@@ -160,11 +180,13 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemsByID(
const SteamItemInstanceID_t* pInstanceIDs,
uint32_t unCountInstanceIDs
) {
return steam_inventory::GetItemsByID(__func__, pResultHandle, pInstanceIDs, unCountInstanceIDs, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetItemsByID)
return steam_inventory::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(
@@ -173,11 +195,13 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_SerializeResult(
void* pOutBuffer,
uint32_t* punOutBufferSize
) {
return steam_inventory::SerializeResult(__func__, resultHandle, pOutBuffer, punOutBufferSize, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_SerializeResult)
return steam_inventory::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(
@@ -185,9 +209,11 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemDefinitionIDs(
SteamItemDef_t* pItemDefIDs,
uint32_t* punItemDefIDsArraySize
) {
return steam_inventory::GetItemDefinitionIDs(__func__, pItemDefIDs, punItemDefIDsArraySize, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetItemDefinitionIDs)
return steam_inventory::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 <koalabox/hook.hpp>
#include <core/steam_types.hpp>
#include <steam_impl/steam_client.hpp>
#include <koalabox/hook.hpp>
using namespace koalabox;
DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(HSteamUser hSteamUser, const char* version) {
return steam_client::GetGenericInterface(__func__, version, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamInternal_FindOrCreateUserInterface)
return steam_client::GetGenericInterface(
__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) {
return steam_client::GetGenericInterface(__func__, version, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamInternal_CreateInterface)
return steam_client::GetGenericInterface(
__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 <core/macros.hpp>
#include <koalabox/logger.hpp>
#include <koalabox/win_util.hpp>
#include <koalabox/util.hpp>
#include <steam_functions/steam_functions.hpp>
#include <regex>
using namespace smoke_api;
using namespace steam_functions;
using namespace koalabox;
/**
* 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);
} catch (const Exception& ex) {
logger->error(
LOG_ERROR(
"Failed to get versioned interface: {}."
"Falling back to version {}", ex.what(), 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() {
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, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamClient)
return steam_client::GetGenericInterface(
__func__, version, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamClient)
return SteamClient_o();
});
return SteamClient_o();
}
);
}
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, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamApps)
return steam_client::GetGenericInterface(
__func__, version, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamApps)
return SteamApps_o();
});
return SteamApps_o();
}
);
}
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, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamUser)
return steam_client::GetGenericInterface(
__func__, version, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamUser)
return SteamUser_o();
});
return SteamUser_o();
}
);
}
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, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamInventory)
return steam_client::GetGenericInterface(
__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 <core/macros.hpp>
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t appID)) { // NOLINT(misc-unused-parameters)
return steam_apps::IsDlcUnlocked(__func__, 0, appID, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(ISteamApps_BIsSubscribedApp)
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t appID)) {
return steam_apps::IsDlcUnlocked(
__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)
return steam_apps::IsDlcUnlocked(__func__, 0, appID, [&]() {
GET_ORIGINAL_FUNCTION_STEAMAPI(ISteamApps_BIsDlcInstalled)
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(AppId_t appID)) {
return steam_apps::IsDlcUnlocked(
__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()) {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamApps_GetDLCCount)
return steam_apps::GetDLCCount(__func__, 0, [&]() {
return ISteamApps_GetDLCCount_o(ARGS());
});
return steam_apps::GetDLCCount(
__func__, 0, [&]() {
return ISteamApps_GetDLCCount_o(ARGS());
}
);
}
VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(
@@ -34,11 +40,13 @@ VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(
int cchNameBufferSize
)
) {
return steam_apps::GetDLCDataByIndex(__func__, 0, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamApps_BGetDLCDataByIndex)
return steam_apps::GetDLCDataByIndex(
__func__, 0, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamApps_BGetDLCDataByIndex)
return ISteamApps_BGetDLCDataByIndex_o(
ARGS(iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize)
);
});
return ISteamApps_BGetDLCDataByIndex_o(
ARGS(iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize)
);
}
);
}

View File

@@ -1,7 +1,5 @@
#include <smoke_api/smoke_api.hpp>
#include <steam_impl/steam_client.hpp>
using namespace smoke_api;
#include <steam_functions/steam_functions.hpp>
VIRTUAL(void*) ISteamClient_GetISteamApps(
PARAMS(
@@ -10,11 +8,13 @@ VIRTUAL(void*) ISteamClient_GetISteamApps(
const char* version
)
) {
return steam_client::GetGenericInterface(__func__, version, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamClient_GetISteamApps)
return steam_client::GetGenericInterface(
__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(
@@ -24,11 +24,13 @@ VIRTUAL(void*) ISteamClient_GetISteamUser(
const char* version
)
) {
return steam_client::GetGenericInterface(__func__, version, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamClient_GetISteamUser)
return steam_client::GetGenericInterface(
__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(
@@ -38,11 +40,13 @@ VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(
const char* pchVersion
)
) {
return steam_client::GetGenericInterface(__func__, pchVersion, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamClient_GetISteamGenericInterface)
return steam_client::GetGenericInterface(
__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(
@@ -52,9 +56,11 @@ VIRTUAL(void*) ISteamClient_GetISteamInventory(
const char* pchVersion
)
) {
return steam_client::GetGenericInterface(__func__, pchVersion, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamClient_GetISteamInventory)
return steam_client::GetGenericInterface(
__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>
using namespace smoke_api;
#include <steam_functions/steam_functions.hpp>
VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(SteamInventoryResult_t resultHandle)) {
return steam_inventory::GetResultStatus(__func__, resultHandle, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_GetResultStatus)
return steam_inventory::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(
@@ -18,7 +18,6 @@ VIRTUAL(bool) ISteamInventory_GetResultItems(
uint32_t * punOutItemsArraySize
)
) {
return steam_inventory::GetResultItems(
__func__, resultHandle, pOutItemsArray, punOutItemsArraySize,
[&]() {
@@ -60,19 +59,23 @@ VIRTUAL(bool) ISteamInventory_CheckResultSteamID(
CSteamID steamIDExpected
)
) {
return steam_inventory::CheckResultSteamID(__func__, resultHandle, steamIDExpected, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_CheckResultSteamID)
return steam_inventory::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)) {
return steam_inventory::GetAllItems(__func__, pResultHandle, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_GetAllItems)
return steam_inventory::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(
@@ -82,11 +85,13 @@ VIRTUAL(bool) ISteamInventory_GetItemsByID(
uint32_t unCountInstanceIDs
)
) {
return steam_inventory::GetItemsByID(__func__, pResultHandle, pInstanceIDs, unCountInstanceIDs, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_GetItemsByID)
return steam_inventory::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(
@@ -96,11 +101,13 @@ VIRTUAL(bool) ISteamInventory_SerializeResult(
uint32_t * punOutBufferSize
)
) {
return steam_inventory::SerializeResult(__func__, resultHandle, pOutBuffer, punOutBufferSize, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_SerializeResult)
return steam_inventory::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(
@@ -109,9 +116,11 @@ VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(
uint32_t * punItemDefIDsArraySize
)
) {
return steam_inventory::GetItemDefinitionIDs(__func__, pItemDefIDs, punItemDefIDsArraySize, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamInventory_GetItemDefinitionIDs)
return steam_inventory::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>
using namespace smoke_api;
#include <steam_functions/steam_functions.hpp>
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID steamID, AppId_t appID)) {
return steam_user::UserHasLicenseForApp(__func__, appID, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(ISteamUser_UserHasLicenseForApp)
return steam_user::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 <koalageddon/steamclient.hpp>
#include <build_config.h>
#include <koalabox/hook.hpp>
#include <koalageddon/koalageddon.hpp>
#include <koalabox/win_util.hpp>
#include <koalabox/logger.hpp>
#include <koalabox/util.hpp>
#include <polyhook2/Misc.hpp>
namespace steam_functions {
@@ -82,20 +84,20 @@ namespace steam_functions {
int min_version,
int max_version
) {
logger->debug("Hooking interface '{}'", version_string);
LOG_DEBUG("Hooking interface '{}'", version_string)
try {
const auto version_number = stoi(version_string.substr(prefix.length()));
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) {
logger->warn(
LOG_WARN(
"Unsupported new version of {}: {}. Fallback version {} will be used",
version_string, version_number, max_version
);
)
}
return version_number;
@@ -118,19 +120,19 @@ namespace steam_functions {
util::panic("Invalid interface version ({}) for function {}", interface_version, function_name);
}
#define HOOK(MAP, FUNC) \
#define HOOK_VIRTUALS(MAP, FUNC) \
hook::swap_virtual_func( \
globals::address_map, \
interface, \
#FUNC, \
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_APPS(FUNC) HOOK(steam_apps_ordinal_map, FUNC)
#define HOOK_STEAM_USER(FUNC) HOOK(steam_user_ordinal_map, FUNC)
#define HOOK_STEAM_INVENTORY(FUNC) HOOK(steam_inventory_ordinal_map, FUNC)
#define HOOK_STEAM_CLIENT(FUNC) HOOK_VIRTUALS(steam_client_ordinal_map, FUNC)
#define HOOK_STEAM_APPS(FUNC) HOOK_VIRTUALS(steam_apps_ordinal_map, FUNC)
#define HOOK_STEAM_USER(FUNC) HOOK_VIRTUALS(steam_user_ordinal_map, FUNC)
#define HOOK_STEAM_INVENTORY(FUNC) HOOK_VIRTUALS(steam_inventory_ordinal_map, FUNC)
void hook_virtuals(void* interface, const String& version_string) {
if (interface == nullptr) {
@@ -138,17 +140,15 @@ namespace steam_functions {
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_pair)) {
if (hooked_interfaces.contains(interface)) {
// This interface is already hooked. Skipping it.
return;
}
static std::mutex section;
const std::lock_guard<std::mutex> guard(section);
static Mutex section;
const MutexLockGuard guard(section);
if (version_string.starts_with(STEAM_CLIENT)) {
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)) {
// Koalageddon mode
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);
koalageddon::steamclient::process_client_engine(reinterpret_cast<uintptr_t>(interface));
} else {
return;
}
hooked_interfaces.insert(interface_pair);
hooked_interfaces.insert(interface);
}
HSteamPipe get_steam_pipe_or_throw() {
@@ -249,7 +239,7 @@ namespace steam_functions {
return function(ARGS(args...));
}
uint32_t get_app_id_or_throw() {
AppId_t get_app_id_or_throw() {
// Get CreateInterface
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(

View File

@@ -1,46 +1,9 @@
#pragma once
#include <koalabox/koalabox.hpp>
#include <steam_types/steam_types.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
@@ -60,7 +23,7 @@ VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(PARAMS(int, AppId_t*, bool*, char*,
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t));
// 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_GetResultItemProperty(
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_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 {
using namespace koalabox;

View File

@@ -1,13 +1,15 @@
#include <steam_impl/steam_apps.hpp>
#include <cpr/cpr.h>
#include <koalabox/io.hpp>
#include <koalabox/http_client.hpp>
#include <core/cache.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 {
using namespace smoke_api;
using namespace koalabox;
/// 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.
@@ -27,9 +29,9 @@ namespace steam_apps {
try {
app_id = steam_functions::get_app_id_or_throw();
// 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) {
logger->error("Failed to get app ID: {}", ex.what());
LOG_ERROR("Failed to get app ID: {}", ex.what())
return false;
}
}
@@ -54,7 +56,7 @@ namespace steam_apps {
dlcs.emplace_back(std::stoi(app_id));
}
} 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;
}
@@ -72,7 +74,7 @@ namespace steam_apps {
dlcs = json[app_id_str].get<decltype(dlcs)>();
}
} 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;
}
@@ -110,34 +112,34 @@ namespace steam_apps {
const String& function_name,
AppId_t app_id,
AppId_t dlc_id,
const std::function<bool()>& original_function
const Function<bool()>& original_function
) {
try {
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;
} catch (const Exception& e) {
logger->error("{} -> Uncaught exception: {}", function_name, e.what());
LOG_ERROR("{} -> Uncaught exception: {}", function_name, e.what())
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 {
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;
};
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();
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) {
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
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
static Set<AppId_t> cached_apps;
@@ -154,7 +156,7 @@ namespace steam_apps {
static std::mutex 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)) {
cached_apps.insert(app_id);
@@ -162,11 +164,11 @@ namespace steam_apps {
}
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);
} catch (const Exception& e) {
logger->error("{} -> Uncaught exception: {}", function_name, e.what());
LOG_ERROR("{} -> Uncaught exception: {}", function_name, e.what())
return 0;
}
}
@@ -179,14 +181,14 @@ namespace steam_apps {
bool* pbAvailable,
char* pchName,
int cchNameBufferSize,
const std::function<bool()>& original_function
const Function<bool()>& original_function
) {
try {
const auto print_dlc_info = [&](const String& tag) {
logger->info(
LOG_INFO(
"{} -> [{}] {}index: {}, DLC ID: {}, available: {}, name: '{}'",
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) {
@@ -224,7 +226,7 @@ namespace steam_apps {
*pbAvailable = config::is_dlc_unlocked(app_id, *pDlcId, [&]() { return *pbAvailable; });
print_dlc_info("original");
} else {
logger->warn("{} -> original call failed for index: {}", function_name, iDLC);
LOG_WARN("{} -> original call failed for index: {}", function_name, iDLC)
}
return success;
}
@@ -236,7 +238,7 @@ namespace steam_apps {
// [injected-dlc-0, injected-dlc-1, ..., cached-dlc-0, cached-dlc-1, ...]
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());
@@ -250,14 +252,14 @@ namespace steam_apps {
return inject_dlc("memory cache", cached_dlcs, adjusted_index);
}
logger->error(
LOG_ERROR(
"{} -> Out of bounds DLC index: {}, local dlc count: {}, cached dlc count: {}",
function_name, iDLC, local_dlc_count, cached_dlc_count
);
)
return false;
} catch (const Exception& e) {
logger->error("{} -> Uncaught exception: {}", function_name, e.what());
LOG_ERROR("{} -> Uncaught exception: {}", function_name, e.what())
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 {
using namespace koalabox;
bool IsDlcUnlocked(
const String& function_name,
AppId_t app_id,
AppId_t dlc_id,
const std::function<bool()>& original_function
const Function<bool()>& original_function
);
int GetDLCCount(
const String& function_name,
AppId_t app_id,
const std::function<int()>& original_function
const Function<int()>& original_function
);
bool GetDLCDataByIndex(
@@ -24,7 +24,7 @@ namespace steam_apps {
bool* pbAvailable,
char* pchName,
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 <koalabox/logger.hpp>
#include <steam_functions/steam_functions.hpp>
namespace steam_client {
void* GetGenericInterface(
const String& function_name,
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();
logger->debug("{} -> Result: {}", function_name, fmt::ptr(interface));
LOG_DEBUG("{} -> '{}' @ {}", function_name, interface_version, interface)
steam_functions::hook_virtuals(interface, interface_version);

View File

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

View File

@@ -1,13 +1,12 @@
#include <koalabox/koalabox.hpp>
#include <steam_functions/steam_functions.hpp>
#include <core/steam_types.hpp>
#include <koalabox/types.hpp>
namespace steam_inventory {
using namespace koalabox;
EResult GetResultStatus(
const String& function_name,
SteamInventoryResult_t resultHandle,
const std::function<EResult()>& original_function
const Function<EResult()>& original_function
);
bool GetResultItems(
@@ -15,8 +14,8 @@ namespace steam_inventory {
SteamInventoryResult_t resultHandle,
SteamItemDetails_t* pOutItemsArray,
uint32_t* punOutItemsArraySize,
const std::function<bool()>& original_function,
const std::function<bool(SteamItemDef_t*, uint32_t*)>& get_item_definition_ids
const Function<bool()>& original_function,
const Function<bool(SteamItemDef_t*, uint32_t*)>& get_item_definition_ids
);
bool GetResultItemProperty(
@@ -26,13 +25,13 @@ namespace steam_inventory {
const char* pchPropertyName,
char* pchValueBuffer,
const uint32_t* punValueBufferSizeOut,
const std::function<bool()>& original_function
const Function<bool()>& original_function
);
bool GetAllItems(
const String& function_name,
const SteamInventoryResult_t* pResultHandle,
const std::function<bool()>& original_function
const Function<bool()>& original_function
);
bool GetItemsByID(
@@ -40,7 +39,7 @@ namespace steam_inventory {
SteamInventoryResult_t* pResultHandle,
const SteamItemInstanceID_t* pInstanceIDs,
uint32_t unCountInstanceIDs,
const std::function<bool()>& original_function
const Function<bool()>& original_function
);
bool SerializeResult(
@@ -48,14 +47,14 @@ namespace steam_inventory {
SteamInventoryResult_t resultHandle,
void* pOutBuffer,
uint32_t* punOutBufferSize,
const std::function<bool()>& original_function
const Function<bool()>& original_function
);
bool GetItemDefinitionIDs(
const String& function_name,
const SteamItemDef_t* pItemDefIDs,
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,
SteamInventoryResult_t resultHandle,
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 <core/config.hpp>
#include <koalabox/logger.hpp>
namespace steam_user {
EUserHasLicenseForAppResult UserHasLicenseForApp(
const String& function_name,
AppId_t appID,
const std::function<EUserHasLicenseForAppResult()>& original_function
const Function<EUserHasLicenseForAppResult()>& original_function
) {
const auto result = original_function();
if (result == k_EUserHasLicenseResultNoAuth) {
logger->warn("{} -> App ID: {}, Result: NoAuth", function_name, appID);
LOG_WARN("{} -> App ID: {}, Result: NoAuth", function_name, appID)
return result;
}
const auto has_license = config::is_dlc_unlocked(0, appID, [&]() {
return result == k_EUserHasLicenseResultHasLicense;
});
const auto has_license = config::is_dlc_unlocked(
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
? k_EUserHasLicenseResultHasLicense

View File

@@ -1,13 +1,12 @@
#include <koalabox/koalabox.hpp>
#include <steam_functions/steam_functions.hpp>
#include <core/steam_types.hpp>
#include <koalabox/types.hpp>
namespace steam_user {
using namespace koalabox;
EUserHasLicenseForAppResult UserHasLicenseForApp(
const String& function_name,
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>
DLL_EXPORT(void*) CreateInterface(const char* interface_string, int* out_result) {
return steam_client::GetGenericInterface(__func__, interface_string, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(CreateInterface)
return steam_client::GetGenericInterface(
__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>
using namespace smoke_api;
VIRTUAL(bool) IClientAppManager_IsAppDlcInstalled(PARAMS(AppId_t app_id, AppId_t dlc_id)) {
return steam_apps::IsDlcUnlocked(__func__, app_id, dlc_id, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(IClientAppManager_IsAppDlcInstalled)
return steam_apps::IsDlcUnlocked(
__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>
using namespace smoke_api;
VIRTUAL(int) IClientApps_GetDLCCount(PARAMS(AppId_t appId)) {
return steam_apps::GetDLCCount(__func__, appId, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(IClientApps_GetDLCCount)
return steam_apps::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(
@@ -21,11 +22,13 @@ VIRTUAL(bool) IClientApps_BGetDLCDataByIndex(
int cchNameBufferSize
)
) {
return steam_apps::GetDLCDataByIndex(__func__, appID, iDLC, pDlcID, pbAvailable, pchName, cchNameBufferSize, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(IClientApps_BGetDLCDataByIndex)
return steam_apps::GetDLCDataByIndex(
__func__, appID, iDLC, pDlcID, pbAvailable, pchName, cchNameBufferSize, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(IClientApps_BGetDLCDataByIndex)
return IClientApps_BGetDLCDataByIndex_o(
ARGS(appID, iDLC, pDlcID, pbAvailable, pchName, cchNameBufferSize)
);
});
return IClientApps_BGetDLCDataByIndex_o(
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>
using namespace smoke_api;
#include <steam_functions/steam_functions.hpp>
VIRTUAL(EResult) IClientInventory_GetResultStatus(PARAMS(SteamInventoryResult_t resultHandle)) {
return steam_inventory::GetResultStatus(__func__, resultHandle, [&]() {
GET_ORIGINAL_HOOKED_FUNCTION(IClientInventory_GetResultStatus)
return steam_inventory::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(

View File

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