mirror of
https://github.com/acidicoala/SmokeAPI.git
synced 2026-01-26 06:22:51 -05:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e72bc29635 | ||
|
|
593c0cb4bc | ||
|
|
d3fd17779c | ||
|
|
f5b8c0c89f | ||
|
|
8decbafb53 | ||
|
|
7ab9895b58 | ||
|
|
c75bbcf636 | ||
|
|
c409ff3202 | ||
|
|
8a6c8d0fba | ||
|
|
7781636335 | ||
|
|
e0ba771d52 | ||
|
|
b0a4ea0f24 | ||
|
|
c5f8a37702 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -4,7 +4,7 @@ on: push
|
||||
jobs:
|
||||
ci:
|
||||
name: CI
|
||||
uses: acidicoala/KoalaBox/.github/workflows/build-and-package.yml@1bdfeefa9933092a747c46679b3d872470ef4998
|
||||
uses: acidicoala/KoalaBox/.github/workflows/build-and-package.yml@a2838977f0b6a2933814e301e0a69ad53fdc6bce
|
||||
permissions:
|
||||
contents: write
|
||||
with:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
|
||||
project(SmokeAPI VERSION 3.1.3)
|
||||
project(SmokeAPI VERSION 3.1.5)
|
||||
|
||||
include(KoalaBox/cmake/KoalaBox.cmake)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
@@ -39,7 +39,6 @@ set(SMOKE_API_SOURCES
|
||||
src/steam_api/virtuals/isteamhttp.cpp
|
||||
src/steam_api/virtuals/isteaminventory.cpp
|
||||
src/steam_api/virtuals/isteamuser.cpp
|
||||
src/steam_api/virtuals/isteamutils.cpp
|
||||
src/steam_api/virtuals/steam_api_virtuals.hpp
|
||||
src/steam_api/steam_client.hpp
|
||||
src/steam_api/steam_client.cpp
|
||||
@@ -110,19 +109,35 @@ if(WIN32)
|
||||
INPUT_SOURCES_DIR ""
|
||||
DLL_FILES_GLOB "${CMAKE_CURRENT_SOURCE_DIR}/res/steamworks/*/binaries/${STEAM_API_MODULE}.dll"
|
||||
)
|
||||
configure_linker_exports(
|
||||
TARGET SmokeAPI
|
||||
HEADER_NAME "linker_exports_for_version.h"
|
||||
FORWARDED_DLL "C:/Windows/System32/version.dll"
|
||||
INPUT_SOURCES_DIR ""
|
||||
DLL_FILES_GLOB "C:/Windows/System32/version.dll"
|
||||
|
||||
set(HEADER_CONTENT "#pragma once\n\n")
|
||||
|
||||
foreach(WIN_DLL version winhttp winmm)
|
||||
set(HEADER_NAME "linker_exports_for_${WIN_DLL}.h")
|
||||
configure_linker_exports(
|
||||
TARGET SmokeAPI
|
||||
HEADER_NAME "${HEADER_NAME}"
|
||||
FORWARDED_DLL "C:/Windows/System32/${WIN_DLL}.dll"
|
||||
INPUT_SOURCES_DIR ""
|
||||
DLL_FILES_GLOB "C:/Windows/System32/${WIN_DLL}.dll"
|
||||
)
|
||||
|
||||
set(HEADER_CONTENT "${HEADER_CONTENT}#include <${HEADER_NAME}>\n")
|
||||
endforeach()
|
||||
|
||||
file(GENERATE
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/generated/linker_exports_for_windows_dlls.h"
|
||||
CONTENT "${HEADER_CONTENT}"
|
||||
)
|
||||
|
||||
# Ignore linker warnings regarding COM-related private exports
|
||||
set_target_properties(SmokeAPI PROPERTIES LINK_FLAGS "/ignore:4104")
|
||||
else()
|
||||
# configure_linker_exports(
|
||||
# TARGET SmokeAPI
|
||||
# HEADER_NAME "libsteam_api_exports.cpp"
|
||||
# FORWARDED_DLL "${STEAM_API_MODULE}_o.so"
|
||||
# DLL_FILES_GLOB "${CMAKE_CURRENT_SOURCE_DIR}/res/steamworks/*/binaries/${LINUX_DIR}/${STEAM_API_MODULE}.so"
|
||||
# INPUT_SOURCES_DIR ""
|
||||
# )
|
||||
# configure_linker_exports(
|
||||
# TARGET SmokeAPI
|
||||
# HEADER_NAME "libsteam_api_exports.cpp"
|
||||
# FORWARDED_DLL "${STEAM_API_MODULE}_o.so"
|
||||
# DLL_FILES_GLOB "${CMAKE_CURRENT_SOURCE_DIR}/res/steamworks/*/binaries/${LINUX_DIR}/${STEAM_API_MODULE}.so"
|
||||
# INPUT_SOURCES_DIR ""
|
||||
# )
|
||||
endif()
|
||||
|
||||
2
KoalaBox
2
KoalaBox
Submodule KoalaBox updated: 44be3bf94f...c8d3ce1a73
28
README.md
28
README.md
@@ -33,7 +33,8 @@ Therefore, **you have to first research the game's topic**, to see if it support
|
||||
|
||||
Additionally, there are several points to bear in mind when it comes to unlocking DLCs with SmokeAPI:
|
||||
|
||||
* SmokeAPI most definitely will not work with games that use 3rd party DRM, such as games from Ubisoft, Rockstar, etc.* SmokeAPI is unlikely to unlock anything in Free-To-Play games since they typically store all player data on the corresponding game server and hence all the checks are server-side.
|
||||
* SmokeAPI most definitely will not work with games that use 3rd party DRM, such as games from Ubisoft, Rockstar, etc.* SmokeAPI most likely will not work with games that use Denuvo SecureDLC.
|
||||
* SmokeAPI is unlikely to unlock anything in Free-To-Play games since they typically store all player data on the corresponding game server and hence all the checks are server-side.
|
||||
* SmokeAPI will not work with games that employ additional ownership protection or if the game is using alternative DLC verification mechanism.
|
||||
* SmokeAPI is unlikely to work with games that use an anti-cheat, since they typically detect any DLL/EXE that has been tampered with. Sometimes it is possible to disable an anti-cheat, but that typically entails the loss of online capabilities. Search in the respective game topic for more information about how to disable anti-cheat.
|
||||
* Some games include DLC files in their base game, regardless of whether you own the DLC or not. However, some games download additional DLC files only after a user has bought the corresponding DLC. In this case, not only will you need to install SmokeAPI, but you also have to get the additional DLC files from somewhere else and put them into the game folder. Up-to-date DLC files often can be found in corresponding game topics.
|
||||
@@ -82,25 +83,25 @@ If that didn't work, refer to the _Troubleshooting_ section below.
|
||||
### 🪝 Hook mode
|
||||
|
||||
- Download the [latest SmokeAPI release zip].
|
||||
- From this downloaded zip extract `SmokeAPI32.dll` or `SmokeAPI64.dll`, depending on a game's bitness.
|
||||
- Rename the unzipped DLL to `version.dll`.
|
||||
- Place this `version.dll` next to the game's `.exe` file.
|
||||
- From this downloaded zip extract `smoke_api32.dll` or `smoke_api64.dll`, depending on a game's bitness.
|
||||
- Rename the unzipped DLL to `version.dll` or `winhttp.dll` or `winmm.dll`.
|
||||
- Place this `version.dll` or `winhttp.dll` or `winmm.dll` next to the game's `.exe` file.
|
||||
|
||||
#### 🪝 Hook mode with Koaloader
|
||||
|
||||
If a game doesn't load
|
||||
`version.dll`, you can use an alternative injector to load SmokeAPI into the game process.
|
||||
If a game doesn't load `version.dll` or `winhttp.dll` or `winmm.dll`, you can use an alternative injector to load
|
||||
SmokeAPI into the game process.
|
||||
One such injector is [Koaloader], which supports different DLLs that a typical game might load.
|
||||
For example, assuming that the game loads `winmm.dll`:
|
||||
For example, assuming that the game loads `d3d11.dll`:
|
||||
|
||||
- Install Koaloader:
|
||||
- Download the [latest Koaloader release zip].
|
||||
- From this downloaded zip extract `winmm.dll` from `winmm-32` or `winmm-64`, depending on a game's bitness.
|
||||
- Place `winmm.dll` next to the game's `.exe` file.
|
||||
- From this downloaded zip extract `d3d11.dll` from `d3d11-32` or `d3d11-64`, depending on a game's bitness.
|
||||
- Place `d3d11.dll` next to the game's `.exe` file.
|
||||
- Install SmokeAPI
|
||||
- Download the [latest SmokeAPI release zip].
|
||||
- From this downloaded zip extract `SmokeAPI32.dll` or `SmokeAPI64.dll`, depending on a game's bitness.
|
||||
- Place `SmokeAPI32.dll` or `SmokeAPI64.dll` next to the game's `.exe` file.
|
||||
- From this downloaded zip extract `smoke_api32.dll` or `smoke_api64.dll`, depending on a game's bitness.
|
||||
- Place `smoke_api32.dll` or `smoke_api64.dll` next to the game's `.exe` file.
|
||||
|
||||
#### 🪝 Hook mode with Special K
|
||||
|
||||
@@ -111,7 +112,7 @@ In such cases, it might be worth trying [Special K], which can inject SmokeAPI a
|
||||
|
||||
- Find a `steam_api.dll` or `steam_api64.dll` file in game directory, and rename it to `steam_api_o.dll` or `steam_api64_o.dll`.
|
||||
- Download the [latest SmokeAPI release zip].
|
||||
- From this downloaded zip extract `SmokeAPI32.dll` or `SmokeAPI64.dll`, depending on a game's bitness.
|
||||
- From this downloaded zip extract `smoke_api32.dll` or `smoke_api64.dll`, depending on a game's bitness.
|
||||
- Rename this extracted DLL to `steam_api.dll` or `steam_api64.dll`, depending on a game's bitness.
|
||||
- Place this renamed unlocker DLL next to the `steam_api_o.dll` or `steam_api64_o.dll` file.
|
||||
|
||||
@@ -171,7 +172,7 @@ Below you can find an example config where nearly every option has been customiz
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.2/res/SmokeAPI.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.5/res/SmokeAPI.schema.json",
|
||||
"$version": 4,
|
||||
"logging": true,
|
||||
"log_steam_http": true,
|
||||
@@ -309,6 +310,7 @@ This project makes use of the following open source projects:
|
||||
- [pantor/inja](https://github.com/pantor/inja)
|
||||
- [bshoshany/thread-pool](https://github.com/bshoshany/thread-pool)
|
||||
- [batterycenter/embed](https://github.com/batterycenter/embed)
|
||||
- [serge1/ELFIO](https://github.com/serge1/ELFIO)
|
||||
|
||||
## 📄 License
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.2/res/SmokeAPI.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.5/res/SmokeAPI.schema.json",
|
||||
"$version": 4,
|
||||
"logging": true,
|
||||
"log_steam_http": false,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.2/res/SmokeAPI.schema.json",
|
||||
"$id": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.5/res/SmokeAPI.schema.json",
|
||||
"title": "SmokeAPI configuration",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -120,7 +120,7 @@
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.2/res/SmokeAPI.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v3.1.5/res/SmokeAPI.schema.json",
|
||||
"$version": 4,
|
||||
"logging": true,
|
||||
"log_steam_http": true,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#define STEAM_API_MODULE "${STEAM_API_MODULE}"
|
||||
#define STEAMCLIENT_DLL "${STEAMCLIENT_DLL}"
|
||||
#define STEAMCLIENT_DLL "${STEAMCLIENT_DLL}"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// ReSharper disable CppUnusedIncludeDirective
|
||||
#include <koalabox/win.hpp>
|
||||
|
||||
#include "smoke_api/smoke_api.hpp"
|
||||
|
||||
// This header will be populated at build time
|
||||
// These headers will be populated at build time
|
||||
#include "linker_exports_for_steam_api.h"
|
||||
#include "linker_exports_for_version.h"
|
||||
#include "linker_exports_for_windows_dlls.h"
|
||||
|
||||
DLL_MAIN(void* handle, const uint32_t reason, void*) {
|
||||
if(reason == DLL_PROCESS_ATTACH) {
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
|
||||
#include "build_config.h"
|
||||
|
||||
#ifdef KB_WIN
|
||||
#include "koalabox/win.hpp"
|
||||
#endif
|
||||
|
||||
// Hooking steam_api has shown itself to be less desirable than steamclient
|
||||
// for the reasons outlined below:
|
||||
//
|
||||
@@ -42,6 +46,7 @@ namespace {
|
||||
namespace kb = koalabox;
|
||||
|
||||
void* original_steamapi_handle = nullptr;
|
||||
bool is_hook_mode;
|
||||
|
||||
std::set<std::string> find_steamclient_versions(void* steamapi_handle) {
|
||||
if(!steamapi_handle) {
|
||||
@@ -80,13 +85,19 @@ namespace {
|
||||
#endif
|
||||
}
|
||||
|
||||
// ReSharper disable once CppDFAConstantFunctionResult
|
||||
bool on_steamclient_loaded(void* steamclient_handle) {
|
||||
static const auto CreateInterface$ = KB_MOD_GET_FUNC(steamclient_handle, CreateInterface);
|
||||
KB_HOOK_DETOUR_MODULE(CreateInterface, steamclient_handle);
|
||||
|
||||
auto* steamapi_handle = original_steamapi_handle
|
||||
? original_steamapi_handle
|
||||
: kb::lib::get_library_handle(STEAM_API_MODULE);
|
||||
if(steamapi_handle) {
|
||||
if(!is_hook_mode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for late hooking
|
||||
|
||||
static const auto CreateInterface$ = KB_LIB_GET_FUNC(steamclient_handle, CreateInterface);
|
||||
|
||||
if(auto* steamapi_handle = kb::lib::get_library_handle(STEAM_API_MODULE)) {
|
||||
// SteamAPI might have been initialized.
|
||||
// Hence, we need to query SteamClient interfaces and hook them if needed.
|
||||
const auto steamclient_versions = find_steamclient_versions(steamapi_handle);
|
||||
@@ -101,15 +112,57 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
KB_HOOK_DETOUR_MODULE(CreateInterface, steamclient_handle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void init_lib_monitor() {
|
||||
kb::lib_monitor::init_listener(
|
||||
{{STEAMCLIENT_DLL, on_steamclient_loaded}}
|
||||
);
|
||||
kb::lib_monitor::init_listener({{STEAMCLIENT_DLL, on_steamclient_loaded}});
|
||||
}
|
||||
|
||||
std::optional<AppId_t> get_app_id_from_env() noexcept {
|
||||
if(const auto app_id_str = kb::util::get_env("SteamAppId")) {
|
||||
try {
|
||||
const auto app_id = std::stoi(*app_id_str);
|
||||
|
||||
LOG_DEBUG("Found AppID from environment: {}", app_id);
|
||||
return app_id;
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("Failed to parse AppID '{}' from environment: {}", *app_id_str, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<AppId_t> get_app_id_from_steam_client() noexcept {
|
||||
try {
|
||||
const DECLARE_ARGS();
|
||||
|
||||
const auto& version_map = steam_interfaces::get_interface_name_to_version_map();
|
||||
THIS = CreateInterface(version_map.at("ISteamClient").c_str(), nullptr);
|
||||
if(THIS) {
|
||||
if(const auto get_steam_utils = SMK_FIND_INTERFACE_FUNC(THIS, ISteamClient, GetISteamUtils)) {
|
||||
constexpr auto steam_pipe = 1;
|
||||
const auto& utils_version = version_map.at("ISteamUtils");
|
||||
THIS = get_steam_utils(ARGS(steam_pipe, utils_version.c_str()));
|
||||
if(THIS) {
|
||||
if(const auto get_app_id = SMK_FIND_INTERFACE_FUNC(THIS, ISteamUtils, GetAppID)) {
|
||||
if(const auto app_id = get_app_id(ARGS())) {
|
||||
LOG_DEBUG("Found AppID from ISteamUtils: {}", app_id);
|
||||
return app_id;
|
||||
}
|
||||
LOG_ERROR("ISteamUtils::GetAppID returned 0");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR("Failed to create interface '{}'", version_map.at("ISteamClient"))
|
||||
}
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("Failed to get app id. Unhandled exception: {}", e.what());
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,14 +179,18 @@ namespace smoke_api {
|
||||
kb::logger::init_null_logger();
|
||||
}
|
||||
|
||||
LOG_INFO("{} v{} | Built at '{}'", PROJECT_NAME, PROJECT_VERSION, __TIMESTAMP__);
|
||||
LOG_INFO("{} v{}{} | Built at '{}'", PROJECT_NAME, PROJECT_VERSION, VERSION_SUFFIX, __TIMESTAMP__);
|
||||
LOG_DEBUG("Parsed config:\n{}", nlohmann::ordered_json(config::instance).dump(2));
|
||||
|
||||
const auto exe_path = kb::lib::get_fs_path(nullptr);
|
||||
const auto exe_name = kb::path::to_str(exe_path.filename());
|
||||
|
||||
LOG_DEBUG("Process name: '{}' [{}-bit]", exe_name, kb::util::BITNESS);
|
||||
LOG_DEBUG("Self handle: {}", module_handle);
|
||||
LOG_DEBUG("Self name: '{}'", kb::path::to_str(kb::lib::get_fs_path(module_handle).filename()));
|
||||
|
||||
#ifdef KB_WIN
|
||||
kb::win::check_self_duplicates();
|
||||
#endif
|
||||
|
||||
// We need to hook functions in either mode
|
||||
kb::hook::init(true);
|
||||
@@ -141,17 +198,16 @@ namespace smoke_api {
|
||||
if(kb::hook::is_hook_mode(module_handle, STEAM_API_MODULE)) {
|
||||
LOG_INFO("Detected hook mode");
|
||||
|
||||
is_hook_mode = true;
|
||||
init_lib_monitor();
|
||||
} else {
|
||||
LOG_INFO("Detected proxy mode");
|
||||
|
||||
is_hook_mode = true;
|
||||
init_lib_monitor();
|
||||
|
||||
const auto self_path = kb::paths::get_self_dir();
|
||||
original_steamapi_handle = kb::lib::load_original_library(
|
||||
self_path,
|
||||
STEAM_API_MODULE
|
||||
);
|
||||
original_steamapi_handle = kb::lib::load_original_library(self_path, STEAM_API_MODULE);
|
||||
}
|
||||
|
||||
LOG_INFO("Initialization complete");
|
||||
@@ -182,50 +238,28 @@ namespace smoke_api {
|
||||
}
|
||||
|
||||
AppId_t get_app_id() {
|
||||
static AppId_t app_id = 0;
|
||||
if(app_id) {
|
||||
return app_id; // cached value
|
||||
static AppId_t cached_app_id = 0;
|
||||
if(cached_app_id) {
|
||||
return cached_app_id;
|
||||
}
|
||||
|
||||
try {
|
||||
if(const auto app_id_str = kb::util::get_env("SteamAppId")) {
|
||||
app_id = std::stoi(*app_id_str);
|
||||
LOG_DEBUG("Found AppID from environment: {}", app_id);
|
||||
LOG_DEBUG("No cached App ID found. Searching in environment variables.");
|
||||
|
||||
return app_id;
|
||||
}
|
||||
} catch(std::exception&) {
|
||||
LOG_WARN("No SteamAppId in environment. Falling back to ISteamUtils::GetAppID.");
|
||||
if(const auto opt_app_id = get_app_id_from_env()) {
|
||||
return cached_app_id = *opt_app_id;
|
||||
}
|
||||
|
||||
// TODO: Then try to read steam_appid.txt here. SteamAppId env var is not available when it's present.
|
||||
LOG_WARN("Failed to find App ID in environment variables. Falling back to ISteamUtils::GetAppID.");
|
||||
|
||||
try {
|
||||
DECLARE_ARGS();
|
||||
// IDEA: Try to read steam_appid.txt here. SteamAppId env var is not available when it's present.
|
||||
// But what if the ID specified in steam_appid.txt is invalid?
|
||||
|
||||
THIS = CreateInterface("SteamClient007", nullptr);
|
||||
if(!THIS) {
|
||||
LOG_ERROR("Failed to create SteamClient interface");
|
||||
return 0;
|
||||
}
|
||||
|
||||
THIS = ISteamClient_GetISteamGenericInterface(ARGS(1, 1, "SteamUtils002"));
|
||||
if(!THIS) {
|
||||
LOG_ERROR("Failed to get SteamUtils interface");
|
||||
return 0;
|
||||
}
|
||||
|
||||
app_id = ISteamUtils_GetAppID(ARGS());
|
||||
if(!app_id) {
|
||||
LOG_ERROR("ISteamUtils::GetAppID returned 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Found AppID from ISteamUtils: {}", app_id);
|
||||
return app_id;
|
||||
} catch(const std::exception& e) {
|
||||
LOG_ERROR("Failed to get app id: {}", e.what());
|
||||
return 0;
|
||||
if(const auto opt_app_id = get_app_id_from_steam_client()) {
|
||||
return cached_app_id = *opt_app_id;
|
||||
}
|
||||
|
||||
LOG_ERROR("Failed to find App ID");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ constexpr auto STEAM_APPS = "STEAMAPPS_INTERFACE_VERSION";
|
||||
constexpr auto STEAM_CLIENT = "SteamClient";
|
||||
constexpr auto STEAM_HTTP = "STEAMHTTP_INTERFACE_VERSION";
|
||||
constexpr auto STEAM_USER = "SteamUser";
|
||||
constexpr auto STEAM_UTILS = "SteamUtils";
|
||||
constexpr auto STEAM_INVENTORY = "STEAMINVENTORY_INTERFACE_V";
|
||||
constexpr auto STEAM_GAME_SERVER = "SteamGameServer";
|
||||
|
||||
|
||||
@@ -104,15 +104,8 @@ namespace {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
STEAM_UTILS,
|
||||
interface_data_t{
|
||||
.fallback_version = "SteamUtils009",
|
||||
.entry_map = {
|
||||
ENTRY(ISteamUtils, GetAppID),
|
||||
}
|
||||
}
|
||||
},
|
||||
// Hooking SteamUtils for GetAppID should be avoided, since it leads to crashes in TW:WH3.
|
||||
// No idea why...
|
||||
};
|
||||
}
|
||||
|
||||
@@ -218,7 +211,7 @@ namespace steam_interfaces {
|
||||
// Map virtual hook map to a set of keys
|
||||
const auto prefixes = std::views::keys(virtual_hook_map) | std::ranges::to<std::set>();
|
||||
|
||||
const auto CreateInterface$ = KB_MOD_GET_FUNC(steamclient_handle, CreateInterface);
|
||||
const auto CreateInterface$ = KB_LIB_GET_FUNC(steamclient_handle, CreateInterface);
|
||||
|
||||
DECLARE_ARGS();
|
||||
THIS = CreateInterface$(steam_client_interface_version.c_str(), nullptr);
|
||||
@@ -257,4 +250,46 @@ namespace steam_interfaces {
|
||||
LOG_ERROR("{} -> Unhandled exception: {}", __func__, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void* find_function(
|
||||
const void* instance_ptr,
|
||||
const std::string& interface_name,
|
||||
const std::string& function_name
|
||||
) {
|
||||
if(!get_interface_name_to_version_map().contains(interface_name)) {
|
||||
LOG_ERROR("Unsupported interface name: '{}'", interface_name);
|
||||
return nullptr;
|
||||
}
|
||||
const auto& interface_version = get_interface_name_to_version_map().at(interface_name);
|
||||
|
||||
static const auto lookup = read_interface_lookup();
|
||||
|
||||
if(!lookup.contains(interface_version)) {
|
||||
LOG_ERROR("Interface '{}' not found in lookup map", interface_version);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto interface_lookup = lookup.at(interface_version);
|
||||
|
||||
if(!interface_lookup.contains(function_name)) {
|
||||
LOG_ERROR("Function '{}' not found in the map of '{}'", function_name, interface_version);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto ordinal = interface_lookup.at(function_name);
|
||||
|
||||
const auto virtual_class = static_cast<const kb::hook::virtual_class_t*>(instance_ptr);
|
||||
return virtual_class->vtable[ordinal];
|
||||
}
|
||||
|
||||
const std::map<std::string, std::string>& get_interface_name_to_version_map() {
|
||||
// Choose minimal supported versions for maximum compatibility
|
||||
// Is it better to get the interface version found in steam_api library?
|
||||
static const std::map<std::string, std::string> map = {
|
||||
{"ISteamClient", "SteamClient007"},
|
||||
{"ISteamUtils", "SteamUtils002"},
|
||||
};
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#define SMK_FIND_INTERFACE_FUNC(INTERFACE_PTR, INTERFACE_NAME, FUNCTION_NAME) \
|
||||
reinterpret_cast<decltype(&INTERFACE_NAME##_##FUNCTION_NAME)>( \
|
||||
steam_interfaces::find_function(INTERFACE_PTR, #INTERFACE_NAME, #FUNCTION_NAME) \
|
||||
)
|
||||
|
||||
namespace steam_interfaces {
|
||||
void hook_virtuals(const void* interface_ptr, const std::string& version_string);
|
||||
|
||||
@@ -15,4 +21,12 @@ namespace steam_interfaces {
|
||||
void* steamclient_handle,
|
||||
const std::string& steam_client_interface_version
|
||||
) noexcept;
|
||||
|
||||
void* find_function(
|
||||
const void* instance_ptr,
|
||||
const std::string& interface_name,
|
||||
const std::string& function_name
|
||||
);
|
||||
|
||||
const std::map<std::string, std::string>& get_interface_name_to_version_map();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ VIRTUAL(bool) ISteamInventory_GetResultItems(
|
||||
SteamItemDetails_t* pOutItemsArray,
|
||||
uint32_t* punOutItemsArraySize
|
||||
)
|
||||
) noexcept {
|
||||
) noexcept {
|
||||
return smoke_api::steam_inventory::GetResultItems(
|
||||
__func__,
|
||||
resultHandle,
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#include <koalabox/logger.hpp>
|
||||
|
||||
#include "smoke_api/smoke_api.hpp"
|
||||
#include "smoke_api/interfaces/steam_user.hpp"
|
||||
#include "steam_api/virtuals/steam_api_virtuals.hpp"
|
||||
|
||||
VIRTUAL(AppId_t) ISteamUtils_GetAppID(PARAMS()) noexcept {
|
||||
SWAPPED_CALL(THIS, ISteamUtils_GetAppID, ARGS());
|
||||
}
|
||||
@@ -13,6 +13,7 @@ VIRTUAL(void*) ISteamClient_GetISteamApps(PARAMS(HSteamUser, HSteamPipe, const c
|
||||
VIRTUAL(void*) ISteamClient_GetISteamUser(PARAMS(HSteamUser, HSteamPipe, const char*)) noexcept;
|
||||
VIRTUAL(void*) ISteamClient_GetISteamGenericInterface(PARAMS(HSteamUser, HSteamPipe, const char*)) noexcept;
|
||||
VIRTUAL(void*) ISteamClient_GetISteamInventory(PARAMS(HSteamUser, HSteamPipe, const char*)) noexcept;
|
||||
VIRTUAL(void*) ISteamClient_GetISteamUtils(PARAMS(HSteamPipe, const char*)) noexcept; // Unhooked
|
||||
|
||||
// ISteamHTTP
|
||||
VIRTUAL(bool) ISteamHTTP_GetHTTPResponseBodyData(PARAMS(HTTPRequestHandle, const uint8_t*, uint32_t)) noexcept;
|
||||
@@ -43,7 +44,7 @@ VIRTUAL(bool) ISteamInventory_CheckResultSteamID(PARAMS(SteamInventoryResult_t,
|
||||
VIRTUAL(EUserHasLicenseForAppResult) ISteamUser_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t)) noexcept;
|
||||
|
||||
// ISteamUtils
|
||||
VIRTUAL(AppId_t) ISteamUtils_GetAppID(PARAMS()) noexcept;
|
||||
VIRTUAL(AppId_t) ISteamUtils_GetAppID(PARAMS()) noexcept; // Unhooked
|
||||
|
||||
// ISteamGameServer
|
||||
VIRTUAL(EUserHasLicenseForAppResult) ISteamGameServer_UserHasLicenseForApp(PARAMS(CSteamID, AppId_t)) noexcept;
|
||||
|
||||
@@ -46,12 +46,12 @@
|
||||
#define PARAMS(...) const void* RCX __VA_OPT__(,) __VA_ARGS__
|
||||
#define ARGS(...) RCX __VA_OPT__(,) __VA_ARGS__
|
||||
#define THIS RCX
|
||||
#define DECLARE_ARGS() const void* RCX = nullptr;
|
||||
#define DECLARE_ARGS() void* RCX = nullptr;
|
||||
#else
|
||||
#define PARAMS(...) const void* ECX, const void* EDX __VA_OPT__(,) __VA_ARGS__
|
||||
#define ARGS(...) ECX, EDX __VA_OPT__(,) __VA_ARGS__
|
||||
#define THIS ECX
|
||||
#define DECLARE_ARGS() const void* ECX = nullptr; const void* EDX = nullptr;
|
||||
#define DECLARE_ARGS() void* ECX = nullptr; const void* EDX = nullptr;
|
||||
#endif
|
||||
|
||||
using AppId_t = uint32_t;
|
||||
|
||||
@@ -8,13 +8,14 @@
|
||||
"sdk_dll_names": "`steam_api.dll` or `steam_api64.dll`",
|
||||
"sdk_dll_orig_names": "`steam_api_o.dll` or `steam_api64_o.dll`",
|
||||
"show_3rd_party_point": true,
|
||||
"unlocker_dll_names": "`SmokeAPI32.dll` or `SmokeAPI64.dll`",
|
||||
"unlocker_dll_names": "`smoke_api32.dll` or `smoke_api64.dll`",
|
||||
"config_filename": "SmokeAPI.config.json",
|
||||
"github_repo_url": "https://github.com/acidicoala/SmokeAPI",
|
||||
"forum_topic_url": "https://cs.rin.ru/forum/viewtopic.php?p=2597932#p2597932",
|
||||
"dlc_database": "SteamDB",
|
||||
"dlc_database_url": "https://steamdb.info/",
|
||||
"json_schema_path": "./res/SmokeAPI.schema.json"
|
||||
"json_schema_path": "./res/SmokeAPI.schema.json",
|
||||
"self_inject_dll": "`version.dll` or `winhttp.dll` or `winmm.dll`"
|
||||
},
|
||||
"tasks": [
|
||||
{
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace {
|
||||
|
||||
fs::remove(zip_file_path);
|
||||
}
|
||||
} // namespace
|
||||
}
|
||||
|
||||
/**
|
||||
* A tool for downloading Steamworks SDK and unpacking its headers and binaries
|
||||
|
||||
Reference in New Issue
Block a user