mirror of
https://github.com/acidicoala/SmokeAPI.git
synced 2024-11-04 12:00:24 +00:00
Refactored hook calls
This commit is contained in:
parent
011f3fac5d
commit
eaca0bec34
@ -6,7 +6,7 @@ include(KoalaBox/cmake/KoalaBox.cmake)
|
||||
|
||||
add_subdirectory(KoalaBox EXCLUDE_FROM_ALL)
|
||||
|
||||
set_32_and_64(ORIGINAL_DLL steam_api)
|
||||
set_32_and_64(STEAMAPI_DLL steam_api)
|
||||
set_32_and_64(STEAMCLIENT_DLL steamclient)
|
||||
set_32_and_64(VSTDLIB_DLL vstdlib_s)
|
||||
|
||||
@ -25,7 +25,7 @@ set(
|
||||
)
|
||||
|
||||
configure_linker_exports(
|
||||
FORWARDED_DLL "${ORIGINAL_DLL}_o"
|
||||
FORWARDED_DLL "${STEAMAPI_DLL}_o"
|
||||
INPUT_SOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/steam_api_exports"
|
||||
INPUT_DLLS "${DLL_INPUT}"
|
||||
DEP_SOURCES "${STEAM_API_EXPORTS}"
|
||||
@ -86,7 +86,7 @@ endif ()
|
||||
|
||||
add_library(SmokeAPI SHARED ${SMOKE_API_SOURCES} ${VERSION_RESOURCE})
|
||||
|
||||
configure_output_name(${ORIGINAL_DLL})
|
||||
configure_output_name(${STEAMAPI_DLL})
|
||||
|
||||
configure_include_directories()
|
||||
|
||||
|
2
KoalaBox
2
KoalaBox
@ -1 +1 @@
|
||||
Subproject commit 53731ddc6b82281df820884f2d2424ee3a62df54
|
||||
Subproject commit 6fa96ea016482b263827d82f02b86552d5e4d407
|
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define ORIGINAL_DLL "${ORIGINAL_DLL}"
|
||||
#define STEAMAPI_DLL "${STEAMAPI_DLL}"
|
||||
#define STEAMCLIENT_DLL "${STEAMCLIENT_DLL}"
|
||||
#define VSTDLIB_DLL "${VSTDLIB_DLL}"
|
||||
|
@ -5,6 +5,7 @@
|
||||
namespace config {
|
||||
Config instance; // NOLINT(cert-err58-cpp)
|
||||
|
||||
// TODO: Reloading via export
|
||||
void init() {
|
||||
instance = config_parser::parse<Config>(paths::get_config_path());
|
||||
}
|
||||
|
@ -1,4 +1,9 @@
|
||||
#include <core/globals.hpp>
|
||||
|
||||
namespace globals {
|
||||
HMODULE self_module = nullptr;
|
||||
// TODO: Original module (rename to proxy module?)
|
||||
HMODULE smokeapi_handle = nullptr;
|
||||
HMODULE steamapi_module = nullptr;
|
||||
HMODULE vstdlib_module = nullptr;
|
||||
HMODULE steamclient_module = nullptr;
|
||||
Map<String, FunctionAddress> address_map;
|
||||
}
|
||||
|
@ -1,5 +1,12 @@
|
||||
#pragma once
|
||||
#include <koalabox/koalabox.hpp>
|
||||
|
||||
namespace globals {
|
||||
extern HMODULE self_module;
|
||||
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;
|
||||
}
|
||||
|
@ -1,7 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <core/globals.hpp>
|
||||
#include <koalabox/hook.hpp>
|
||||
|
||||
// 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 VIRTUAL(TYPE) __declspec(noinline) TYPE __fastcall
|
||||
|
||||
#define DETOUR(FUNC, ADDRESS) hook::detour_or_warn(ADDRESS, #FUNC, reinterpret_cast<FunctionAddress>(FUNC));
|
||||
#define DETOUR_ORIGINAL(FUNC) DETOUR(FUNC, smoke_api::original_library)
|
||||
#define GET_ORIGINAL_VIRTUAL_FUNCTION(FUNC) \
|
||||
const auto FUNC##_o = koalabox::hook::get_original_function(globals::address_map, #FUNC, FUNC);
|
||||
|
||||
#define $GET_ORIGINAL_MODULE_FUNCTION(FUNC, MODULE_HANDLE) \
|
||||
static const auto FUNC##_o = koalabox::hook::get_original_function(MODULE_HANDLE, #FUNC, FUNC);
|
||||
|
||||
#define GET_ORIGINAL_FUNCTION_STEAMCLIENT(FUNC) $GET_ORIGINAL_MODULE_FUNCTION(FUNC, globals::steamclient_module)
|
||||
#define GET_ORIGINAL_FUNCTION_STEAMAPI(FUNC) $GET_ORIGINAL_MODULE_FUNCTION(FUNC, globals::steamapi_module)
|
||||
#define GET_ORIGINAL_FUNCTION_VSTDLIB(FUNC) $GET_ORIGINAL_MODULE_FUNCTION(FUNC, globals::vstdlib_module)
|
||||
|
||||
#define $DETOUR(FUNC, MODULE_HANDLE) \
|
||||
koalabox::hook::detour_or_warn(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));
|
||||
|
||||
#define DETOUR_STEAMCLIENT(FUNC) $DETOUR(FUNC, globals::steamclient_module)
|
||||
#define DETOUR_VSTDLIB(FUNC) $DETOUR(FUNC, globals::vstdlib_module)
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
namespace paths {
|
||||
Path get_self_path() {
|
||||
static const auto path = loader::get_module_dir(globals::self_module);
|
||||
static const auto path = loader::get_module_dir(globals::smokeapi_handle);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,9 @@
|
||||
#include <build_config.h>
|
||||
#include <core/cache.hpp>
|
||||
#include <core/config.hpp>
|
||||
#include <smoke_api/smoke_api.hpp>
|
||||
#include <koalabox/dll_monitor.hpp>
|
||||
#include <koalabox/http_client.hpp>
|
||||
#include <koalabox/util.hpp>
|
||||
|
||||
namespace koalageddon {
|
||||
KoalageddonConfig config; // NOLINT(cert-err58-cpp)
|
||||
@ -57,24 +57,24 @@ namespace koalageddon {
|
||||
logger->info("Loaded Koalageddon config from the {}", kg_config_source);
|
||||
}).detach();
|
||||
|
||||
dll_monitor::init({VSTDLIB_DLL, STEAMCLIENT_DLL}, [](const HMODULE& library, const String& name) {
|
||||
dll_monitor::init({VSTDLIB_DLL, STEAMCLIENT_DLL}, [](const HMODULE& module_handle, const String& name) {
|
||||
try {
|
||||
smoke_api::original_library = library;
|
||||
|
||||
static auto init_count = 0;
|
||||
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) {
|
||||
init_vstdlib_hooks();
|
||||
}
|
||||
init_count++;
|
||||
} else if (util::strings_are_equal(name, STEAMCLIENT_DLL)) {
|
||||
// SteamClient DLL handles unlocking functions
|
||||
|
||||
globals::steamclient_module = module_handle;
|
||||
init_steamclient_hooks();
|
||||
init_count++;
|
||||
}
|
||||
|
||||
if (init_count == 2) {
|
||||
if (globals::vstdlib_module != nullptr && globals::steamclient_module != nullptr) {
|
||||
dll_monitor::shutdown();
|
||||
}
|
||||
} catch (const Exception& ex) {
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include <build_config.h>
|
||||
#include <smoke_api/smoke_api.hpp>
|
||||
#include <koalageddon/koalageddon.hpp>
|
||||
#include <koalabox/hook.hpp>
|
||||
#include <koalabox/patcher.hpp>
|
||||
@ -8,7 +7,7 @@
|
||||
#include <Zydis/Zydis.h>
|
||||
#include <Zydis/DecoderTypes.h>
|
||||
|
||||
using namespace smoke_api;
|
||||
using namespace koalabox;
|
||||
|
||||
#define DEMUX_DECL(INTERFACE) \
|
||||
constexpr auto INTERFACE = #INTERFACE; \
|
||||
@ -19,7 +18,6 @@ DEMUX_DECL(IClientApps)
|
||||
DEMUX_DECL(IClientInventory)
|
||||
DEMUX_DECL(IClientUser)
|
||||
|
||||
|
||||
DLL_EXPORT(void) SteamClient_Interface_Interceptor(const char* interface_name, const char* function_name);
|
||||
|
||||
namespace koalageddon {
|
||||
@ -34,30 +32,30 @@ namespace koalageddon {
|
||||
constexpr auto INTERFACE_TARGET_COUNT = 4;
|
||||
|
||||
/*
|
||||
* We need an interface=>function ordinal map in order to hook steam interface function
|
||||
* via virtual function pointer swap. We could construct it by exploiting these code chunks:
|
||||
*
|
||||
* 8B01 | mov eax, dword ptr ds:[ecx]
|
||||
* 68 ???????? | push steamclient.function_name
|
||||
* 68 ???????? | push steamclient.interface_name
|
||||
*
|
||||
* Step 1: Find all addresses that begin with pattern
|
||||
* 8B 01 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? FF 10
|
||||
* Step 2: Extract function and interface name pointers by adding 3 and 8 respectively
|
||||
* Step 3: Starting from the found address, and until the function epilogue, scan for either instructions:
|
||||
*
|
||||
* (1) FF50 ?? | call dword ptr ds:[eax+0x??]
|
||||
* or
|
||||
* (2) 8B40 ?? | mov eax, dword ptr ds:[eax+??]
|
||||
* FFD0 | call eax
|
||||
*
|
||||
* In the case (1), the offset is encoded in the found call instruction.
|
||||
* In the case (2), the offset is encoded in the instruction preceding the call.
|
||||
*
|
||||
* ROADBLOCK: There is actually a case (3) which calls a local variable (ebp-??),
|
||||
* which itself is constructed over multiple instruction calls, making it non-deterministic.
|
||||
* Until this roadblock is resolved, automatic detection of ordinals remains non-viable.
|
||||
*/
|
||||
* We need an interface=>function ordinal map in order to hook steam interface function
|
||||
* via virtual function pointer swap. We could construct it by exploiting these code chunks:
|
||||
*
|
||||
* 8B01 | mov eax, dword ptr ds:[ecx]
|
||||
* 68 ???????? | push steamclient.function_name
|
||||
* 68 ???????? | push steamclient.interface_name
|
||||
*
|
||||
* Step 1: Find all addresses that begin with pattern
|
||||
* 8B 01 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? FF 10
|
||||
* Step 2: Extract function and interface name pointers by adding 3 and 8 respectively
|
||||
* Step 3: Starting from the found address, and until the function epilogue, scan for either instructions:
|
||||
*
|
||||
* (1) FF50 ?? | call dword ptr ds:[eax+0x??]
|
||||
* or
|
||||
* (2) 8B40 ?? | mov eax, dword ptr ds:[eax+??]
|
||||
* FFD0 | call eax
|
||||
*
|
||||
* In the case (1), the offset is encoded in the found call instruction.
|
||||
* In the case (2), the offset is encoded in the instruction preceding the call.
|
||||
*
|
||||
* ROADBLOCK: There is actually a case (3) which calls a local variable (ebp-??),
|
||||
* which itself is constructed over multiple instruction calls, making it non-deterministic.
|
||||
* Until this roadblock is resolved, automatic detection of ordinals remains non-viable.
|
||||
*/
|
||||
[[maybe_unused]] Map<String, uint32_t> construct_interface_function_ordinal_map() {
|
||||
auto* const steamclient_handle = win_util::get_module_handle_or_throw(STEAMCLIENT_DLL);
|
||||
const auto steamclient_module_info = win_util::get_module_info_or_throw(steamclient_handle);
|
||||
@ -170,7 +168,10 @@ namespace koalageddon {
|
||||
const auto start_address = reinterpret_cast<FunctionAddress>(module_info.lpBaseOfDll);
|
||||
auto* terminal_address = (uint8_t*) (start_address + module_info.SizeOfImage);
|
||||
|
||||
// First, find the interface demux
|
||||
// TODO: There may actually be a way to find this address from "first principles"
|
||||
// SteamClient.Steam_CreateSteamPipe begins with a call to fun_alpha()
|
||||
// fun_alpha() calls fun_beta()
|
||||
// ordinal 18
|
||||
const auto* interface_demux_address = patcher::find_pattern_address(
|
||||
module_info,
|
||||
"interface demux",
|
||||
@ -212,13 +213,13 @@ namespace koalageddon {
|
||||
// Finally, hook the demux functions of interest
|
||||
|
||||
if (IClientAppManager == interface_name) {
|
||||
DETOUR(IClientAppManager_Demux, function_demux_address)
|
||||
DETOUR_ADDRESS(IClientAppManager_Demux, function_demux_address)
|
||||
} else if (IClientApps == interface_name) {
|
||||
DETOUR(IClientApps_Demux, function_demux_address)
|
||||
DETOUR_ADDRESS(IClientApps_Demux, function_demux_address)
|
||||
} else if (IClientInventory == interface_name) {
|
||||
DETOUR(IClientInventory_Demux, function_demux_address)
|
||||
DETOUR_ADDRESS(IClientInventory_Demux, function_demux_address)
|
||||
} else if (IClientUser == interface_name) {
|
||||
DETOUR(IClientUser_Demux, function_demux_address)
|
||||
DETOUR_ADDRESS(IClientUser_Demux, function_demux_address)
|
||||
}
|
||||
|
||||
// Update the terminal address to limit the search scope only to relevant portion of the code
|
||||
@ -252,7 +253,7 @@ namespace koalageddon {
|
||||
);
|
||||
|
||||
if (interface_interceptor_address) {
|
||||
DETOUR(SteamClient_Interface_Interceptor, interface_interceptor_address)
|
||||
DETOUR_ADDRESS(SteamClient_Interface_Interceptor, interface_interceptor_address)
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,6 +291,7 @@ DLL_EXPORT(void) SteamClient_Interface_Interceptor(const char* interface_name, c
|
||||
};
|
||||
|
||||
#define HOOK_INTERFACE(FUNC) hook::swap_virtual_func_or_throw( \
|
||||
globals::address_map, \
|
||||
(void*) interface_address, \
|
||||
#FUNC, \
|
||||
koalageddon::config.FUNC##_ordinal, \
|
||||
@ -321,7 +323,7 @@ DLL_EXPORT(void) SteamClient_Interface_Interceptor(const char* interface_name, c
|
||||
});
|
||||
}
|
||||
|
||||
GET_ORIGINAL_FUNCTION(SteamClient_Interface_Interceptor)
|
||||
GET_ORIGINAL_VIRTUAL_FUNCTION(SteamClient_Interface_Interceptor)
|
||||
SteamClient_Interface_Interceptor_o(interface_name, function_name);
|
||||
} catch (const Exception& ex) {
|
||||
logger->error("{} -> Error: {}", __func__, ex.what());
|
||||
@ -344,7 +346,7 @@ DLL_EXPORT(void) INTERFACE##_Demux( \
|
||||
const std::lock_guard<std::mutex> guard(koalageddon::map_mutex); \
|
||||
koalageddon::interface_name_pointer_map[INTERFACE] = arg1; \
|
||||
} \
|
||||
GET_ORIGINAL_FUNCTION(INTERFACE##_Demux) \
|
||||
GET_ORIGINAL_VIRTUAL_FUNCTION(INTERFACE##_Demux) \
|
||||
INTERFACE##_Demux_o(arg1, arg2, arg3, arg4); \
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,17 @@
|
||||
#include <smoke_api/smoke_api.hpp>
|
||||
#include <steam_functions/steam_functions.hpp>
|
||||
#include <core/macros.hpp>
|
||||
#include <koalageddon/koalageddon.hpp>
|
||||
|
||||
#include <steam_functions/steam_functions.hpp>
|
||||
#include <koalabox/hook.hpp>
|
||||
|
||||
using namespace smoke_api;
|
||||
using namespace koalageddon;
|
||||
using namespace koalabox;
|
||||
|
||||
typedef uint32_t HCoroutine;
|
||||
DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, struct CoroutineData* data);
|
||||
|
||||
namespace koalageddon {
|
||||
void init_vstdlib_hooks() {
|
||||
DETOUR_ORIGINAL(Coroutine_Create)
|
||||
DETOUR_VSTDLIB(Coroutine_Create)
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,13 +46,14 @@ struct CoroutineData {
|
||||
};
|
||||
|
||||
VIRTUAL(void) VStdLib_Callback_Interceptor(PARAMS(const char** p_name)) {
|
||||
GET_ORIGINAL_FUNCTION(VStdLib_Callback_Interceptor)
|
||||
GET_ORIGINAL_FUNCTION_VSTDLIB(VStdLib_Callback_Interceptor)
|
||||
|
||||
VStdLib_Callback_Interceptor_o(ARGS(p_name));
|
||||
|
||||
static auto hooked_functions = 0;
|
||||
static auto lock_status_hooked = false;
|
||||
static auto stop_playing_hooked = false;
|
||||
|
||||
if (hooked_functions == 2) {
|
||||
if (lock_status_hooked && stop_playing_hooked) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -62,18 +63,13 @@ VIRTUAL(void) VStdLib_Callback_Interceptor(PARAMS(const char** p_name)) {
|
||||
const auto name = String(data->get_callback_name());
|
||||
// logger->trace("{} -> instance: {}, name: '{}'", __func__, fmt::ptr(THIS), name);
|
||||
|
||||
if (name == "SharedLicensesLockStatus") {
|
||||
static std::once_flag flag;
|
||||
std::call_once(flag, [&]() {
|
||||
DETOUR(SharedLicensesLockStatus, data->get_callback_data()->get_callback_address())
|
||||
hooked_functions++;
|
||||
});
|
||||
} else if (name == "SharedLibraryStopPlaying") {
|
||||
static std::once_flag flag;
|
||||
std::call_once(flag, [&]() {
|
||||
DETOUR(SharedLibraryStopPlaying, data->get_callback_data()->get_callback_address())
|
||||
hooked_functions++;
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,7 +79,7 @@ VIRTUAL(void) VStdLib_Callback_Interceptor(PARAMS(const char** p_name)) {
|
||||
* hence we must hook an interface method that sets the callback name.
|
||||
*/
|
||||
DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, CoroutineData* data) {
|
||||
GET_ORIGINAL_FUNCTION(Coroutine_Create)
|
||||
GET_ORIGINAL_FUNCTION_VSTDLIB(Coroutine_Create)
|
||||
|
||||
const auto result = Coroutine_Create_o(callback_address, data);
|
||||
|
||||
@ -92,7 +88,7 @@ DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, CoroutineData* d
|
||||
std::call_once(flag, [&]() {
|
||||
logger->debug("Coroutine_Create -> callback: {}, data: {}", callback_address, fmt::ptr(data));
|
||||
|
||||
DETOUR(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;
|
||||
|
@ -11,30 +11,29 @@
|
||||
#include <koalabox/loader.hpp>
|
||||
#include <koalabox/win_util.hpp>
|
||||
|
||||
// TODO: Define COMPILE_KOALAGEDDON in CMake
|
||||
#ifndef _WIN64
|
||||
#include <koalageddon/koalageddon.hpp>
|
||||
#endif
|
||||
|
||||
namespace smoke_api {
|
||||
HMODULE original_library = nullptr;
|
||||
|
||||
HMODULE self_module = nullptr;
|
||||
|
||||
bool is_hook_mode = false;
|
||||
using namespace koalabox;
|
||||
|
||||
void init_proxy_mode() {
|
||||
logger->info("🔀 Detected proxy mode");
|
||||
|
||||
original_library = loader::load_original_library(paths::get_self_path(), ORIGINAL_DLL);
|
||||
globals::steamapi_module = loader::load_original_library(paths::get_self_path(), STEAMAPI_DLL);
|
||||
}
|
||||
|
||||
void init_hook_mode() {
|
||||
logger->info("🪝 Detected hook mode");
|
||||
|
||||
dll_monitor::init(STEAMCLIENT_DLL, [](const HMODULE& library) {
|
||||
original_library = library;
|
||||
globals::steamclient_module = library;
|
||||
|
||||
DETOUR_ORIGINAL(CreateInterface)
|
||||
DETOUR_STEAMCLIENT(CreateInterface)
|
||||
|
||||
dll_monitor::shutdown();
|
||||
});
|
||||
|
||||
// Hooking steam_api has shown itself to be less desirable than steamclient
|
||||
@ -79,7 +78,7 @@ namespace smoke_api {
|
||||
try {
|
||||
DisableThreadLibraryCalls(module_handle);
|
||||
|
||||
globals::self_module = module_handle;
|
||||
globals::smokeapi_handle = module_handle;
|
||||
|
||||
koalabox::project_name = PROJECT_NAME;
|
||||
|
||||
@ -97,9 +96,7 @@ namespace smoke_api {
|
||||
|
||||
logger->debug(R"(Process name: "{}" [{}-bit])", exe_name, exe_bitness);
|
||||
|
||||
is_hook_mode = hook::is_hook_mode(self_module, ORIGINAL_DLL);
|
||||
|
||||
if (is_hook_mode) {
|
||||
if (hook::is_hook_mode(globals::smokeapi_handle, STEAMAPI_DLL)) {
|
||||
hook::init(true);
|
||||
|
||||
#ifdef _WIN64
|
||||
@ -125,10 +122,8 @@ namespace smoke_api {
|
||||
|
||||
void shutdown() {
|
||||
try {
|
||||
if (is_hook_mode) {
|
||||
dll_monitor::shutdown();
|
||||
} else {
|
||||
win_util::free_library(original_library);
|
||||
if (globals::steamapi_module != nullptr) {
|
||||
win_util::free_library(globals::steamapi_module);
|
||||
}
|
||||
|
||||
logger->info("💀 Shutdown complete");
|
||||
|
@ -1,37 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <koalabox/koalabox.hpp>
|
||||
#include <koalabox/hook.hpp> // For macros
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#define GET_ORIGINAL_FUNCTION(FUNC) \
|
||||
static const auto FUNC##_o = hook::get_original_function( \
|
||||
smoke_api::is_hook_mode, \
|
||||
smoke_api::original_library, \
|
||||
#FUNC, \
|
||||
FUNC \
|
||||
);
|
||||
|
||||
#define GET_ORIGINAL_VIRTUAL_FUNCTION(FUNC) \
|
||||
const auto FUNC##_o = hook::get_original_function( \
|
||||
true, \
|
||||
smoke_api::original_library, \
|
||||
#FUNC, \
|
||||
FUNC \
|
||||
);
|
||||
|
||||
namespace smoke_api {
|
||||
using namespace koalabox;
|
||||
|
||||
extern HMODULE self_module;
|
||||
|
||||
extern HMODULE original_library;
|
||||
|
||||
extern bool is_hook_mode;
|
||||
|
||||
void init(HMODULE module_handle);
|
||||
|
||||
void shutdown();
|
||||
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
#include <smoke_api/smoke_api.hpp>
|
||||
#include <core/macros.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>
|
||||
|
||||
using namespace smoke_api;
|
||||
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_ISteamApps_BIsSubscribedApp)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_BIsSubscribedApp)
|
||||
|
||||
return SteamAPI_ISteamApps_BIsSubscribedApp_o(self, appID);
|
||||
});
|
||||
@ -18,7 +18,7 @@ DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(ISteamApps* self, AppId_t
|
||||
|
||||
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsDlcInstalled(ISteamApps* self, AppId_t appID) {
|
||||
return steam_apps::IsDlcUnlocked(__func__, 0, appID, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamApps_BIsDlcInstalled)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_BIsDlcInstalled)
|
||||
|
||||
return SteamAPI_ISteamApps_BIsDlcInstalled_o(self, appID);
|
||||
});
|
||||
@ -26,7 +26,7 @@ DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsDlcInstalled(ISteamApps* self, AppId_t a
|
||||
|
||||
DLL_EXPORT(int) SteamAPI_ISteamApps_GetDLCCount(ISteamApps* self) {
|
||||
return steam_apps::GetDLCCount(__func__, 0, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamApps_GetDLCCount)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_GetDLCCount)
|
||||
|
||||
return SteamAPI_ISteamApps_GetDLCCount_o(self);
|
||||
});
|
||||
@ -41,7 +41,7 @@ DLL_EXPORT(bool) SteamAPI_ISteamApps_BGetDLCDataByIndex(
|
||||
int cchNameBufferSize
|
||||
) {
|
||||
return steam_apps::GetDLCDataByIndex(__func__, 0, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamApps_BGetDLCDataByIndex)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamApps_BGetDLCDataByIndex)
|
||||
|
||||
return SteamAPI_ISteamApps_BGetDLCDataByIndex_o(
|
||||
self, iDLC, pAppID, pbAvailable, pchName, cchNameBufferSize
|
||||
@ -57,7 +57,7 @@ DLL_EXPORT(EUserHasLicenseForAppResult) SteamAPI_ISteamUser_UserHasLicenseForApp
|
||||
AppId_t appID
|
||||
) {
|
||||
return steam_user::UserHasLicenseForApp(__func__, appID, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamUser_UserHasLicenseForApp)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamUser_UserHasLicenseForApp)
|
||||
|
||||
return SteamAPI_ISteamUser_UserHasLicenseForApp_o(self, steamID, appID);
|
||||
});
|
||||
@ -72,7 +72,7 @@ DLL_EXPORT(void*) SteamAPI_ISteamClient_GetISteamGenericInterface(
|
||||
const char* pchVersion
|
||||
) {
|
||||
return steam_client::GetGenericInterface(__func__, pchVersion, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamClient_GetISteamGenericInterface)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamClient_GetISteamGenericInterface)
|
||||
|
||||
return SteamAPI_ISteamClient_GetISteamGenericInterface_o(self, hSteamUser, hSteamPipe, pchVersion);
|
||||
});
|
||||
@ -85,7 +85,7 @@ DLL_EXPORT(EResult) SteamAPI_ISteamInventory_GetResultStatus(
|
||||
SteamInventoryResult_t resultHandle
|
||||
) {
|
||||
return steam_inventory::GetResultStatus(__func__, resultHandle, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamInventory_GetResultStatus)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetResultStatus)
|
||||
|
||||
return SteamAPI_ISteamInventory_GetResultStatus_o(self, resultHandle);
|
||||
});
|
||||
@ -100,12 +100,12 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItems(
|
||||
return steam_inventory::GetResultItems(
|
||||
__func__, resultHandle, pOutItemsArray, punOutItemsArraySize,
|
||||
[&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamInventory_GetResultItems)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetResultItems)
|
||||
|
||||
return SteamAPI_ISteamInventory_GetResultItems_o(self, resultHandle, pOutItemsArray, punOutItemsArraySize);
|
||||
},
|
||||
[&](SteamItemDef_t* pItemDefIDs, uint32_t* punItemDefIDsArraySize) {
|
||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamInventory_GetItemDefinitionIDs)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetItemDefinitionIDs)
|
||||
|
||||
return SteamAPI_ISteamInventory_GetItemDefinitionIDs_o(self, pItemDefIDs, punItemDefIDsArraySize);
|
||||
}
|
||||
@ -122,7 +122,7 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItemProperty(
|
||||
) {
|
||||
return steam_inventory::GetResultItemProperty(
|
||||
__func__, resultHandle, unItemIndex, pchPropertyName, pchValueBuffer, punValueBufferSizeOut, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamInventory_GetResultItemProperty)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetResultItemProperty)
|
||||
|
||||
return SteamAPI_ISteamInventory_GetResultItemProperty_o(
|
||||
self, resultHandle, unItemIndex, pchPropertyName, pchValueBuffer, punValueBufferSizeOut
|
||||
@ -137,7 +137,7 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_CheckResultSteamID(
|
||||
CSteamID steamIDExpected
|
||||
) {
|
||||
return steam_inventory::CheckResultSteamID(__func__, resultHandle, steamIDExpected, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamInventory_CheckResultSteamID)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_CheckResultSteamID)
|
||||
|
||||
return SteamAPI_ISteamInventory_CheckResultSteamID_o(self, resultHandle, steamIDExpected);
|
||||
});
|
||||
@ -148,7 +148,7 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetAllItems(
|
||||
SteamInventoryResult_t* pResultHandle
|
||||
) {
|
||||
return steam_inventory::GetAllItems(__func__, pResultHandle, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamInventory_GetAllItems)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetAllItems)
|
||||
|
||||
return SteamAPI_ISteamInventory_GetAllItems_o(self, pResultHandle);
|
||||
});
|
||||
@ -161,7 +161,7 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemsByID(
|
||||
uint32_t unCountInstanceIDs
|
||||
) {
|
||||
return steam_inventory::GetItemsByID(__func__, pResultHandle, pInstanceIDs, unCountInstanceIDs, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamInventory_GetItemsByID)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetItemsByID)
|
||||
|
||||
return SteamAPI_ISteamInventory_GetItemsByID_o(self, pResultHandle, pInstanceIDs, unCountInstanceIDs);
|
||||
});
|
||||
@ -174,7 +174,7 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_SerializeResult(
|
||||
uint32_t* punOutBufferSize
|
||||
) {
|
||||
return steam_inventory::SerializeResult(__func__, resultHandle, pOutBuffer, punOutBufferSize, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamInventory_SerializeResult)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_SerializeResult)
|
||||
|
||||
return SteamAPI_ISteamInventory_SerializeResult_o(self, resultHandle, pOutBuffer, punOutBufferSize);
|
||||
});
|
||||
@ -186,7 +186,7 @@ DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemDefinitionIDs(
|
||||
uint32_t* punItemDefIDsArraySize
|
||||
) {
|
||||
return steam_inventory::GetItemDefinitionIDs(__func__, pItemDefIDs, punItemDefIDsArraySize, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamAPI_ISteamInventory_GetItemDefinitionIDs)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_ISteamInventory_GetItemDefinitionIDs)
|
||||
|
||||
return SteamAPI_ISteamInventory_GetItemDefinitionIDs_o(self, pItemDefIDs, punItemDefIDsArraySize);
|
||||
});
|
||||
|
@ -1,11 +1,12 @@
|
||||
#include <smoke_api/smoke_api.hpp>
|
||||
#include <core/macros.hpp>
|
||||
#include <koalabox/hook.hpp>
|
||||
#include <steam_impl/steam_client.hpp>
|
||||
|
||||
using namespace smoke_api;
|
||||
using namespace koalabox;
|
||||
|
||||
DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(HSteamUser hSteamUser, const char* version) {
|
||||
return steam_client::GetGenericInterface(__func__, version, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamInternal_FindOrCreateUserInterface)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamInternal_FindOrCreateUserInterface)
|
||||
|
||||
return SteamInternal_FindOrCreateUserInterface_o(hSteamUser, version);
|
||||
});
|
||||
@ -13,7 +14,7 @@ DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(HSteamUser hSteamUser,
|
||||
|
||||
DLL_EXPORT(void*) SteamInternal_CreateInterface(const char* version) {
|
||||
return steam_client::GetGenericInterface(__func__, version, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamInternal_CreateInterface)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamInternal_CreateInterface)
|
||||
|
||||
return SteamInternal_CreateInterface_o(version);
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ String get_versioned_interface(const String& version_prefix, const String& fallb
|
||||
|
||||
if (not version_map.contains(version_prefix)) {
|
||||
try {
|
||||
const String rdata = win_util::get_pe_section_data_or_throw(original_library, ".rdata");
|
||||
const String rdata = win_util::get_pe_section_data_or_throw(globals::steamapi_module, ".rdata");
|
||||
|
||||
const std::regex regex(version_prefix + "\\d{3}");
|
||||
std::smatch match;
|
||||
@ -44,7 +44,7 @@ DLL_EXPORT(void*) SteamClient() {
|
||||
static auto version = get_versioned_interface(STEAM_CLIENT, "006");
|
||||
|
||||
return steam_client::GetGenericInterface(__func__, version, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamClient)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamClient)
|
||||
|
||||
return SteamClient_o();
|
||||
});
|
||||
@ -54,7 +54,7 @@ DLL_EXPORT(void*) SteamApps() {
|
||||
static auto version = get_versioned_interface(STEAM_APPS, "002");
|
||||
|
||||
return steam_client::GetGenericInterface(__func__, version, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamApps)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamApps)
|
||||
|
||||
return SteamApps_o();
|
||||
});
|
||||
@ -64,7 +64,7 @@ DLL_EXPORT(void*) SteamUser() {
|
||||
static auto version = get_versioned_interface(STEAM_USER, "012");
|
||||
|
||||
return steam_client::GetGenericInterface(__func__, version, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamUser)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamUser)
|
||||
|
||||
return SteamUser_o();
|
||||
});
|
||||
@ -74,7 +74,7 @@ DLL_EXPORT(void*) SteamInventory() {
|
||||
static auto version = get_versioned_interface(STEAM_INVENTORY, "001");
|
||||
|
||||
return steam_client::GetGenericInterface(__func__, version, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(SteamInventory)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(SteamInventory)
|
||||
|
||||
return SteamInventory_o();
|
||||
});
|
||||
|
@ -1,11 +1,8 @@
|
||||
#include <smoke_api/smoke_api.hpp>
|
||||
#include <steam_impl/steam_apps.hpp>
|
||||
|
||||
using namespace smoke_api;
|
||||
|
||||
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t appID)) { // NOLINT(misc-unused-parameters)
|
||||
return steam_apps::IsDlcUnlocked(__func__, 0, appID, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(ISteamApps_BIsSubscribedApp)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(ISteamApps_BIsSubscribedApp)
|
||||
|
||||
return ISteamApps_BIsSubscribedApp_o(ARGS(appID));
|
||||
});
|
||||
@ -13,7 +10,7 @@ VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t appID)) { // NOLINT(mis
|
||||
|
||||
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(AppId_t appID)) { // NOLINT(misc-unused-parameters)
|
||||
return steam_apps::IsDlcUnlocked(__func__, 0, appID, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(ISteamApps_BIsDlcInstalled)
|
||||
GET_ORIGINAL_FUNCTION_STEAMAPI(ISteamApps_BIsDlcInstalled)
|
||||
|
||||
return ISteamApps_BIsDlcInstalled_o(ARGS(appID));
|
||||
});
|
||||
|
@ -121,7 +121,8 @@ namespace steam_functions {
|
||||
|
||||
#define HOOK(MAP, FUNC) \
|
||||
hook::swap_virtual_func( \
|
||||
interface, \
|
||||
globals::address_map, \
|
||||
interface, \
|
||||
#FUNC, \
|
||||
get_ordinal(MAP, #FUNC, version_number), \
|
||||
(FunctionAddress) (FUNC) \
|
||||
@ -202,7 +203,7 @@ namespace steam_functions {
|
||||
}
|
||||
|
||||
HSteamPipe get_steam_pipe_or_throw() {
|
||||
const auto& steam_api_module = win_util::get_module_handle_or_throw(ORIGINAL_DLL);
|
||||
const auto& steam_api_module = win_util::get_module_handle_or_throw(STEAMAPI_DLL);
|
||||
void* GetHSteamPipe_address;
|
||||
try {
|
||||
GetHSteamPipe_address = (void*) win_util::get_proc_address_or_throw(
|
||||
|
@ -108,7 +108,8 @@ namespace steam_apps {
|
||||
|
||||
bool IsDlcUnlocked(
|
||||
const String& function_name,
|
||||
AppId_t app_id, AppId_t dlc_id,
|
||||
AppId_t app_id,
|
||||
AppId_t dlc_id,
|
||||
const std::function<bool()>& original_function
|
||||
) {
|
||||
try {
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include <smoke_api/smoke_api.hpp>
|
||||
#include <koalabox/koalabox.hpp>
|
||||
#include <steam_functions/steam_functions.hpp>
|
||||
|
||||
namespace steam_client {
|
||||
using namespace smoke_api;
|
||||
using namespace koalabox;
|
||||
|
||||
void* GetGenericInterface(
|
||||
const String& function_name,
|
||||
|
@ -1,9 +1,8 @@
|
||||
#include <smoke_api/smoke_api.hpp>
|
||||
#include <koalabox/koalabox.hpp>
|
||||
#include <steam_functions/steam_functions.hpp>
|
||||
|
||||
using namespace smoke_api;
|
||||
|
||||
namespace steam_user {
|
||||
using namespace koalabox;
|
||||
|
||||
EUserHasLicenseForAppResult UserHasLicenseForApp(
|
||||
const String& function_name,
|
||||
|
@ -5,7 +5,7 @@ using namespace smoke_api;
|
||||
|
||||
DLL_EXPORT(void*) CreateInterface(const char* interface_string, int* out_result) {
|
||||
return steam_client::GetGenericInterface(__func__, interface_string, [&]() {
|
||||
GET_ORIGINAL_FUNCTION(CreateInterface)
|
||||
GET_ORIGINAL_FUNCTION_STEAMCLIENT(CreateInterface)
|
||||
|
||||
return CreateInterface_o(interface_string, out_result);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user