Prepare steam proxy
This commit is contained in:
parent
7b2698561b
commit
83c070f13b
@ -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();
|
||||
}
|
||||
|
@ -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_;
|
||||
|
||||
|
68
src/main.cpp
68
src/main.cpp
@ -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();
|
||||
}
|
||||
|
@ -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)
|
79
src/module/steam_proxy.cpp
Normal file
79
src/module/steam_proxy.cpp
Normal 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
95
src/steam/interface.cpp
Normal 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
66
src/steam/interface.hpp
Normal 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);
|
||||
};
|
||||
}
|
@ -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, ®_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, ®_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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user