Prepare steam proxy

This commit is contained in:
momo5502 2019-01-06 23:24:33 +01:00
parent 7b2698561b
commit 83c070f13b
9 changed files with 367 additions and 86 deletions

View File

@ -14,29 +14,47 @@ void module_loader::register_module(std::unique_ptr<module>&& module_)
modules_->push_back(std::move(module_));
}
void module_loader::post_start()
bool module_loader::post_start()
{
static auto handled = false;
if (handled || !modules_) return;
if (handled || !modules_) return true;
handled = true;
try
{
for (const auto& module_ : *modules_)
{
module_->post_start();
}
}
catch(premature_shutdown_trigger&)
{
return false;
}
void module_loader::post_load()
return true;
}
bool module_loader::post_load()
{
static auto handled = false;
if (handled || !modules_) return;
if (handled || !modules_) return true;
handled = true;
try
{
for (const auto& module_ : *modules_)
{
module_->post_load();
}
}
catch (premature_shutdown_trigger&)
{
return false;
}
return true;
}
void module_loader::pre_destroy()
{
@ -59,3 +77,8 @@ void module_loader::destroy_modules()
delete modules_;
modules_ = nullptr;
}
void module_loader::trigger_premature_shutdown()
{
throw premature_shutdown_trigger();
}

View File

@ -4,6 +4,14 @@
class module_loader final
{
public:
class premature_shutdown_trigger final : public std::exception
{
const char* what() const noexcept override
{
return "Premature shutdown requested";
}
};
template <typename T>
class installer final
{
@ -18,10 +26,12 @@ public:
static void register_module(std::unique_ptr<module>&& module);
static void post_start();
static void post_load();
static bool post_start();
static bool post_load();
static void pre_destroy();
static void trigger_premature_shutdown();
private:
static std::vector<std::unique_ptr<module>>* modules_;

View File

@ -37,31 +37,11 @@ void verify_tls()
}
}
int main()
FARPROC load_binary(const launcher::mode mode)
{
FARPROC entry_point;
try
{
#ifdef GENERATE_DIFFS
binary_loader::create();
return 0;
#endif
verify_tls();
module_loader::post_start();
launcher launcher;
loader loader(mode);
utils::nt::module self;
const auto mode = launcher.run();
if (mode == launcher::mode::none)
{
module_loader::pre_destroy();
return 0;
}
loader loader(mode);
loader.set_import_resolver([self](const std::string& module, const std::string& function) -> FARPROC
{
if (module == "steam_api.dll")
@ -76,18 +56,54 @@ int main()
return nullptr;
});
entry_point = loader.load(self);
if (!entry_point) throw std::runtime_error("Unable to load binary into memory");
return loader.load(self);
}
int main()
{
FARPROC entry_point;
{
bool premature_shutdown = true;
const auto _ = gsl::finally( [&premature_shutdown]()
{
if(premature_shutdown)
{
module_loader::pre_destroy();
}
});
try
{
#ifdef GENERATE_DIFFS
binary_loader::create();
return 0;
#endif
verify_tls();
if (!module_loader::post_start()) return 0;
launcher launcher;
const auto mode = launcher.run();
if (mode == launcher::mode::none) return 0;
entry_point = load_binary(mode);
if (!entry_point)
{
throw std::runtime_error("Unable to load binary into memory");
}
game::initialize(mode);
module_loader::post_load();
if (!module_loader::post_load()) return 0;
premature_shutdown = false;
}
catch (std::exception& e)
{
MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR);
module_loader::pre_destroy();
return 1;
}
}
return entry_point();
}

View File

@ -1,20 +0,0 @@
#include <std_include.hpp>
#include <discord_rpc.h>
#include "loader/module_loader.hpp"
#include "game/game.hpp"
class steam final : public module
{
public:
void post_load() override
{
if (game::is_dedi()) return;
}
void pre_destroy() override
{
}
};
REGISTER_MODULE(steam)

View File

@ -0,0 +1,79 @@
#include <std_include.hpp>
#include <discord_rpc.h>
#include "loader/module_loader.hpp"
#include "game/game.hpp"
#include "utils/nt.hpp"
#include "steam/steam.hpp"
#include "steam/interface.hpp"
#include "utils/string.hpp"
class steam_proxy final : public module
{
public:
void post_start() override
{
if (game::is_dedi()) return;
this->run_mod();
this->load_client();
}
void pre_destroy() override
{
}
private:
utils::nt::module steam_client_module_;
void run_mod()
{
const char* command = "-proc ";
const char* parent_proc = strstr(GetCommandLineA(), command);
if (parent_proc)
{
const int pid = atoi(parent_proc + strlen(command));
const HANDLE process_handle = OpenProcess(SYNCHRONIZE, FALSE, pid);
if (process_handle && process_handle != INVALID_HANDLE_VALUE)
{
WaitForSingleObject(process_handle, INFINITE);
CloseHandle(process_handle);
}
module_loader::trigger_premature_shutdown();
}
}
void* load_client_engine()
{
if (!this->steam_client_module_.is_valid()) return nullptr;
for(int i = 1;; ++i)
{
std::string name = utils::string::va("CLIENTENGINE_INTERFACE_VERSION%03i", i);
void* client_engine = this->steam_client_module_.invoke<void*>("CreateInterface", name.data(), nullptr);
if (client_engine) return client_engine;
}
}
void load_client()
{
const auto steam_path = ::steam::get_steam_install_directory();
if (steam_path.empty()) return;
SetDllDirectoryA(steam_path.data());
this->steam_client_module_ = utils::nt::module::load("steamclient.dll");
if (!this->steam_client_module_.is_valid()) return;
steam::interface steam_client = this->steam_client_module_.invoke<void*>("CreateInterface", "SteamClient008", nullptr);
steam::interface client_engine = load_client_engine();
const auto pipe = steam_client.invoke<void*>(0); // CreateSteamPipe
const auto gobal_user = steam_client.invoke<void*>(2, pipe); // ConnectToGlobalUser
}
};
//REGISTER_MODULE(steam_proxy)

95
src/steam/interface.cpp Normal file
View File

@ -0,0 +1,95 @@
#include <std_include.hpp>
#include "interface.hpp"
#include "utils/memory.hpp"
namespace steam
{
interface::interface(void* interface_ptr) : interface_ptr_(static_cast<void***>(interface_ptr))
{
}
interface::method interface::find_method(const std::string& name)
{
const auto method_entry = this->methods_.find(name);
if(method_entry != this->methods_.end())
{
return method_entry->second;
}
return this->search_method(name);
}
interface::method interface::search_method(const std::string& name)
{
if (!utils::memory::is_bad_read_ptr(this->interface_ptr_))
{
auto vftbl = *this->interface_ptr_;
while (!utils::memory::is_bad_read_ptr(vftbl) && !utils::memory::is_bad_code_ptr(*vftbl))
{
const interface::method_result result = this->analyze_method(*vftbl);
if (!result.valid) break;
const interface::method method_result{ *vftbl, result.param_size };
this->methods_[result.name] = method_result;
if(result.name == name)
{
return method_result;
}
++vftbl;
}
}
return {};
}
interface::method_result interface::analyze_method(const void* method_ptr)
{
interface::method_result result;
if (utils::memory::is_bad_code_ptr(method_ptr)) return result;
ud_t ud;
ud_init(&ud);
ud_set_mode(&ud, 32);
ud_set_pc(&ud, uint64_t(method_ptr));
ud_set_input_buffer(&ud, static_cast<const uint8_t*>(method_ptr), INT32_MAX);
while (true)
{
ud_disassemble(&ud);
if (ud_insn_mnemonic(&ud) == UD_Iret)
{
const ud_operand* operand = ud_insn_opr(&ud, 0);
if (!operand) break;
if (operand->type == UD_OP_IMM && operand->size == 16)
{
result.param_size = operand->lval.uword;
result.valid = !result.name.empty();
return result;
}
break;
}
if (ud_insn_mnemonic(&ud) == UD_Ipush && result.name.empty())
{
const auto operand = ud_insn_opr(&ud, 0);
if (operand->type == UD_OP_IMM && operand->size == 32)
{
char* operand_ptr = reinterpret_cast<char*>(operand->lval.udword);
if (!utils::memory::is_bad_read_ptr(operand_ptr))
{
result.name = operand_ptr;
}
}
}
}
return result;
}
}

66
src/steam/interface.hpp Normal file
View File

@ -0,0 +1,66 @@
#pragma once
#ifdef interface
#undef interface
#endif
namespace steam
{
class interface final
{
public:
class method final
{
public:
void* pointer = nullptr;
size_t param_size = 0;
};
class method_result final
{
public:
bool valid = false;
std::string name;
size_t param_size = 0;
};
interface(void* interface_ptr);
template<typename T, typename... Args>
T invoke(const std::string& method_name, Args... args)
{
if(!this->interface_ptr_)
{
throw std::runtime_error("Invalid interface pointer");
}
const auto method_result = this->find_method(method_name);
if(!method_result.pointer)
{
throw std::runtime_error("Unable to find desired method");
}
return reinterpret_cast<T(__thiscall*)(void*, Args ...)>(method_result.pointer)(this->interface_ptr_, args...);
}
template<typename T, typename... Args>
T invoke(size_t table_entry, Args... args)
{
if (!this->interface_ptr_)
{
throw std::runtime_error("Invalid interface pointer");
}
return reinterpret_cast<T(__thiscall*)(void*, Args ...)>((*this->interface_ptr_)[table_entry])(this->interface_ptr_, args...);
}
private:
void*** interface_ptr_;
std::unordered_map<std::string, method> methods_;
method find_method(const std::string& name);
method search_method(const std::string& name);
method_result analyze_method(const void* method_ptr);
};
}

View File

@ -77,6 +77,30 @@ namespace steam
results_.clear();
}
std::string get_steam_install_directory()
{
HKEY reg_key;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", 0, KEY_QUERY_VALUE, &reg_key) ==
ERROR_SUCCESS)
{
char path[MAX_PATH] = { 0 };
DWORD length = sizeof(path);
RegQueryValueExA(reg_key, "InstallPath", nullptr, nullptr, reinterpret_cast<BYTE*>(path),
&length);
RegCloseKey(reg_key);
std::string steam_path = path;
if (steam_path.back() != '\\' && steam_path.back() != '/')
{
steam_path.push_back('\\');
}
return steam_path;
}
return {};
}
extern "C" {
bool SteamAPI_RestartAppIfNecessary()
{
@ -89,24 +113,10 @@ namespace steam
if (!overlay)
{
HKEY reg_key;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", 0, KEY_QUERY_VALUE, &reg_key) ==
ERROR_SUCCESS)
const auto steam_path = get_steam_install_directory();
if(!steam_path.empty())
{
char steam_path[MAX_PATH] = {0};
DWORD length = sizeof(steam_path);
RegQueryValueExA(reg_key, "InstallPath", nullptr, nullptr, reinterpret_cast<BYTE*>(steam_path),
&length);
RegCloseKey(reg_key);
std::string overlay_path = steam_path;
if (overlay_path.back() != '\\' && overlay_path.back() != '/')
{
overlay_path.push_back('\\');
}
overlay_path.append("gameoverlayrenderer.dll");
overlay = ::utils::nt::module::load(overlay_path);
overlay = ::utils::nt::module::load(steam_path + "gameoverlayrenderer.dll");
}
}

View File

@ -101,5 +101,7 @@ namespace steam
STEAM_EXPORT apps* SteamApps();
STEAM_EXPORT user_stats* SteamUserStats();
std::string get_steam_install_directory();
extern ::utils::nt::module overlay;
}