[Proxy] Adapt process spawning for different api versions
This commit is contained in:
parent
66d0fef6fe
commit
760debe648
@ -53,9 +53,24 @@ namespace Steam
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Interface::getMethodParamSize(void* method)
|
||||||
|
{
|
||||||
|
unsigned char* methodPtr = static_cast<unsigned char*>(method);
|
||||||
|
for (; !IsBadReadPtr(methodPtr, 3); ++methodPtr)
|
||||||
|
{
|
||||||
|
if (methodPtr[0] == 0xC2 && methodPtr[2] == 0) // __stdcall return
|
||||||
|
{
|
||||||
|
return (static_cast<size_t>(methodPtr[1])/* / sizeof(void*)*/);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string Interface::getMethodName(unsigned char* methodPtr)
|
std::string Interface::getMethodName(unsigned char* methodPtr)
|
||||||
{
|
{
|
||||||
for(;!IsBadReadPtr(methodPtr, 1); ++methodPtr)
|
for(;!IsBadReadPtr(methodPtr, 3); ++methodPtr)
|
||||||
{
|
{
|
||||||
if(methodPtr[0] == 0x68) // Push
|
if(methodPtr[0] == 0x68) // Push
|
||||||
{
|
{
|
||||||
@ -100,21 +115,21 @@ namespace Steam
|
|||||||
gameID.appID = Proxy::AppId & 0xFFFFFF;
|
gameID.appID = Proxy::AppId & 0xFFFFFF;
|
||||||
gameID.modID = 0xBAADF00D;
|
gameID.modID = 0xBAADF00D;
|
||||||
|
|
||||||
Interface clientApps(Proxy::ClientEngine->GetIClientApps(Proxy::SteamUser, Proxy::SteamPipe, "CLIENTAPPS_INTERFACE_VERSION001"));
|
// Interface clientApps(Proxy::ClientEngine->GetIClientApps(Proxy::SteamUser, Proxy::SteamPipe, "CLIENTAPPS_INTERFACE_VERSION001"));
|
||||||
Interface clientShortcuts(Proxy::ClientEngine->GetIClientShortcuts(Proxy::SteamUser, Proxy::SteamPipe, "CLIENTSHORTCUTS_INTERFACE_VERSION001"));
|
// Interface clientShortcuts(Proxy::ClientEngine->GetIClientShortcuts(Proxy::SteamUser, Proxy::SteamPipe, "CLIENTSHORTCUTS_INTERFACE_VERSION001"));
|
||||||
if (!clientApps || !clientShortcuts) return;
|
// if (!clientApps || !clientShortcuts) return;
|
||||||
|
//
|
||||||
KeyValuesBuilder builder;
|
// KeyValuesBuilder builder;
|
||||||
builder.packString("name", mod.data());
|
// builder.packString("name", mod.data());
|
||||||
builder.packUint64("gameid", gameID.bits);
|
// builder.packUint64("gameid", gameID.bits);
|
||||||
builder.packString("installed", "1");
|
// builder.packString("installed", "1");
|
||||||
builder.packString("gamedir", "IW4x");
|
// builder.packString("gamedir", "IW4x");
|
||||||
builder.packString("serverbrowsername", "IW4x");
|
// builder.packString("serverbrowsername", "IW4x");
|
||||||
builder.packEnd();
|
// builder.packEnd();
|
||||||
|
//
|
||||||
std::string str = builder.getString();
|
// std::string str = builder.getString();
|
||||||
uint32_t uniqueId = clientShortcuts.invoke<uint32_t>("GetUniqueLocalAppId");
|
// uint32_t uniqueId = clientShortcuts.invoke<uint32_t>("GetUniqueLocalAppId");
|
||||||
if (clientApps.invoke<bool>("SetLocalAppConfig", uniqueId, str.data(), static_cast<uint32_t>(str.size())))
|
// if (clientApps.invoke<bool>("SetLocalAppConfig", uniqueId, str.data(), static_cast<uint32_t>(str.size())))
|
||||||
{
|
{
|
||||||
Interface clientUtils(Proxy::ClientEngine->GetIClientUtils(Proxy::SteamPipe, "CLIENTUTILS_INTERFACE_VERSION001"));
|
Interface clientUtils(Proxy::ClientEngine->GetIClientUtils(Proxy::SteamPipe, "CLIENTUTILS_INTERFACE_VERSION001"));
|
||||||
clientUtils.invoke<void>("SetAppIDForCurrentPipe", Proxy::AppId, false);
|
clientUtils.invoke<void>("SetAppIDForCurrentPipe", Proxy::AppId, false);
|
||||||
@ -126,7 +141,30 @@ namespace Steam
|
|||||||
GetCurrentDirectoryA(sizeof(ourDirectory), ourDirectory);
|
GetCurrentDirectoryA(sizeof(ourDirectory), ourDirectory);
|
||||||
|
|
||||||
std::string cmdline = ::Utils::String::VA("\"%s\" -proc %d", ourPath, GetCurrentProcessId());
|
std::string cmdline = ::Utils::String::VA("\"%s\" -proc %d", ourPath, GetCurrentProcessId());
|
||||||
Proxy::ClientUser.invoke<bool>("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<bool>("SpawnProcess", ourPath, cmdline.data(), 0, ourDirectory, gameID.bits, Proxy::AppId, mod.data(), 0, 0);
|
||||||
|
}
|
||||||
|
else if(expectedParams == 36) // Beta
|
||||||
|
{
|
||||||
|
Proxy::ClientUser.invoke<bool>("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<bool>("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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,10 +111,26 @@ namespace Steam
|
|||||||
template<typename T, typename... Args>
|
template<typename T, typename... Args>
|
||||||
T invoke(std::string methodName, Args... args)
|
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);
|
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<sizeof(Args)...>::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<T(__thiscall*)(void*, Args ...)>(method)(this->interfacePtr, args...);
|
return reinterpret_cast<T(__thiscall*)(void*, Args ...)>(method)(this->interfacePtr, args...);
|
||||||
}
|
}
|
||||||
@ -124,11 +140,28 @@ namespace Steam
|
|||||||
return this->interfacePtr != nullptr;
|
return this->interfacePtr != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t paramSize(std::string methodName)
|
||||||
|
{
|
||||||
|
void* method = this->getMethod(methodName);
|
||||||
|
if (method) return this->getMethodParamSize(method);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// TODO: Use fold expressions in C++17 once available
|
||||||
|
template<std::size_t ...>
|
||||||
|
struct AddSizes : std::integral_constant<std::size_t, 0> {};
|
||||||
|
|
||||||
|
// This recursively adds the sizes of the individual arguments while respecting the architecture of the CPU
|
||||||
|
template<std::size_t X, std::size_t ... Xs>
|
||||||
|
struct AddSizes<X, Xs...> : std::integral_constant<std::size_t, X + ((AddSizes<Xs...>::value + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1))> {};
|
||||||
|
|
||||||
void* interfacePtr;
|
void* interfacePtr;
|
||||||
std::unordered_map<std::string, void*> methodCache;
|
std::unordered_map<std::string, void*> methodCache;
|
||||||
void* getMethod(std::string method);
|
void* getMethod(std::string method);
|
||||||
void* lookupMethod(std::string method);
|
void* lookupMethod(std::string method);
|
||||||
|
size_t getMethodParamSize(void* method);
|
||||||
std::string getMethodName(unsigned char* methodPtr);
|
std::string getMethodName(unsigned char* methodPtr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user