mirror of
https://github.com/acidicoala/SmokeAPI.git
synced 2026-01-24 21:42:53 -05:00
Split static & shared lib
This commit is contained in:
23
src/steam_api/exports/steam_api.cpp
Normal file
23
src/steam_api/exports/steam_api.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <koalabox/logger.hpp>
|
||||
|
||||
#include "smoke_api.hpp"
|
||||
#include "smoke_api/config.hpp"
|
||||
|
||||
// TODO: Support in hook mode
|
||||
DLL_EXPORT(bool) SteamAPI_RestartAppIfNecessary(const uint32_t unOwnAppID) {
|
||||
if(smoke_api::config::instance.override_app_id != 0) {
|
||||
LOG_DEBUG("{} -> {}. Preventing app restart", unOwnAppID, __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note: Assumes proxy mode only
|
||||
MODULE_CALL(SteamAPI_RestartAppIfNecessary, unOwnAppID);
|
||||
}
|
||||
|
||||
// TODO: Support in hook mode
|
||||
DLL_EXPORT(void) SteamAPI_Shutdown() {
|
||||
LOG_INFO("{} -> Game requested shutdown", __func__);
|
||||
|
||||
// Note: Assumes proxy mode only
|
||||
MODULE_CALL(SteamAPI_Shutdown);
|
||||
}
|
||||
296
src/steam_api/exports/steam_api_flat.cpp
Normal file
296
src/steam_api/exports/steam_api_flat.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
#include <koalabox/logger.hpp>
|
||||
|
||||
#include "smoke_api.hpp"
|
||||
#include "smoke_api/interfaces/steam_apps.hpp"
|
||||
#include "smoke_api/interfaces/steam_inventory.hpp"
|
||||
#include "smoke_api/interfaces/steam_user.hpp"
|
||||
#include "steam_api/steam_client.hpp"
|
||||
#include "steam_api/steam_interface.hpp"
|
||||
|
||||
// ISteamApps
|
||||
|
||||
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsSubscribedApp(void* self, AppId_t dlcID) {
|
||||
try {
|
||||
return smoke_api::steam_apps::IsDlcUnlocked(
|
||||
__func__,
|
||||
steam_interface::get_app_id(),
|
||||
dlcID,
|
||||
MODULE_CALL_CLOSURE(SteamAPI_ISteamApps_BIsSubscribedApp, self, dlcID)
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DLL_EXPORT(bool) SteamAPI_ISteamApps_BIsDlcInstalled(void* self, AppId_t dlcID) {
|
||||
try {
|
||||
return smoke_api::steam_apps::IsDlcUnlocked(
|
||||
__func__,
|
||||
steam_interface::get_app_id(),
|
||||
dlcID,
|
||||
MODULE_CALL_CLOSURE(SteamAPI_ISteamApps_BIsDlcInstalled, self, dlcID)
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DLL_EXPORT(int) SteamAPI_ISteamApps_GetDLCCount(void* self) {
|
||||
try {
|
||||
return smoke_api::steam_apps::GetDLCCount(
|
||||
__func__,
|
||||
steam_interface::get_app_id(),
|
||||
MODULE_CALL_CLOSURE(SteamAPI_ISteamApps_GetDLCCount, self)
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DLL_EXPORT(bool) SteamAPI_ISteamApps_BGetDLCDataByIndex(
|
||||
void* self,
|
||||
const int iDLC,
|
||||
AppId_t* pDlcID,
|
||||
bool* pbAvailable,
|
||||
char* pchName,
|
||||
const int cchNameBufferSize
|
||||
) {
|
||||
try {
|
||||
return smoke_api::steam_apps::GetDLCDataByIndex(
|
||||
__func__,
|
||||
steam_interface::get_app_id(),
|
||||
iDLC,
|
||||
pDlcID,
|
||||
pbAvailable,
|
||||
pchName,
|
||||
cchNameBufferSize,
|
||||
MODULE_CALL_CLOSURE(
|
||||
SteamAPI_ISteamApps_BGetDLCDataByIndex,
|
||||
self,
|
||||
iDLC,
|
||||
pDlcID,
|
||||
pbAvailable,
|
||||
pchName,
|
||||
cchNameBufferSize
|
||||
),
|
||||
[&](const AppId_t dlc_id) {
|
||||
return SteamAPI_ISteamApps_BIsDlcInstalled(self, dlc_id);
|
||||
}
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ISteamClient
|
||||
|
||||
DLL_EXPORT(void*) SteamAPI_ISteamClient_GetISteamGenericInterface(
|
||||
void* self,
|
||||
const HSteamUser hSteamUser,
|
||||
const HSteamPipe hSteamPipe,
|
||||
const char* pchVersion
|
||||
) {
|
||||
try {
|
||||
return steam_client::GetGenericInterface(
|
||||
__func__,
|
||||
pchVersion,
|
||||
MODULE_CALL_CLOSURE(
|
||||
SteamAPI_ISteamClient_GetISteamGenericInterface,
|
||||
self,
|
||||
hSteamUser,
|
||||
hSteamPipe,
|
||||
pchVersion
|
||||
)
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ISteamInventory
|
||||
|
||||
DLL_EXPORT(EResult) SteamAPI_ISteamInventory_GetResultStatus(
|
||||
void* self,
|
||||
const SteamInventoryResult_t resultHandle
|
||||
) {
|
||||
return smoke_api::steam_inventory::GetResultStatus(
|
||||
__func__,
|
||||
resultHandle,
|
||||
MODULE_CALL_CLOSURE(SteamAPI_ISteamInventory_GetResultStatus, self, resultHandle)
|
||||
);
|
||||
}
|
||||
|
||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemDefinitionIDs(
|
||||
void* self,
|
||||
SteamItemDef_t* pItemDefIDs,
|
||||
uint32_t* punItemDefIDsArraySize
|
||||
) {
|
||||
return smoke_api::steam_inventory::GetItemDefinitionIDs(
|
||||
__func__,
|
||||
pItemDefIDs,
|
||||
punItemDefIDsArraySize,
|
||||
MODULE_CALL_CLOSURE(
|
||||
SteamAPI_ISteamInventory_GetItemDefinitionIDs,
|
||||
self,
|
||||
pItemDefIDs,
|
||||
punItemDefIDsArraySize
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItems(
|
||||
void* self,
|
||||
const SteamInventoryResult_t resultHandle,
|
||||
SteamItemDetails_t* pOutItemsArray,
|
||||
uint32_t* punOutItemsArraySize
|
||||
) {
|
||||
return smoke_api::steam_inventory::GetResultItems(
|
||||
__func__,
|
||||
resultHandle,
|
||||
pOutItemsArray,
|
||||
punOutItemsArraySize,
|
||||
MODULE_CALL_CLOSURE(
|
||||
SteamAPI_ISteamInventory_GetResultItems,
|
||||
self,
|
||||
resultHandle,
|
||||
pOutItemsArray,
|
||||
punOutItemsArraySize
|
||||
),
|
||||
[&](SteamItemDef_t* pItemDefIDs, uint32_t* punItemDefIDsArraySize) {
|
||||
MODULE_CALL(
|
||||
SteamAPI_ISteamInventory_GetItemDefinitionIDs,
|
||||
self,
|
||||
pItemDefIDs,
|
||||
punItemDefIDsArraySize
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetResultItemProperty(
|
||||
void* self,
|
||||
const SteamInventoryResult_t resultHandle,
|
||||
const uint32_t unItemIndex,
|
||||
const char* pchPropertyName,
|
||||
char* pchValueBuffer,
|
||||
uint32_t* punValueBufferSizeOut
|
||||
) {
|
||||
return smoke_api::steam_inventory::GetResultItemProperty(
|
||||
__func__,
|
||||
resultHandle,
|
||||
unItemIndex,
|
||||
pchPropertyName,
|
||||
pchValueBuffer,
|
||||
punValueBufferSizeOut,
|
||||
MODULE_CALL_CLOSURE(
|
||||
SteamAPI_ISteamInventory_GetResultItemProperty,
|
||||
self,
|
||||
resultHandle,
|
||||
unItemIndex,
|
||||
pchPropertyName,
|
||||
pchValueBuffer,
|
||||
punValueBufferSizeOut
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_CheckResultSteamID(
|
||||
void* self,
|
||||
const SteamInventoryResult_t resultHandle,
|
||||
const CSteamID steamIDExpected
|
||||
) {
|
||||
return smoke_api::steam_inventory::CheckResultSteamID(
|
||||
__func__,
|
||||
resultHandle,
|
||||
steamIDExpected,
|
||||
MODULE_CALL_CLOSURE(
|
||||
SteamAPI_ISteamInventory_CheckResultSteamID,
|
||||
self,
|
||||
resultHandle,
|
||||
steamIDExpected
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetAllItems(
|
||||
void* self,
|
||||
SteamInventoryResult_t* pResultHandle
|
||||
) {
|
||||
return smoke_api::steam_inventory::GetAllItems(
|
||||
__func__,
|
||||
pResultHandle,
|
||||
MODULE_CALL_CLOSURE(SteamAPI_ISteamInventory_GetAllItems, self, pResultHandle)
|
||||
);
|
||||
}
|
||||
|
||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_GetItemsByID(
|
||||
void* self,
|
||||
SteamInventoryResult_t* pResultHandle,
|
||||
const SteamItemInstanceID_t* pInstanceIDs,
|
||||
const uint32_t unCountInstanceIDs
|
||||
) {
|
||||
return smoke_api::steam_inventory::GetItemsByID(
|
||||
__func__,
|
||||
pResultHandle,
|
||||
pInstanceIDs,
|
||||
unCountInstanceIDs,
|
||||
MODULE_CALL_CLOSURE(
|
||||
SteamAPI_ISteamInventory_GetItemsByID,
|
||||
self,
|
||||
pResultHandle,
|
||||
pInstanceIDs,
|
||||
unCountInstanceIDs
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
DLL_EXPORT(bool) SteamAPI_ISteamInventory_SerializeResult(
|
||||
void* self,
|
||||
const SteamInventoryResult_t resultHandle,
|
||||
void* pOutBuffer,
|
||||
uint32_t* punOutBufferSize
|
||||
) {
|
||||
return smoke_api::steam_inventory::SerializeResult(
|
||||
__func__,
|
||||
resultHandle,
|
||||
pOutBuffer,
|
||||
punOutBufferSize,
|
||||
MODULE_CALL_CLOSURE(
|
||||
SteamAPI_ISteamInventory_SerializeResult,
|
||||
self,
|
||||
resultHandle,
|
||||
pOutBuffer,
|
||||
punOutBufferSize
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// ISteamUser
|
||||
|
||||
DLL_EXPORT(EUserHasLicenseForAppResult) SteamAPI_ISteamUser_UserHasLicenseForApp(
|
||||
void* self,
|
||||
const CSteamID steamID,
|
||||
const AppId_t dlcID
|
||||
) {
|
||||
try {
|
||||
return smoke_api::steam_user::UserHasLicenseForApp(
|
||||
__func__,
|
||||
steam_interface::get_app_id(),
|
||||
dlcID,
|
||||
MODULE_CALL_CLOSURE(
|
||||
SteamAPI_ISteamUser_UserHasLicenseForApp,
|
||||
self,
|
||||
steamID,
|
||||
dlcID
|
||||
)
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return k_EUserHasLicenseResultDoesNotHaveLicense;
|
||||
}
|
||||
}
|
||||
22
src/steam_api/exports/steam_api_internal.cpp
Normal file
22
src/steam_api/exports/steam_api_internal.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "smoke_api.hpp"
|
||||
#include "smoke_api/types.hpp"
|
||||
#include "steam_api/steam_client.hpp"
|
||||
|
||||
DLL_EXPORT(void*) SteamInternal_FindOrCreateUserInterface(
|
||||
const HSteamUser hSteamUser,
|
||||
const char* version
|
||||
) {
|
||||
return steam_client::GetGenericInterface(
|
||||
__func__,
|
||||
version,
|
||||
MODULE_CALL_CLOSURE(SteamInternal_FindOrCreateUserInterface, hSteamUser, version)
|
||||
);
|
||||
}
|
||||
|
||||
DLL_EXPORT(void*) SteamInternal_CreateInterface(const char* version) {
|
||||
return steam_client::GetGenericInterface(
|
||||
__func__,
|
||||
version,
|
||||
MODULE_CALL_CLOSURE(SteamInternal_CreateInterface, version)
|
||||
);
|
||||
}
|
||||
92
src/steam_api/exports/steam_api_unversioned.cpp
Normal file
92
src/steam_api/exports/steam_api_unversioned.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
#include <regex>
|
||||
#include <map>
|
||||
|
||||
#include <koalabox/logger.hpp>
|
||||
#include <koalabox/util.hpp>
|
||||
#include <koalabox/win_util.hpp>
|
||||
|
||||
#include "smoke_api.hpp"
|
||||
#include "steam_api/steam_client.hpp"
|
||||
|
||||
namespace {
|
||||
namespace kb = koalabox;
|
||||
|
||||
/**
|
||||
* Searches the `.rdata` section of the original dll for the full interface version string
|
||||
* Results are cached for performance.
|
||||
*/
|
||||
std::string get_versioned_interface(
|
||||
const std::string& version_prefix,
|
||||
const std::string& fallback
|
||||
) {
|
||||
static std::map<std::string, std::string> version_map;
|
||||
|
||||
if(not version_map.contains(version_prefix)) {
|
||||
try {
|
||||
const std::string rdata = kb::win_util::get_pe_section_data_or_throw(
|
||||
smoke_api::steamapi_module,
|
||||
".rdata"
|
||||
);
|
||||
|
||||
const std::regex regex(version_prefix + "\\d{3}");
|
||||
if(std::smatch match; std::regex_search(rdata, match, regex)) {
|
||||
version_map[version_prefix] = match[0];
|
||||
return version_map[version_prefix];
|
||||
}
|
||||
|
||||
throw kb::util::exception("No match found for '{}'", version_prefix);
|
||||
} catch(const std::exception& ex) {
|
||||
LOG_ERROR(
|
||||
"Failed to get versioned interface: {}."
|
||||
"Falling back to version {}",
|
||||
ex.what(),
|
||||
fallback
|
||||
);
|
||||
|
||||
version_map[version_prefix] = version_prefix + fallback;
|
||||
}
|
||||
}
|
||||
|
||||
return version_map[version_prefix];
|
||||
}
|
||||
}
|
||||
|
||||
DLL_EXPORT(void*) SteamClient() {
|
||||
static auto version = get_versioned_interface(STEAM_CLIENT, "006");
|
||||
|
||||
return steam_client::GetGenericInterface(
|
||||
__func__,
|
||||
version,
|
||||
MODULE_CALL_CLOSURE(SteamClient)
|
||||
);
|
||||
}
|
||||
|
||||
DLL_EXPORT(void*) SteamApps() {
|
||||
static auto version = get_versioned_interface(STEAM_APPS, "002");
|
||||
|
||||
return steam_client::GetGenericInterface(
|
||||
__func__,
|
||||
version,
|
||||
MODULE_CALL_CLOSURE(SteamApps)
|
||||
);
|
||||
}
|
||||
|
||||
DLL_EXPORT(void*) SteamUser() {
|
||||
static auto version = get_versioned_interface(STEAM_USER, "012");
|
||||
|
||||
return steam_client::GetGenericInterface(
|
||||
__func__,
|
||||
version,
|
||||
MODULE_CALL_CLOSURE(SteamUser)
|
||||
);
|
||||
}
|
||||
|
||||
DLL_EXPORT(void*) SteamInventory() {
|
||||
static auto version = get_versioned_interface(STEAM_INVENTORY, "001");
|
||||
|
||||
return steam_client::GetGenericInterface(
|
||||
__func__,
|
||||
version,
|
||||
MODULE_CALL_CLOSURE(SteamInventory)
|
||||
);
|
||||
}
|
||||
19
src/steam_api/steam_client.cpp
Normal file
19
src/steam_api/steam_client.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include <koalabox/logger.hpp>
|
||||
|
||||
#include "steam_api/steam_interface.hpp"
|
||||
|
||||
namespace steam_client {
|
||||
void* GetGenericInterface(
|
||||
const std::string& function_name,
|
||||
const std::string& interface_version,
|
||||
const std::function<void*()>& original_function
|
||||
) {
|
||||
auto* const interface = original_function();
|
||||
|
||||
LOG_DEBUG("{} -> '{}' @ {}", function_name, interface_version, interface);
|
||||
|
||||
steam_interface::hook_virtuals(interface, interface_version);
|
||||
|
||||
return interface;
|
||||
}
|
||||
}
|
||||
11
src/steam_api/steam_client.hpp
Normal file
11
src/steam_api/steam_client.hpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace steam_client {
|
||||
void* GetGenericInterface(
|
||||
const std::string& function_name,
|
||||
const std::string& interface_version,
|
||||
const std::function<void*()>& original_function
|
||||
);
|
||||
}
|
||||
168
src/steam_api/steam_interface.cpp
Normal file
168
src/steam_api/steam_interface.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
#include <ranges>
|
||||
#include <set>
|
||||
|
||||
#include <battery/embed.hpp>
|
||||
|
||||
#include <koalabox/hook.hpp>
|
||||
#include <koalabox/logger.hpp>
|
||||
#include <koalabox/util.hpp>
|
||||
#include <koalabox/win_util.hpp>
|
||||
|
||||
#include "smoke_api.hpp"
|
||||
#include "virtuals/steam_api_virtuals.hpp"
|
||||
|
||||
namespace {
|
||||
struct interface_entry {
|
||||
// function_name must match the function identifier to be able to call original functions
|
||||
std::string function_name; // e.g. "ISteamClient_GetISteamApps"
|
||||
uintptr_t function_address; // e.g. ISteamClient_GetISteamApps
|
||||
};
|
||||
|
||||
struct interface_data {
|
||||
std::string fallback_version; // e.g. "SteamClient021"
|
||||
std::map<std::string, interface_entry> entry_map;
|
||||
// e.g. {ENTRY(ISteamClient, GetISteamApps), ...}
|
||||
};
|
||||
|
||||
std::map<std::string, interface_data> get_virtual_hook_map() {
|
||||
#define ENTRY(INTERFACE, FUNC) \
|
||||
{ \
|
||||
#FUNC, { \
|
||||
#INTERFACE "_" #FUNC, reinterpret_cast<uintptr_t>(INTERFACE##_##FUNC) \
|
||||
} \
|
||||
}
|
||||
|
||||
return {
|
||||
{
|
||||
STEAM_CLIENT,
|
||||
interface_data{
|
||||
.fallback_version = "SteamClient021",
|
||||
.entry_map = {
|
||||
ENTRY(ISteamClient, GetISteamApps),
|
||||
ENTRY(ISteamClient, GetISteamUser),
|
||||
ENTRY(ISteamClient, GetISteamGenericInterface),
|
||||
ENTRY(ISteamClient, GetISteamInventory),
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
STEAM_APPS,
|
||||
interface_data{
|
||||
.fallback_version = "STEAMAPPS_INTERFACE_VERSION008",
|
||||
.entry_map = {
|
||||
ENTRY(ISteamApps, BIsSubscribedApp),
|
||||
ENTRY(ISteamApps, BIsDlcInstalled),
|
||||
ENTRY(ISteamApps, GetDLCCount),
|
||||
ENTRY(ISteamApps, BGetDLCDataByIndex),
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
STEAM_USER,
|
||||
interface_data{
|
||||
.fallback_version = "SteamUser023",
|
||||
.entry_map = {
|
||||
ENTRY(ISteamUser, UserHasLicenseForApp),
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
STEAM_INVENTORY,
|
||||
interface_data{
|
||||
.fallback_version = "STEAMINVENTORY_INTERFACE_V003",
|
||||
.entry_map = {
|
||||
ENTRY(ISteamInventory, GetResultStatus),
|
||||
ENTRY(ISteamInventory, GetResultItems),
|
||||
ENTRY(ISteamInventory, CheckResultSteamID),
|
||||
ENTRY(ISteamInventory, GetAllItems),
|
||||
ENTRY(ISteamInventory, GetItemsByID),
|
||||
ENTRY(ISteamInventory, SerializeResult),
|
||||
ENTRY(ISteamInventory, GetItemDefinitionIDs),
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
nlohmann::json read_interface_lookup() {
|
||||
const auto lookup_str = b::embed<"res/interface_lookup.json">().str();
|
||||
return nlohmann::json::parse(lookup_str);
|
||||
}
|
||||
|
||||
const nlohmann::json& find_lookup(
|
||||
const std::string& interface_version,
|
||||
const std::string& fallback_version
|
||||
) {
|
||||
static const auto lookup = read_interface_lookup();
|
||||
|
||||
if(lookup.contains(interface_version)) {
|
||||
return lookup[interface_version];
|
||||
}
|
||||
|
||||
LOG_WARN(
|
||||
"Interface version '{}' not found in lookup map. Using fallback: '{}'",
|
||||
interface_version,
|
||||
fallback_version
|
||||
);
|
||||
|
||||
return lookup[fallback_version];
|
||||
}
|
||||
}
|
||||
|
||||
namespace steam_interface {
|
||||
namespace kb = koalabox;
|
||||
|
||||
AppId_t get_app_id_or_throw() {
|
||||
const auto app_id_str = kb::win_util::get_env_var("SteamAppId");
|
||||
return std::stoi(app_id_str);
|
||||
}
|
||||
|
||||
AppId_t get_app_id() {
|
||||
try {
|
||||
static const auto app_id = get_app_id_or_throw();
|
||||
return app_id;
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("Failed to get app id: {}", e.what());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void hook_virtuals(void* interface, const std::string& version_string) {
|
||||
if(interface == nullptr) {
|
||||
// Game has tried to use an interface before initializing steam api
|
||||
return;
|
||||
}
|
||||
|
||||
static std::set<void*> processed_interfaces;
|
||||
|
||||
if(processed_interfaces.contains(interface)) {
|
||||
LOG_DEBUG("Interface {} at {} has already been processed.", version_string, interface);
|
||||
return;
|
||||
}
|
||||
|
||||
static std::mutex section;
|
||||
const std::lock_guard guard(section);
|
||||
|
||||
static const auto virtual_hook_map = get_virtual_hook_map();
|
||||
for(const auto& [prefix, data] : virtual_hook_map) {
|
||||
if(version_string.starts_with(prefix)) {
|
||||
const auto& lookup = find_lookup(version_string, data.fallback_version);
|
||||
|
||||
for(const auto& [function, entry] : data.entry_map) {
|
||||
if(lookup.contains(function)) {
|
||||
kb::hook::swap_virtual_func(
|
||||
interface,
|
||||
entry.function_name,
|
||||
lookup[function],
|
||||
entry.function_address
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
processed_interfaces.insert(interface);
|
||||
}
|
||||
}
|
||||
10
src/steam_api/steam_interface.hpp
Normal file
10
src/steam_api/steam_interface.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "smoke_api/types.hpp"
|
||||
|
||||
namespace steam_interface {
|
||||
AppId_t get_app_id_or_throw();
|
||||
AppId_t get_app_id();
|
||||
|
||||
void hook_virtuals(void* interface, const std::string& version_string);
|
||||
}
|
||||
79
src/steam_api/virtuals/isteamapps.cpp
Normal file
79
src/steam_api/virtuals/isteamapps.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include <koalabox/logger.hpp>
|
||||
|
||||
#include "smoke_api.hpp"
|
||||
#include "smoke_api/interfaces/steam_apps.hpp"
|
||||
#include "steam_api/steam_interface.hpp"
|
||||
#include "steam_api/virtuals/steam_api_virtuals.hpp"
|
||||
|
||||
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(const AppId_t dlc_id)) {
|
||||
try {
|
||||
return smoke_api::steam_apps::IsDlcUnlocked(
|
||||
__func__,
|
||||
steam_interface::get_app_id(),
|
||||
dlc_id,
|
||||
HOOKED_CALL_CLOSURE(ISteamApps_BIsSubscribedApp, ARGS(dlc_id))
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(const AppId_t dlc_id)) {
|
||||
try {
|
||||
return smoke_api::steam_apps::IsDlcUnlocked(
|
||||
__func__,
|
||||
steam_interface::get_app_id(),
|
||||
dlc_id,
|
||||
HOOKED_CALL_CLOSURE(ISteamApps_BIsDlcInstalled, ARGS(dlc_id))
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
VIRTUAL(int) ISteamApps_GetDLCCount(PARAMS()) {
|
||||
try {
|
||||
return smoke_api::steam_apps::GetDLCCount(
|
||||
__func__,
|
||||
steam_interface::get_app_id(),
|
||||
HOOKED_CALL_CLOSURE(ISteamApps_GetDLCCount, ARGS())
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(
|
||||
PARAMS(
|
||||
const int iDLC,
|
||||
AppId_t* p_dlc_id,
|
||||
bool* pbAvailable,
|
||||
char* pchName,
|
||||
const int cchNameBufferSize
|
||||
)
|
||||
) {
|
||||
try {
|
||||
return smoke_api::steam_apps::GetDLCDataByIndex(
|
||||
__func__,
|
||||
steam_interface::get_app_id(),
|
||||
iDLC,
|
||||
p_dlc_id,
|
||||
pbAvailable,
|
||||
pchName,
|
||||
cchNameBufferSize,
|
||||
HOOKED_CALL_CLOSURE(
|
||||
ISteamApps_BGetDLCDataByIndex,
|
||||
ARGS(iDLC, p_dlc_id, pbAvailable, pchName, cchNameBufferSize)
|
||||
),
|
||||
[&](const AppId_t dlc_id) {
|
||||
return ISteamApps_BIsDlcInstalled(ARGS(dlc_id));
|
||||
}
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
87
src/steam_api/virtuals/isteamclient.cpp
Normal file
87
src/steam_api/virtuals/isteamclient.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#include <koalabox/logger.hpp>
|
||||
|
||||
#include "smoke_api.hpp"
|
||||
#include "steam_api/steam_client.hpp"
|
||||
#include "steam_api/virtuals/steam_api_virtuals.hpp"
|
||||
|
||||
VIRTUAL(void*) ISteamClient_GetISteamApps(
|
||||
PARAMS(
|
||||
const HSteamUser hSteamUser,
|
||||
const HSteamPipe hSteamPipe,
|
||||
const char* version
|
||||
)
|
||||
) {
|
||||
try {
|
||||
return steam_client::GetGenericInterface(
|
||||
__func__,
|
||||
version,
|
||||
HOOKED_CALL_CLOSURE(ISteamClient_GetISteamApps, ARGS(hSteamUser, hSteamPipe, version))
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
VIRTUAL(void*) ISteamClient_GetISteamUser(
|
||||
PARAMS(
|
||||
const HSteamUser hSteamUser,
|
||||
const HSteamPipe hSteamPipe,
|
||||
const char* version
|
||||
)
|
||||
) {
|
||||
try {
|
||||
return steam_client::GetGenericInterface(
|
||||
__func__,
|
||||
version,
|
||||
HOOKED_CALL_CLOSURE(ISteamClient_GetISteamUser, ARGS(hSteamUser, hSteamPipe, version))
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(
|
||||
PARAMS(
|
||||
HSteamUser hSteamUser,
|
||||
HSteamPipe hSteamPipe,
|
||||
const char* pchVersion
|
||||
)
|
||||
) {
|
||||
try {
|
||||
return steam_client::GetGenericInterface(
|
||||
__func__,
|
||||
pchVersion,
|
||||
HOOKED_CALL_CLOSURE(
|
||||
ISteamClient_GetISteamGenericInterface,
|
||||
ARGS(hSteamUser, hSteamPipe, pchVersion)
|
||||
)
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
VIRTUAL(void*) ISteamClient_GetISteamInventory(
|
||||
PARAMS(
|
||||
const HSteamUser hSteamUser,
|
||||
const HSteamPipe hSteamPipe,
|
||||
const char* pchVersion
|
||||
)
|
||||
) {
|
||||
try {
|
||||
return steam_client::GetGenericInterface(
|
||||
__func__,
|
||||
pchVersion,
|
||||
HOOKED_CALL_CLOSURE(
|
||||
ISteamClient_GetISteamInventory,
|
||||
ARGS(hSteamUser, hSteamPipe, pchVersion)
|
||||
)
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
144
src/steam_api/virtuals/isteaminventory.cpp
Normal file
144
src/steam_api/virtuals/isteaminventory.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
#include "smoke_api.hpp"
|
||||
#include "smoke_api/interfaces/steam_inventory.hpp"
|
||||
#include "steam_api/virtuals/steam_api_virtuals.hpp"
|
||||
|
||||
VIRTUAL(EResult) ISteamInventory_GetResultStatus(
|
||||
PARAMS(const SteamInventoryResult_t resultHandle)
|
||||
) {
|
||||
return smoke_api::steam_inventory::GetResultStatus(
|
||||
__func__,
|
||||
resultHandle,
|
||||
HOOKED_CALL_CLOSURE(ISteamInventory_GetResultStatus, ARGS(resultHandle))
|
||||
);
|
||||
}
|
||||
|
||||
VIRTUAL(bool) ISteamInventory_GetResultItems(
|
||||
PARAMS(
|
||||
const SteamInventoryResult_t resultHandle,
|
||||
SteamItemDetails_t* pOutItemsArray,
|
||||
uint32_t* punOutItemsArraySize
|
||||
)
|
||||
) {
|
||||
return smoke_api::steam_inventory::GetResultItems(
|
||||
__func__,
|
||||
resultHandle,
|
||||
pOutItemsArray,
|
||||
punOutItemsArraySize,
|
||||
HOOKED_CALL_CLOSURE(
|
||||
ISteamInventory_GetResultItems,
|
||||
ARGS(resultHandle, pOutItemsArray, punOutItemsArraySize)
|
||||
),
|
||||
[&](SteamItemDef_t* pItemDefIDs, uint32_t* punItemDefIDsArraySize) {
|
||||
HOOKED_CALL(
|
||||
ISteamInventory_GetItemDefinitionIDs,
|
||||
ARGS(pItemDefIDs, punItemDefIDsArraySize)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
VIRTUAL(bool) ISteamInventory_GetResultItemProperty(
|
||||
PARAMS(
|
||||
const SteamInventoryResult_t resultHandle,
|
||||
const uint32_t unItemIndex,
|
||||
const char* pchPropertyName,
|
||||
char* pchValueBuffer,
|
||||
uint32_t* punValueBufferSizeOut
|
||||
)
|
||||
) {
|
||||
return smoke_api::steam_inventory::GetResultItemProperty(
|
||||
__func__,
|
||||
resultHandle,
|
||||
unItemIndex,
|
||||
pchPropertyName,
|
||||
pchValueBuffer,
|
||||
punValueBufferSizeOut,
|
||||
HOOKED_CALL_CLOSURE(
|
||||
ISteamInventory_GetResultItemProperty,
|
||||
ARGS(
|
||||
resultHandle,
|
||||
unItemIndex,
|
||||
pchPropertyName,
|
||||
pchValueBuffer,
|
||||
punValueBufferSizeOut
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
VIRTUAL(bool) ISteamInventory_GetAllItems(PARAMS(SteamInventoryResult_t* pResultHandle)) {
|
||||
return smoke_api::steam_inventory::GetAllItems(
|
||||
__func__,
|
||||
pResultHandle,
|
||||
HOOKED_CALL_CLOSURE(ISteamInventory_GetAllItems, ARGS(pResultHandle))
|
||||
);
|
||||
}
|
||||
|
||||
VIRTUAL(bool) ISteamInventory_GetItemsByID(
|
||||
PARAMS(
|
||||
SteamInventoryResult_t* pResultHandle,
|
||||
const SteamItemInstanceID_t* pInstanceIDs,
|
||||
const uint32_t unCountInstanceIDs
|
||||
)
|
||||
) {
|
||||
return smoke_api::steam_inventory::GetItemsByID(
|
||||
__func__,
|
||||
pResultHandle,
|
||||
pInstanceIDs,
|
||||
unCountInstanceIDs,
|
||||
HOOKED_CALL_CLOSURE(
|
||||
ISteamInventory_GetItemsByID,
|
||||
ARGS(pResultHandle, pInstanceIDs, unCountInstanceIDs)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
VIRTUAL(bool) ISteamInventory_SerializeResult(
|
||||
PARAMS(
|
||||
const SteamInventoryResult_t resultHandle,
|
||||
void* pOutBuffer,
|
||||
uint32_t* punOutBufferSize
|
||||
)
|
||||
) {
|
||||
return smoke_api::steam_inventory::SerializeResult(
|
||||
__func__,
|
||||
resultHandle,
|
||||
pOutBuffer,
|
||||
punOutBufferSize,
|
||||
HOOKED_CALL_CLOSURE(
|
||||
ISteamInventory_SerializeResult,
|
||||
ARGS(resultHandle, pOutBuffer, punOutBufferSize)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(
|
||||
PARAMS(
|
||||
SteamItemDef_t*pItemDefIDs,
|
||||
uint32_t* punItemDefIDsArraySize
|
||||
)
|
||||
) {
|
||||
return smoke_api::steam_inventory::GetItemDefinitionIDs(
|
||||
__func__,
|
||||
pItemDefIDs,
|
||||
punItemDefIDsArraySize,
|
||||
HOOKED_CALL_CLOSURE(
|
||||
ISteamInventory_GetItemDefinitionIDs,
|
||||
ARGS(pItemDefIDs, punItemDefIDsArraySize)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
VIRTUAL(bool) ISteamInventory_CheckResultSteamID(
|
||||
PARAMS(SteamInventoryResult_t resultHandle, CSteamID steamIDExpected)
|
||||
) {
|
||||
return smoke_api::steam_inventory::CheckResultSteamID(
|
||||
__func__,
|
||||
resultHandle,
|
||||
steamIDExpected,
|
||||
HOOKED_CALL_CLOSURE(
|
||||
ISteamInventory_CheckResultSteamID,
|
||||
ARGS(resultHandle, steamIDExpected)
|
||||
)
|
||||
);
|
||||
}
|
||||
23
src/steam_api/virtuals/isteamuser.cpp
Normal file
23
src/steam_api/virtuals/isteamuser.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <koalabox/logger.hpp>
|
||||
|
||||
#include "smoke_api.hpp"
|
||||
#include "smoke_api/interfaces/steam_user.hpp"
|
||||
#include "steam_api/steam_interface.hpp"
|
||||
#include "steam_api/virtuals/steam_api_virtuals.hpp"
|
||||
|
||||
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(
|
||||
PARAMS(const CSteamID steamID, const AppId_t dlc_id)
|
||||
) {
|
||||
try {
|
||||
static const auto app_id = steam_interface::get_app_id();
|
||||
return smoke_api::steam_user::UserHasLicenseForApp(
|
||||
__func__,
|
||||
app_id,
|
||||
dlc_id,
|
||||
HOOKED_CALL_CLOSURE(ISteamUser_UserHasLicenseForApp, ARGS(steamID, dlc_id))
|
||||
);
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("{} -> Error: {}", __func__, e.what());
|
||||
return k_EUserHasLicenseResultDoesNotHaveLicense;
|
||||
}
|
||||
}
|
||||
70
src/steam_api/virtuals/steam_api_virtuals.hpp
Normal file
70
src/steam_api/virtuals/steam_api_virtuals.hpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include "smoke_api/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(...) const void *ECX, const void *EDX, __VA_ARGS__
|
||||
#define ARGS(...) ECX, EDX, __VA_ARGS__
|
||||
#define THIS ECX
|
||||
#endif
|
||||
|
||||
#define VIRTUAL(TYPE) __declspec(noinline) TYPE __fastcall // NOLINT(*-macro-parentheses)
|
||||
|
||||
// ISteamApps
|
||||
VIRTUAL(bool) ISteamApps_BIsSubscribedApp(PARAMS(AppId_t));
|
||||
VIRTUAL(bool) ISteamApps_BIsDlcInstalled(PARAMS(AppId_t));
|
||||
VIRTUAL(int) ISteamApps_GetDLCCount(PARAMS());
|
||||
VIRTUAL(bool) ISteamApps_BGetDLCDataByIndex(PARAMS(int, AppId_t*, bool*, char*, int));
|
||||
|
||||
// ISteamClient
|
||||
VIRTUAL(void*) ISteamClient_GetISteamApps(PARAMS(HSteamUser, HSteamPipe, const char*));
|
||||
VIRTUAL(void*) ISteamClient_GetISteamUser(PARAMS(HSteamUser, HSteamPipe, const char*));
|
||||
VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(PARAMS(HSteamUser, HSteamPipe, const char*));
|
||||
VIRTUAL(void*) ISteamClient_GetISteamInventory(PARAMS(HSteamUser, HSteamPipe, const char*));
|
||||
|
||||
// ISteamInventory
|
||||
VIRTUAL(EResult) ISteamInventory_GetResultStatus(PARAMS(SteamInventoryResult_t));
|
||||
VIRTUAL(bool) ISteamInventory_GetResultItems(
|
||||
PARAMS(SteamInventoryResult_t, SteamItemDetails_t*, uint32_t*) // @formatter:off
|
||||
); // @formatter:on
|
||||
|
||||
VIRTUAL(bool) ISteamInventory_GetResultItemProperty(
|
||||
PARAMS(SteamInventoryResult_t, uint32_t, const char*, char*, uint32_t*) // @formatter:off
|
||||
); // @formatter:on
|
||||
VIRTUAL(bool) ISteamInventory_GetAllItems(PARAMS(SteamInventoryResult_t*));
|
||||
VIRTUAL(bool) ISteamInventory_GetItemsByID(
|
||||
PARAMS(SteamInventoryResult_t*, const SteamItemInstanceID_t*, uint32_t)
|
||||
);
|
||||
VIRTUAL(bool) ISteamInventory_SerializeResult(PARAMS(SteamInventoryResult_t, void*, uint32_t*));
|
||||
VIRTUAL(bool) ISteamInventory_GetItemDefinitionIDs(PARAMS(SteamItemDef_t*, uint32_t*));
|
||||
VIRTUAL(bool) ISteamInventory_CheckResultSteamID(PARAMS(SteamInventoryResult_t, CSteamID));
|
||||
|
||||
// ISteamUser
|
||||
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t));
|
||||
Reference in New Issue
Block a user