From 760debe6484173435388e71285650506299bbfa9 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 19 Feb 2017 02:00:45 +0100 Subject: [PATCH] [Proxy] Adapt process spawning for different api versions --- src/Steam/Proxy.cpp | 72 ++++++++++++++++++++++++++++++++++----------- src/Steam/Proxy.hpp | 37 +++++++++++++++++++++-- 2 files changed, 90 insertions(+), 19 deletions(-) diff --git a/src/Steam/Proxy.cpp b/src/Steam/Proxy.cpp index 8b5f62cf..79f70b1e 100644 --- a/src/Steam/Proxy.cpp +++ b/src/Steam/Proxy.cpp @@ -53,9 +53,24 @@ namespace Steam return nullptr; } + size_t Interface::getMethodParamSize(void* method) + { + unsigned char* methodPtr = static_cast(method); + for (; !IsBadReadPtr(methodPtr, 3); ++methodPtr) + { + if (methodPtr[0] == 0xC2 && methodPtr[2] == 0) // __stdcall return + { + return (static_cast(methodPtr[1])/* / sizeof(void*)*/); + } + } + + return 0; + } + + std::string Interface::getMethodName(unsigned char* methodPtr) { - for(;!IsBadReadPtr(methodPtr, 1); ++methodPtr) + for(;!IsBadReadPtr(methodPtr, 3); ++methodPtr) { if(methodPtr[0] == 0x68) // Push { @@ -100,21 +115,21 @@ namespace Steam gameID.appID = Proxy::AppId & 0xFFFFFF; gameID.modID = 0xBAADF00D; - Interface clientApps(Proxy::ClientEngine->GetIClientApps(Proxy::SteamUser, Proxy::SteamPipe, "CLIENTAPPS_INTERFACE_VERSION001")); - Interface clientShortcuts(Proxy::ClientEngine->GetIClientShortcuts(Proxy::SteamUser, Proxy::SteamPipe, "CLIENTSHORTCUTS_INTERFACE_VERSION001")); - if (!clientApps || !clientShortcuts) return; - - KeyValuesBuilder builder; - builder.packString("name", mod.data()); - builder.packUint64("gameid", gameID.bits); - builder.packString("installed", "1"); - builder.packString("gamedir", "IW4x"); - builder.packString("serverbrowsername", "IW4x"); - builder.packEnd(); - - std::string str = builder.getString(); - uint32_t uniqueId = clientShortcuts.invoke("GetUniqueLocalAppId"); - if (clientApps.invoke("SetLocalAppConfig", uniqueId, str.data(), static_cast(str.size()))) +// Interface clientApps(Proxy::ClientEngine->GetIClientApps(Proxy::SteamUser, Proxy::SteamPipe, "CLIENTAPPS_INTERFACE_VERSION001")); +// Interface clientShortcuts(Proxy::ClientEngine->GetIClientShortcuts(Proxy::SteamUser, Proxy::SteamPipe, "CLIENTSHORTCUTS_INTERFACE_VERSION001")); +// if (!clientApps || !clientShortcuts) return; +// +// KeyValuesBuilder builder; +// builder.packString("name", mod.data()); +// builder.packUint64("gameid", gameID.bits); +// builder.packString("installed", "1"); +// builder.packString("gamedir", "IW4x"); +// builder.packString("serverbrowsername", "IW4x"); +// builder.packEnd(); +// +// std::string str = builder.getString(); +// uint32_t uniqueId = clientShortcuts.invoke("GetUniqueLocalAppId"); +// if (clientApps.invoke("SetLocalAppConfig", uniqueId, str.data(), static_cast(str.size()))) { Interface clientUtils(Proxy::ClientEngine->GetIClientUtils(Proxy::SteamPipe, "CLIENTUTILS_INTERFACE_VERSION001")); clientUtils.invoke("SetAppIDForCurrentPipe", Proxy::AppId, false); @@ -126,7 +141,30 @@ namespace Steam GetCurrentDirectoryA(sizeof(ourDirectory), ourDirectory); std::string cmdline = ::Utils::String::VA("\"%s\" -proc %d", ourPath, GetCurrentProcessId()); - Proxy::ClientUser.invoke("SpawnProcess", ourPath, cmdline.data(), 0, ourDirectory, gameID.bits, Proxy::AppId, mod.data(), 0, 0); + + // As of 02/19/2017, the SpawnProcess method doesn't require the app id anymore, + // but only for those who participate in the beta. + // Therefore we have to check how many bytes the method expects as arguments + // and adapt our call accordingly! + size_t expectedParams = Proxy::ClientUser.paramSize("SpawnProcess"); + if(expectedParams == 40) // Release + { + Proxy::ClientUser.invoke("SpawnProcess", ourPath, cmdline.data(), 0, ourDirectory, gameID.bits, Proxy::AppId, mod.data(), 0, 0); + } + else if(expectedParams == 36) // Beta + { + Proxy::ClientUser.invoke("SpawnProcess", ourPath, cmdline.data(), 0, ourDirectory, gameID.bits, mod.data(), 0, 0); + } + else if (expectedParams == 48) // Legacy, expects VAC blob + { + char blob[8] = { 0 }; + + Proxy::ClientUser.invoke("SpawnProcess", blob, 0, ourPath, cmdline.data(), 0, ourDirectory, gameID.bits, Proxy::AppId, mod.data(), 0, 0); + } + else + { + OutputDebugStringA("Steam proxy was unable to match the arguments for SpawnProcess!\n"); + } } } diff --git a/src/Steam/Proxy.hpp b/src/Steam/Proxy.hpp index d3344652..3d42dad4 100644 --- a/src/Steam/Proxy.hpp +++ b/src/Steam/Proxy.hpp @@ -111,10 +111,26 @@ namespace Steam template T invoke(std::string methodName, Args... args) { - if(!this->interfacePtr) throw std::runtime_error("No valid interface provided!"); + if(!this->interfacePtr) + { + OutputDebugStringA(::Utils::String::VA("Steam interface pointer is invalid (%s)!\n", methodName.data())); + return T(); + } void* method = this->getMethod(methodName); - if (!method) throw std::runtime_error("Method not found!"); + if (!method) + { + OutputDebugStringA(::Utils::String::VA("Steam interface method %s not found!\n", methodName.data())); + return T(); + } + + size_t argc = this->getMethodParamSize(method); + constexpr size_t passedArgc = Interface::AddSizes::value; + if(passedArgc != argc) + { + OutputDebugStringA(::Utils::String::VA("Steam interface arguments for method %s do not match (expected %d bytes, but got %d bytes)!\n", methodName.data(), argc, passedArgc)); + return T(); + } return reinterpret_cast(method)(this->interfacePtr, args...); } @@ -124,11 +140,28 @@ namespace Steam return this->interfacePtr != nullptr; } + size_t paramSize(std::string methodName) + { + void* method = this->getMethod(methodName); + if (method) return this->getMethodParamSize(method); + + return 0; + } + private: + // TODO: Use fold expressions in C++17 once available + template + struct AddSizes : std::integral_constant {}; + + // This recursively adds the sizes of the individual arguments while respecting the architecture of the CPU + template + struct AddSizes : std::integral_constant::value + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1))> {}; + void* interfacePtr; std::unordered_map methodCache; void* getMethod(std::string method); void* lookupMethod(std::string method); + size_t getMethodParamSize(void* method); std::string getMethodName(unsigned char* methodPtr); };