Reworked tools

This commit is contained in:
acidicoala
2025-08-18 05:23:13 +05:00
parent 5f1e83adad
commit b170fd2276
23 changed files with 5826 additions and 3510 deletions

View File

@@ -1,10 +1,10 @@
#pragma once
#include <nlohmann/json.hpp>
#include <core/globals.hpp>
#include <koalabox/core.hpp>
#include <koalabox/hook.hpp>
#include <koalabox/logger.hpp>
#include <nlohmann/json.hpp>
/**
* By default, virtual functions are declared with __thiscall
@@ -30,35 +30,39 @@
* The macros below implement the above-mentioned considerations.
*/
#ifdef _WIN64
#define PARAMS(...) void* RCX, __VA_ARGS__
#define PARAMS(...) void *RCX, __VA_ARGS__
#define ARGS(...) RCX, __VA_ARGS__
#define THIS RCX
#else
#define PARAMS(...) const void* ECX, const void* EDX, __VA_ARGS__
#define PARAMS(...) const void *ECX, const void *EDX, __VA_ARGS__
#define ARGS(...) ECX, EDX, __VA_ARGS__
#define THIS ECX
#endif
// Names beginning with $ designate macros that are not meant to be used directly by the sources consuming this file
// Names beginning with $ designate macros that are not meant to be used directly by the sources
// consuming this file
// IMPORTANT: DLL_EXPORT is hardcoded in exports_generator.cpp,
// so any name changes here must be reflected there as well.
#define DLL_EXPORT(TYPE) extern "C" [[maybe_unused]] __declspec(dllexport) TYPE __cdecl
#define DLL_EXPORT(TYPE) extern "C" [[maybe_unused]] __declspec( dllexport ) TYPE __cdecl
#define VIRTUAL(TYPE) __declspec(noinline) TYPE __fastcall
// TODO: Replace with direct call
#define GET_ORIGINAL_HOOKED_FUNCTION(FUNC) \
#define GET_ORIGINAL_HOOKED_FUNCTION(FUNC) \
static const auto FUNC##_o = koalabox::hook::get_original_hooked_function(#FUNC, FUNC);
#define ORIGINAL_FUNCTION_STEAMAPI(FUNC) \
#define ORIGINAL_FUNCTION_STEAMAPI(FUNC) \
koalabox::hook::get_original_function(globals::steamapi_module, #FUNC, FUNC)
// TODO: Rename to DEFINE_ORIGINAL_FUNCTION_STEAMAPI
#define GET_ORIGINAL_FUNCTION_STEAMAPI(FUNC) \
#define GET_ORIGINAL_FUNCTION_STEAMAPI(FUNC) \
static const auto FUNC##_o = ORIGINAL_FUNCTION_STEAMAPI(FUNC);
#define DETOUR_ADDRESS(FUNC, ADDRESS) \
#define DETOUR_ADDRESS(FUNC, ADDRESS) \
koalabox::hook::detour_or_warn(ADDRESS, #FUNC, reinterpret_cast<uintptr_t>(FUNC));
#define $DETOUR(FUNC, NAME, MODULE_HANDLE) \
#define $DETOUR(FUNC, NAME, MODULE_HANDLE) \
koalabox::hook::detour_or_warn(MODULE_HANDLE, NAME, reinterpret_cast<uintptr_t>(FUNC));
#define DETOUR_STEAMCLIENT(FUNC) $DETOUR(FUNC, #FUNC, globals::steamclient_module)
@@ -116,16 +120,15 @@ struct App {
using AppDlcNameMap = Map<AppIdKey, App>;
class DLC {
private:
private:
// These 2 names must match the property names from Steam API
String appid;
String name;
public:
public:
explicit DLC() = default;
explicit DLC(String appid, String name) : appid{std::move(appid)}, name{std::move(name)} {
}
explicit DLC(String appid, String name) : appid{std::move(appid)}, name{std::move(name)} {}
[[nodiscard]] String get_id_str() const {
return appid;
@@ -141,7 +144,7 @@ public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(DLC, appid, name)
static Vector<DLC> get_dlcs_from_apps(const AppDlcNameMap &apps, AppId_t app_id);
static Vector<DLC> get_dlcs_from_apps(const AppDlcNameMap& apps, AppId_t app_id);
static DlcNameMap get_dlc_map_from_vector(const Vector<DLC> &vector);
static DlcNameMap get_dlc_map_from_vector(const Vector<DLC>& vector);
};

View File

@@ -1,5 +1,18 @@
#include <smoke_api/config.hpp>
// DLL_EXPORT(void) SteamAPI_Shutdown1() {
// LOG_INFO("{} -> Game requested shutdown", __func__);
//
// ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_Shutdown)();
// }
/*DLL_EXPORT(void) SteamAPI_Shutdown2() {
LOG_INFO("{} -> Game requested shutdown", __func__);
ORIGINAL_FUNCTION_STEAMAPI(SteamAPI_Shutdown)();
}*/
// TODO: Detour in hook mode
DLL_EXPORT(bool) SteamAPI_RestartAppIfNecessary(
[[maybe_unused]] const uint32_t unOwnAppID

View File

@@ -5,6 +5,7 @@
#include <koalabox/hook.hpp>
#include <koalabox/loader.hpp>
#include <koalabox/logger.hpp>
#include <koalabox/str.hpp>
#include <koalabox/util.hpp>
#include <koalabox/win_util.hpp>
@@ -40,8 +41,9 @@
namespace {
void override_app_id() {
const auto override_app_id = smoke_api::config::instance.override_app_id;
if (override_app_id == 0)
if (override_app_id == 0) {
return;
}
spdlog::default_logger_raw();
LOG_DEBUG("Overriding app id to {}", override_app_id);
@@ -74,7 +76,7 @@ namespace {
bool is_valve_steam(const String& exe_name) noexcept {
try {
if (exe_name < not_equals > "steam.exe") {
if (not koalabox::str::eq(exe_name, "steam.exe")) {
return false;
}
@@ -85,7 +87,7 @@ namespace {
const auto manifest = koalabox::win_util::get_module_manifest(steam_handle);
// Steam.exe manifest is expected to contain this string
return manifest < contains > "valvesoftware.steam.steam";
return manifest.contains("valvesoftware.steam.steam");
} catch (const Exception& e) {
LOG_ERROR("{} -> {}", __func__, e.what());

View File

@@ -4,14 +4,14 @@
VIRTUAL(bool) IClientAppManager_IsAppDlcInstalled(PARAMS(AppId_t app_id, AppId_t dlc_id)) {
try {
return steam_apps::IsDlcUnlocked(
__func__, app_id, dlc_id, [&]() {
__func__, app_id, dlc_id, [&] {
GET_ORIGINAL_HOOKED_FUNCTION(IClientAppManager_IsAppDlcInstalled)
return IClientAppManager_IsAppDlcInstalled_o(ARGS(app_id, dlc_id));
}
);
} catch (const Exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what())
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return false;
}
}

View File

@@ -11,7 +11,7 @@ VIRTUAL(int) IClientApps_GetDLCCount(PARAMS(AppId_t appId)) {
}
);
} catch (const Exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what())
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return 0;
}
}
@@ -36,7 +36,7 @@ VIRTUAL(bool) IClientApps_BGetDLCDataByIndex(
ARGS(appID, iDLC, pDlcID, pbAvailable, pchName, cchNameBufferSize)
);
},
[&](AppId_t dlc_id) {
[&](const AppId_t dlc_id) {
const auto* app_manager_interface = store::steamclient::interface_name_to_address_map["IClientAppManager"];
if (app_manager_interface) {
IClientAppManager_IsAppDlcInstalled(app_manager_interface, EDX, appID, dlc_id);
@@ -48,7 +48,7 @@ VIRTUAL(bool) IClientApps_BGetDLCDataByIndex(
}
);
} catch (const Exception& e) {
LOG_ERROR("{} -> Error: {}", __func__, e.what())
LOG_ERROR("{} -> Error: {}", __func__, e.what());
return false;
}
}

View File

@@ -91,7 +91,7 @@ namespace store::steamclient {
}
void detour_interface_selector(const String& interface_name, uintptr_t function_selector_address) {
LOG_DEBUG("Detected interface: '{}'", interface_name)
LOG_DEBUG("Detected interface: '{}'", interface_name);
DETOUR_SELECTOR(IClientAppManager)
DETOUR_SELECTOR(IClientApps)
@@ -198,10 +198,10 @@ namespace store::steamclient {
const std::list<ZydisDecodedInstruction>& instruction_list
)>& callback
) {
LOG_TRACE("{} -> start_address: {}", __func__, (void*) start_address)
LOG_TRACE("{} -> start_address: {}", __func__, (void*) start_address);
if (visited_addresses.contains(start_address)) {
LOG_TRACE("Breaking recursion due to visited address")
LOG_TRACE("Breaking recursion due to visited address");
return;
}
@@ -222,7 +222,7 @@ namespace store::steamclient {
LOG_TRACE(
"{} -> visiting {} │ {}",
__func__, (void*) current_address, *get_instruction_string(instruction, current_address)
)
);
const auto operand = instruction.operands[0];
@@ -239,7 +239,7 @@ namespace store::steamclient {
visit_code(visited_addresses, jump_taken_destination, context, callback);
visit_code(visited_addresses, jump_not_taken_destination, context, callback);
LOG_TRACE("{} -> Breaking recursion due to a conditional branch", __func__)
LOG_TRACE("{} -> Breaking recursion due to a conditional branch", __func__);
return;
}
@@ -266,12 +266,12 @@ namespace store::steamclient {
table_entry++;
}
LOG_TRACE("{} -> Breaking recursion due to a jump table", __func__)
LOG_TRACE("{} -> Breaking recursion due to a jump table", __func__);
return;
}
if (instruction.mnemonic == ZYDIS_MNEMONIC_RET) {
LOG_TRACE("{} -> Breaking recursion due to return instruction", __func__)
LOG_TRACE("{} -> Breaking recursion due to return instruction", __func__);
return;
}
@@ -385,7 +385,7 @@ namespace store::steamclient {
if (offset && is_derived_from_base_reg) {
const auto ordinal = *offset / sizeof(uintptr_t);
LOG_DEBUG("Found function ordinal {}::{}@{}", target_interface, function_name, ordinal)
LOG_DEBUG("Found function ordinal {}::{}@{}", target_interface, function_name, ordinal);
function_name_to_ordinal_map[function_name] = ordinal;
return true;
@@ -410,7 +410,7 @@ namespace store::steamclient {
const auto&
) {
if (instruction.mnemonic == ZYDIS_MNEMONIC_CALL && operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE) {
LOG_TRACE("Found call instruction at {}", (void*) current_address)
LOG_TRACE("Found call instruction at {}", (void*) current_address);
const auto function_selector_address = get_absolute_address(instruction, current_address);
@@ -436,15 +436,15 @@ namespace store::steamclient {
store::config.steam_client_internal_interface_selector_ordinal
];
LOG_DEBUG("Found interface selector at: {}", (void*) interface_selector_address)
LOG_DEBUG("Found interface selector at: {}", (void*) interface_selector_address);
if (ZYAN_FAILED(ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_ADDRESS_WIDTH_32))) {
LOG_ERROR("Failed to initialize zydis decoder")
if (ZYAN_FAILED(ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_STACK_WIDTH_32))) {
LOG_ERROR("Failed to initialize zydis decoder");
return;
}
if (ZYAN_FAILED(ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL))) {
LOG_ERROR("Failed to initialize zydis formatter")
LOG_ERROR("Failed to initialize zydis formatter");
return;
}

View File

@@ -1,13 +1,15 @@
#include <store_mode/store.hpp>
#include <store_mode/vstdlib/vstdlib.hpp>
#include <store_mode/store_cache.hpp>
#include <store_mode/store_api.hpp>
#include <smoke_api/config.hpp>
#include "koalabox/str.hpp"
#include <build_config.h>
#include <koalabox/dll_monitor.hpp>
#include <koalabox/logger.hpp>
#include <koalabox/ipc.hpp>
#include <common/steamclient_exports.hpp>
#include <koalabox/dll_monitor.hpp>
#include <koalabox/ipc.hpp>
#include <koalabox/logger.hpp>
#include <smoke_api/config.hpp>
#include <store_mode/store.hpp>
#include <store_mode/store_api.hpp>
#include <store_mode/store_cache.hpp>
#include <store_mode/vstdlib/vstdlib.hpp>
namespace store {
@@ -18,7 +20,7 @@ namespace store {
*/
void init_store_config() {
const auto print_source = [](const String& source) {
LOG_INFO("Loaded Store config from the {}", source)
LOG_INFO("Loaded Store config from the {}", source);
};
// First try to read a local config override
@@ -30,7 +32,7 @@ namespace store {
print_source("local config override");
return;
} catch (const Exception& ex) {
LOG_ERROR("Failed to get local store_mode config: {}", ex.what())
LOG_ERROR("Failed to get local store_mode config: {}", ex.what());
}
}
@@ -40,7 +42,7 @@ namespace store {
print_source("disk cache");
} catch (const Exception& ex) {
LOG_ERROR("Failed to get cached store_mode config: {}", ex.what())
LOG_ERROR("Failed to get cached store_mode config: {}", ex.what());
print_source("default config bundled in the binary");
@@ -62,7 +64,7 @@ namespace store {
store_cache::save_store_config(github_config);
if (github_config == config) {
LOG_DEBUG("Fetched Store config is equal to existing config")
LOG_DEBUG("Fetched Store config is equal to existing config");
return;
}
@@ -79,7 +81,7 @@ namespace store {
MB_SETFOREGROUND | MB_ICONINFORMATION | MB_OK
);
} catch (const Exception& ex) {
LOG_ERROR("Failed to get remote store_mode config: {}", ex.what())
LOG_ERROR("Failed to get remote store_mode config: {}", ex.what());
}
})
}
@@ -90,7 +92,7 @@ namespace store {
koalabox::dll_monitor::init_listener(
{VSTDLIB_DLL, STEAMCLIENT_DLL}, [](const HMODULE& module_handle, const String& name) {
try {
if (name < equals > VSTDLIB_DLL) {
if (koalabox::str::eq(name, VSTDLIB_DLL)) {
// VStdLib DLL handles Family Sharing functions
globals::vstdlib_module = module_handle;
@@ -98,7 +100,7 @@ namespace store {
if (smoke_api::config::instance.unlock_family_sharing) {
DETOUR_VSTDLIB(Coroutine_Create)
}
} else if (name < equals > STEAMCLIENT_DLL) {
} else if (koalabox::str::eq(name, STEAMCLIENT_DLL)) {
// SteamClient DLL handles unlocking functions
globals::steamclient_module = module_handle;
@@ -113,7 +115,7 @@ namespace store {
LOG_ERROR(
"Error listening to DLL load events. Module: '{}', Message: {}",
name, ex.what()
)
);
}
}
);