From 82e7b2c5701745dc27b8285233a405dc5756cd18 Mon Sep 17 00:00:00 2001 From: a Date: Fri, 1 Aug 2025 18:35:19 +0300 Subject: [PATCH] new stub for old steam lib --- .github/workflows/emu-build-all-win.yml | 2 + package_win.bat | 4 + post_build/README.steam_old_lib.md | 12 + premake5.lua | 39 +++ steam_old_lib/dllmain.cpp | 34 ++ steam_old_lib/steam_old_lib.cpp | 399 ++++++++++++++++++++++++ steam_old_lib/steam_old_lib.hpp | 122 ++++++++ 7 files changed, 612 insertions(+) create mode 100644 post_build/README.steam_old_lib.md create mode 100644 steam_old_lib/dllmain.cpp create mode 100644 steam_old_lib/steam_old_lib.cpp create mode 100644 steam_old_lib/steam_old_lib.hpp diff --git a/.github/workflows/emu-build-all-win.yml b/.github/workflows/emu-build-all-win.yml index c794d1dc..b9e1835e 100644 --- a/.github/workflows/emu-build-all-win.yml +++ b/.github/workflows/emu-build-all-win.yml @@ -43,6 +43,8 @@ jobs: "steamclient_experimental_loader", "steamclient_experimental_extra", "lib_game_overlay_renderer", + # steam old lib + "lib_steam_old", # tools "tool_lobby_connect", "tool_generate_interfaces", diff --git a/package_win.bat b/package_win.bat index 202da68e..84eac3ed 100644 --- a/package_win.bat +++ b/package_win.bat @@ -56,6 +56,10 @@ if exist "%TARGET_DIR%\experimental\" ( copy /y "%ROOT%\post_build\README.experimental.md" "%TARGET_DIR%\experimental\" ) +if exist "%TARGET_DIR%\steam_old_lib\" ( + copy /y "%ROOT%\post_build\README.steam_old_lib.md" "%TARGET_DIR%\steam_old_lib\" +) + if exist "%TARGET_DIR%\steamclient_experimental\" ( xcopy /y /s /e /r "%ROOT%\post_build\win\ColdClientLoader.EXAMPLE\" "%TARGET_DIR%\steamclient_experimental\dll_injection.EXAMPLE\" copy /y "%ROOT%\post_build\README.experimental_steamclient.md" "%TARGET_DIR%\steamclient_experimental\" diff --git a/post_build/README.steam_old_lib.md b/post_build/README.steam_old_lib.md new file mode 100644 index 00000000..8bfc4c82 --- /dev/null +++ b/post_build/README.steam_old_lib.md @@ -0,0 +1,12 @@ +## What is this ? +This is an old Windows-only library equivalent to `steam_api.dll` that's still used by some old games. + +## How to use ? +- Copy/Paste it beside the game's `.exe` file +- Inject it via `ColdClientLoader`, or any other loader you prefer + +## Purpose ? +Bypass initial/basic checks in old games protected with old version of Stub drm. + +## Note +Note that it doesn't emulate any Steam functionality at the moment. diff --git a/premake5.lua b/premake5.lua index 32b06384..c6e6b14a 100644 --- a/premake5.lua +++ b/premake5.lua @@ -1354,6 +1354,45 @@ project "steamclient_experimental_extra" -- End steamclient_experimental_extra +-- Project lib_steam_old +project "lib_steam_old" + -- https://premake.github.io/docs/Configurations-and-Platforms/#per-project-configurations + removeplatforms { "x64" } + + kind "SharedLib" + location "%{wks.location}/%{prj.name}" + targetdir(path.join(build_dir, os_iden, _ACTION, "%{cfg.buildcfg}/steam_old_lib")) + targetname "Steam" + + + -- include dir + --------- + -- x32 include dir + includedirs { + x32_deps_include, + } + + + -- common source & header files + --------- + filter {} -- reset the filter and remove all active keywords + files { + "steam_old_lib/**", + "helpers/common_helpers.cpp", "helpers/common_helpers/**", + 'libs/utfcpp/**', + -- detours + detours_files, + } + removefiles { + 'libs/detours/uimports.cc', + } + -- x32 common source files + files { + "resources/win/client/32/resources.rc" + } +-- End lib_steam_old + + -- Project steamclient_experimental_loader project "steamclient_experimental_loader" kind "WindowedApp" diff --git a/steam_old_lib/dllmain.cpp b/steam_old_lib/dllmain.cpp new file mode 100644 index 00000000..3fcdfeac --- /dev/null +++ b/steam_old_lib/dllmain.cpp @@ -0,0 +1,34 @@ +#include "steam_old_lib.hpp" + + +static bool dll_loaded = false; + +BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved) +{ + switch (reason) { + case DLL_PROCESS_ATTACH: { + if (!soldlib::patch((void*)hModule)) { + +#ifdef SOLD_EXTRA_DEBUG + MessageBoxA(nullptr, "Failed to initialize", "Main", MB_OK | MB_ICONERROR); +#endif + + // https://learn.microsoft.com/en-us/windows/win32/dlls/dllmain + // "The system immediately calls your entry-point function with DLL_PROCESS_DETACH and unloads the DLL" + return FALSE; + } + + dll_loaded = true; + } + break; + + case DLL_PROCESS_DETACH: { + if (dll_loaded) { + soldlib::restore(); + } + } + break; + } + + return TRUE; +} diff --git a/steam_old_lib/steam_old_lib.cpp b/steam_old_lib/steam_old_lib.cpp new file mode 100644 index 00000000..08a754b0 --- /dev/null +++ b/steam_old_lib/steam_old_lib.cpp @@ -0,0 +1,399 @@ +#include "steam_old_lib.hpp" + +#include "common_helpers/common_helpers.hpp" + +#include "detours/detours.h" + +#include +#include +#include +#include + +#include // WinVerifyTrust + + +#define S_API extern "C" __declspec(dllexport) +#define STEAM_CALL __cdecl + +#define STEAM_INVALID_CALL_HANDLE 0 + + +static HMODULE my_hModule = nullptr; +HMODULE wintrust_dll = nullptr; +std::wstring wintrust_lib_path = L""; + +static bool WinVerifyTrust_hooked = false; +static bool LoadLibraryA_hooked = false; +static bool LoadLibraryExA_hooked = false; +static bool LoadLibraryW_hooked = false; +static bool LoadLibraryExW_hooked = false; + +static decltype(WinVerifyTrust) *actual_WinVerifyTrust = nullptr; +__declspec(noinline) +static LONG WINAPI WinVerifyTrust_hook(HWND hwnd, GUID *pgActionID, LPVOID pWVTData) { + if (WinVerifyTrust_hooked) { + SetLastError(ERROR_SUCCESS); + return 0; // success + } + + if (actual_WinVerifyTrust) { + return actual_WinVerifyTrust(hwnd, pgActionID, pWVTData); + } + + SetLastError(ERROR_SUCCESS); + return 0; // success +} + +static decltype(LoadLibraryA) *actual_LoadLibraryA = LoadLibraryA; +__declspec(noinline) +static HMODULE WINAPI LoadLibraryA_hook(LPCSTR lpLibFileName) +{ + if (LoadLibraryA_hooked && + lpLibFileName && lpLibFileName[0] && + common_helpers::ends_with_i(lpLibFileName, "Steam.dll")) { + return my_hModule; + } + + return actual_LoadLibraryA(lpLibFileName); +} + +static decltype(LoadLibraryExA) *actual_LoadLibraryExA = LoadLibraryExA; +__declspec(noinline) +static HMODULE WINAPI LoadLibraryExA_hook(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) +{ + if (LoadLibraryExA_hooked && + lpLibFileName && lpLibFileName[0] && + common_helpers::ends_with_i(lpLibFileName, "Steam.dll")) { + return my_hModule; + } + + return actual_LoadLibraryExA(lpLibFileName, hFile, dwFlags); +} + +static decltype(LoadLibraryW) *actual_LoadLibraryW = LoadLibraryW; +__declspec(noinline) +static HMODULE WINAPI LoadLibraryW_hook(LPCWSTR lpLibFileName) +{ + if (LoadLibraryW_hooked && + lpLibFileName && lpLibFileName[0] && + common_helpers::ends_with_i(lpLibFileName, L"Steam.dll")) { + return my_hModule; + } + + return actual_LoadLibraryW(lpLibFileName); +} + +static decltype(LoadLibraryExW) *actual_LoadLibraryExW = LoadLibraryExW; +__declspec(noinline) +static HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) +{ + if (LoadLibraryExW_hooked && + lpLibFileName && lpLibFileName[0] && + common_helpers::ends_with_i(lpLibFileName, L"Steam.dll")) { + return my_hModule; + } + + return actual_LoadLibraryExW(lpLibFileName, hFile, dwFlags); +} + + +static bool redirect_win32_apis() +{ + try { + wintrust_dll = LoadLibraryExW(wintrust_lib_path.c_str(), NULL, 0); + if (!wintrust_dll) throw std::runtime_error(""); + + actual_WinVerifyTrust = (decltype(actual_WinVerifyTrust))GetProcAddress(wintrust_dll, "WinVerifyTrust"); + if (!actual_WinVerifyTrust) throw std::runtime_error(""); + + if (DetourTransactionBegin() != NO_ERROR) throw std::runtime_error(""); + if (DetourUpdateThread(GetCurrentThread()) != NO_ERROR) throw std::runtime_error(""); + + if (DetourAttach((PVOID *)&actual_WinVerifyTrust, (PVOID)WinVerifyTrust_hook) != NO_ERROR) throw std::runtime_error(""); + if (DetourAttach((PVOID *)&actual_LoadLibraryA, (PVOID)LoadLibraryA_hook) != NO_ERROR) throw std::runtime_error(""); + if (DetourAttach((PVOID *)&actual_LoadLibraryExA, (PVOID)LoadLibraryExA_hook) != NO_ERROR) throw std::runtime_error(""); + if (DetourAttach((PVOID *)&actual_LoadLibraryW, (PVOID)LoadLibraryW_hook) != NO_ERROR) throw std::runtime_error(""); + if (DetourAttach((PVOID *)&actual_LoadLibraryExW, (PVOID)LoadLibraryExW_hook) != NO_ERROR) throw std::runtime_error(""); + if (DetourTransactionCommit() != NO_ERROR) throw std::runtime_error(""); + + WinVerifyTrust_hooked = true; + LoadLibraryA_hooked = true; + LoadLibraryExA_hooked = true; + LoadLibraryW_hooked = true; + LoadLibraryExW_hooked = true; + + return true; + } catch (...) { + + } + + if (wintrust_dll) { + FreeLibrary(wintrust_dll); + wintrust_dll = nullptr; + } + + return false; +} + +static bool restore_win32_apis() +{ + WinVerifyTrust_hooked = false; + LoadLibraryA_hooked = false; + LoadLibraryExA_hooked = false; + LoadLibraryW_hooked = false; + LoadLibraryExW_hooked = false; + + bool ret = false; + + try { + if (DetourTransactionBegin() != NO_ERROR) throw std::runtime_error(""); + if (DetourUpdateThread(GetCurrentThread()) != NO_ERROR) throw std::runtime_error(""); + + if (actual_WinVerifyTrust) { + DetourDetach((PVOID *)&actual_WinVerifyTrust, (PVOID)WinVerifyTrust_hook); + } + + DetourDetach((PVOID *)&actual_LoadLibraryA, (PVOID)LoadLibraryA_hook); + DetourDetach((PVOID *)&actual_LoadLibraryExA, (PVOID)LoadLibraryExA_hook); + DetourDetach((PVOID *)&actual_LoadLibraryW, (PVOID)LoadLibraryW_hook); + DetourDetach((PVOID *)&actual_LoadLibraryExW, (PVOID)LoadLibraryExW_hook); + if (DetourTransactionCommit() != NO_ERROR) throw std::runtime_error(""); + + ret = true; + } catch (...) { + + } + + if (wintrust_dll) { + FreeLibrary(wintrust_dll); + wintrust_dll = nullptr; + } + + return ret; +} + +#ifdef SOLD_EXTRA_DEBUG +extern "C" __declspec(dllexport) +#endif +void __cdecl notify_patch_done() +{ +#ifdef SOLD_EXTRA_DEBUG + MessageBoxA(nullptr, "Cleanup/Uninstall was called, hook a debugger here!", "Cleanup called", MB_OK | MB_ICONASTERISK); +#endif +} + +static void set_ok_err(soldlib::TSteamError *pError) { + if (pError) { + pError->eSteamError = soldlib::ESteamError::eSteamErrorNone; + pError->eDetailedErrorType = soldlib::EDetailedPlatformErrorType::eNoDetailedErrorAvailable; + pError->nDetailedErrorCode = 0; + pError->szDesc[0] = 0; + } +} + +static void set_bad_err(soldlib::TSteamError *pError) { + if (pError) { + pError->eSteamError = soldlib::ESteamError::eSteamErrorBadArg; + pError->eDetailedErrorType = soldlib::EDetailedPlatformErrorType::eNoDetailedErrorAvailable; + pError->nDetailedErrorCode = soldlib::ESteamError::eSteamErrorBadArg; + pError->szDesc[0] = 0; + } +} + +bool soldlib::patch(void *lib_hModule) +{ + my_hModule = (HMODULE)lib_hModule; + + if (wintrust_lib_path.empty()) { + auto size = GetSystemDirectoryW(&wintrust_lib_path[0], 0); + if (size <= 0) return false; + + wintrust_lib_path.resize(size); + size = GetSystemDirectoryW(&wintrust_lib_path[0], (unsigned)wintrust_lib_path.size()); + if (size >= (unsigned)wintrust_lib_path.size()) { + wintrust_lib_path.clear(); + return false; + } + + wintrust_lib_path.pop_back(); // remove null + wintrust_lib_path += L"\\Wintrust.dll"; + } + + return redirect_win32_apis(); +} + +bool soldlib::restore() +{ + return restore_win32_apis(); +} + + + +S_API int STEAM_CALL SteamStartup( unsigned int uUsingMask, soldlib::TSteamError *pError ) +{ + set_ok_err(pError); + return 1; +} + +S_API int STEAM_CALL SteamCleanup( soldlib::TSteamError *pError ) +{ + set_ok_err(pError); + // restore_win32_apis(); // appid 7450 loads the dll again at runtime, we can't unload here + notify_patch_done(); + return 1; +} + +S_API unsigned /*SteamCallHandle_t*/ STEAM_CALL SteamUninstall( soldlib::TSteamError *pError ) +{ + set_ok_err(pError); + // restore_win32_apis(); // appid 7450 loads the dll again at runtime, we can't unload here + notify_patch_done(); + return STEAM_INVALID_CALL_HANDLE; +} + +S_API int STEAM_CALL SteamGetAccountStatus( unsigned int* puAccountStatusFlags, soldlib::TSteamError *pError ) +{ + if (puAccountStatusFlags) { + *puAccountStatusFlags = + soldlib::ESteamAccountStatusBitFields::eSteamAccountStatusDefault + | soldlib::ESteamAccountStatusBitFields::eSteamAccountStatusEmailVerified; + } + + set_ok_err(pError); + return 1; +} + +S_API int STEAM_CALL SteamGetCurrentEmailAddress( char *szEmailaddress, unsigned int uBufSize, unsigned int *puEmailaddressChars, soldlib::TSteamError *pError ) +{ + constexpr const static std::string_view EMAIL = "orca@gbe.com"; + + unsigned copied = 0; + if (szEmailaddress && uBufSize > 0) { + copied = (unsigned)EMAIL.copy(szEmailaddress, uBufSize); + szEmailaddress[copied] = 0; + } + if (puEmailaddressChars) *puEmailaddressChars = copied; + set_ok_err(pError); + return 1; +} + +// https://gitlab.com/KittenPopo/csgo-2018-source/-/blob/main/common/Steam.h +// https://github.com/SteamRE/open-steamworks/blob/master/Open%20Steamworks/Steam.h +S_API int STEAM_CALL SteamIsAppSubscribed( unsigned int uAppId, int *pbIsAppSubscribed, int *pbIsSubscriptionPending, soldlib::TSteamError *pError ) { + if (pbIsAppSubscribed) *pbIsAppSubscribed = 1; + if (pbIsSubscriptionPending) *pbIsSubscriptionPending = 0; + set_ok_err(pError); + return 1; +} + +S_API int STEAM_CALL SteamIsSubscribed( unsigned int uSubscriptionId, int *pbIsSubscribed, int *pbIsSubscriptionPending, soldlib::TSteamError *pError ) +{ + if (pbIsSubscribed) *pbIsSubscribed = 1; + if (pbIsSubscriptionPending) *pbIsSubscriptionPending = 0; + set_ok_err(pError); + return 1; +} + +S_API int STEAM_CALL SteamIsLoggedIn( int *pbIsLoggedIn, soldlib::TSteamError *pError ) +{ + if (pbIsLoggedIn) *pbIsLoggedIn = 1; + set_ok_err(pError); + return 1; +} + +S_API int STEAM_CALL SteamIsSecureComputer( int *pbIsSecureComputer, soldlib::TSteamError *pError ) +{ + if (pbIsSecureComputer) *pbIsSecureComputer = 1; + set_ok_err(pError); + return 1; +} + +S_API unsigned /*SteamCallHandle_t*/ STEAM_CALL SteamLaunchApp( unsigned int uAppId, unsigned int uLaunchOption, const char *cszArgs, soldlib::TSteamError *pError ) +{ + set_ok_err(pError); + return STEAM_INVALID_CALL_HANDLE; +} + +S_API unsigned /*SteamCallHandle_t*/ STEAM_CALL SteamLogin( const char *cszUser, const char *cszPassphrase, int bIsSecureComputer, soldlib::TSteamError *pError ) +{ + set_ok_err(pError); + return STEAM_INVALID_CALL_HANDLE; +} + + +S_API unsigned /*SteamCallHandle_t*/ STEAM_CALL SteamRefreshAccountInfo( soldlib::TSteamError *pError ) +{ + set_ok_err(pError); + return STEAM_INVALID_CALL_HANDLE; +} + +S_API unsigned /*SteamCallHandle_t*/ STEAM_CALL SteamRefreshAccountInfoEx( int bContentDescriptionOnly, soldlib::TSteamError* pError ) +{ + set_ok_err(pError); + return STEAM_INVALID_CALL_HANDLE; +} + +S_API unsigned /*SteamCallHandle_t*/ STEAM_CALL SteamRefreshAccountInfo2( int bRefreshAccount, int bRefreshCDDB, soldlib::TSteamError *pError ) +{ + set_ok_err(pError); + return 1; +} + +S_API unsigned /*SteamCallHandle_t*/ STEAM_CALL SteamRefreshLogin( const char *cszPassphrase, int bIsSecureComputer, soldlib::TSteamError *pError ) +{ + set_ok_err(pError); + return STEAM_INVALID_CALL_HANDLE; +} + + +S_API unsigned /*SteamCallHandle_t*/ STEAM_CALL SteamSubscribe( unsigned int uSubscriptionId, const void /*TSteamSubscriptionBillingInfo*/ *pSubscriptionBillingInfo, soldlib::TSteamError *pError ) +{ + set_ok_err(pError); + return STEAM_INVALID_CALL_HANDLE; +} + +S_API unsigned /*SteamCallHandle_t*/ STEAM_CALL SteamUnsubscribe( unsigned int uSubscriptionId, soldlib::TSteamError *pError ) +{ + set_ok_err(pError); + return 1; +} + +S_API unsigned /*SteamCallHandle_t*/ STEAM_CALL SteamUpdateAccountBillingInfo( const void /*TSteamPaymentCardInfo*/ *pPaymentCardInfo, soldlib::TSteamError *pError ) +{ + set_ok_err(pError); + return STEAM_INVALID_CALL_HANDLE; +} + +S_API unsigned /*SteamCallHandle_t*/ STEAM_CALL SteamUpdateSubscriptionBillingInfo( unsigned int uSubscriptionId, const void /*TSteamSubscriptionBillingInfo*/ *pSubscriptionBillingInfo, soldlib::TSteamError *pError ) +{ + set_ok_err(pError); + return STEAM_INVALID_CALL_HANDLE; +} + +S_API unsigned int STEAM_CALL SteamNumAppsRunning( soldlib::TSteamError *pError ) +{ + set_ok_err(pError); + return 1; +} + +S_API int STEAM_CALL SteamCheckAppOwnership( unsigned int uAppId, int* pbOwned, void /*TSteamGlobalUserID*/ *pSteamID, soldlib::TSteamError* pError ) +{ + if (pbOwned) *pbOwned = 1; + set_ok_err(pError); + return 1; +} + + +S_API int STEAM_CALL SteamGetAppDLCStatus( unsigned int uAppId, unsigned int uDLCCacheId, int *pbDownloaded, soldlib::TSteamError *pError ) +{ + if (pbDownloaded) *pbDownloaded = 0; + + if (0 == uAppId || UINT32_MAX == uAppId) { + set_bad_err(pError); + return 0; + } + + if (pbDownloaded) *pbDownloaded = 1; + set_ok_err(pError); + return 1; +} diff --git a/steam_old_lib/steam_old_lib.hpp b/steam_old_lib/steam_old_lib.hpp new file mode 100644 index 00000000..a45a9490 --- /dev/null +++ b/steam_old_lib/steam_old_lib.hpp @@ -0,0 +1,122 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN +#include + + +#if !defined(SOLD_EXTRA_DEBUG) + #if defined(DEBUG) || defined(_DEBUG) + #define SOLD_EXTRA_DEBUG + #endif +#endif + + +namespace soldlib { + + // https://github.com/SteamRE/open-steamworks/blob/master/Open%20Steamworks/SteamTypes.h +#define STEAM_MAX_PATH 255 + +// https://github.com/SteamRE/open-steamworks/blob/master/Open%20Steamworks/ESteamError.h +typedef enum ESteamError +{ + eSteamErrorNone = 0, + eSteamErrorUnknown = 1, + eSteamErrorLibraryNotInitialized = 2, + eSteamErrorLibraryAlreadyInitialized = 3, + eSteamErrorConfig = 4, + eSteamErrorContentServerConnect = 5, + eSteamErrorBadHandle = 6, + eSteamErrorHandlesExhausted = 7, + eSteamErrorBadArg = 8, + eSteamErrorNotFound = 9, + eSteamErrorRead = 10, + eSteamErrorEOF = 11, + eSteamErrorSeek = 12, + eSteamErrorCannotWriteNonUserConfigFile = 13, + eSteamErrorCacheOpen = 14, + eSteamErrorCacheRead = 15, + eSteamErrorCacheCorrupted = 16, + eSteamErrorCacheWrite = 17, + eSteamErrorCacheSession = 18, + eSteamErrorCacheInternal = 19, + eSteamErrorCacheBadApp = 20, + eSteamErrorCacheVersion = 21, + eSteamErrorCacheBadFingerPrint = 22, + + eSteamErrorNotFinishedProcessing = 23, + eSteamErrorNothingToDo = 24, + eSteamErrorCorruptEncryptedUserIDTicket = 25, + eSteamErrorSocketLibraryNotInitialized = 26, + eSteamErrorFailedToConnectToUserIDTicketValidationServer = 27, + eSteamErrorBadProtocolVersion = 28, + eSteamErrorReplayedUserIDTicketFromClient = 29, + eSteamErrorReceiveResultBufferTooSmall = 30, + eSteamErrorSendFailed = 31, + eSteamErrorReceiveFailed = 32, + eSteamErrorReplayedReplyFromUserIDTicketValidationServer = 33, + eSteamErrorBadSignatureFromUserIDTicketValidationServer = 34, + eSteamErrorValidationStalledSoAborted = 35, + eSteamErrorInvalidUserIDTicket = 36, + eSteamErrorClientLoginRateTooHigh = 37, + eSteamErrorClientWasNeverValidated = 38, + eSteamErrorInternalSendBufferTooSmall = 39, + eSteamErrorInternalReceiveBufferTooSmall = 40, + eSteamErrorUserTicketExpired = 41, + eSteamErrorCDKeyAlreadyInUseOnAnotherClient = 42, + + eSteamErrorNotLoggedIn = 101, + eSteamErrorAlreadyExists = 102, + eSteamErrorAlreadySubscribed = 103, + eSteamErrorNotSubscribed = 104, + eSteamErrorAccessDenied = 105, + eSteamErrorFailedToCreateCacheFile = 106, + eSteamErrorCallStalledSoAborted = 107, + eSteamErrorEngineNotRunning = 108, + eSteamErrorEngineConnectionLost = 109, + eSteamErrorLoginFailed = 110, + eSteamErrorAccountPending = 111, + eSteamErrorCacheWasMissingRetry = 112, + eSteamErrorLocalTimeIncorrect = 113, + eSteamErrorCacheNeedsDecryption = 114, + eSteamErrorAccountDisabled = 115, + eSteamErrorCacheNeedsRepair = 116, + eSteamErrorRebootRequired = 117, + + eSteamErrorNetwork = 200, + + eSteamErrorOffline = 201, +} ESteamError; + +// https://github.com/SteamRE/open-steamworks/blob/master/Open%20Steamworks/TSteamError.h +typedef enum EDetailedPlatformErrorType +{ + eNoDetailedErrorAvailable, + eStandardCerrno, + eWin32LastError, + eWinSockLastError, + eDetailedPlatformErrorCount +} EDetailedPlatformErrorType; + +typedef struct TSteamError +{ + ESteamError eSteamError; + EDetailedPlatformErrorType eDetailedErrorType; + int nDetailedErrorCode; + char szDesc[STEAM_MAX_PATH]; +} TSteamError; + +// https://gitlab.com/KittenPopo/csgo-2018-source/-/blob/main/common/SteamCommon.h +// https://github.com/ValveSoftware/source-sdk-2013/blob/master/src/common/steamcommon.h +typedef enum +{ + eSteamAccountStatusDefault = 0x00000000, + eSteamAccountStatusEmailVerified = 0x00000001, + /* Note: Mask value 0x2 is reserved for future use. (Some, but not all, public accounts already have this set.) */ + eSteamAccountDisabled = 0x00000004 +} ESteamAccountStatusBitFields; + + +bool patch(void *lib_hModule); +bool restore(); + +}