t7x/src/client/main.cpp

254 lines
6.6 KiB
C++
Raw Normal View History

2022-05-21 06:04:08 -04:00
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include <utils/finally.hpp>
#include <utils/hook.hpp>
#include <utils/nt.hpp>
2022-06-26 04:07:46 -04:00
#include <utils/io.hpp>
#include <steam/steam.hpp>
2022-05-21 06:04:08 -04:00
namespace
{
2022-06-26 04:07:46 -04:00
std::pair<void**, void*> g_original_import{};
2022-09-17 06:19:59 -04:00
DECLSPEC_NORETURN void WINAPI exit_hook(const uint32_t code)
2022-05-23 11:57:45 -04:00
{
component_loader::pre_destroy();
2022-09-17 06:19:59 -04:00
ExitProcess(code);
2022-05-23 11:57:45 -04:00
}
2022-05-21 06:04:08 -04:00
2022-06-26 04:07:46 -04:00
std::pair<void**, void*> patch_steam_import(const std::string& func, void* function)
2022-05-21 06:04:08 -04:00
{
2022-06-26 04:07:46 -04:00
static const utils::nt::library game{};
2022-05-23 11:57:45 -04:00
2022-06-26 04:07:46 -04:00
const auto game_entry = game.get_iat_entry("steam_api64.dll", func);
if (!game_entry)
2022-05-21 06:04:08 -04:00
{
2022-06-26 04:07:46 -04:00
throw std::runtime_error("Import '" + func + "' not found!");
}
2022-05-21 06:04:08 -04:00
2022-06-26 04:07:46 -04:00
const auto original_import = game_entry;
utils::hook::set(game_entry, function);
return {game_entry, original_import};
}
bool restart_app_if_necessary_stub()
{
const std::string steam_path = steam::SteamAPI_GetSteamInstallPath();
if (steam_path.empty() || !::utils::io::file_exists(steam_path + "/steam.exe"))
{
MessageBoxA(nullptr, "Steam must be installed for the game to run. Please install Steam!", "Error",
MB_ICONERROR);
ShellExecuteA(nullptr, "open", "https://store.steampowered.com/about/", nullptr, nullptr, SW_SHOWNORMAL);
TerminateProcess(GetCurrentProcess(), 1);
}
utils::hook::set(g_original_import.first, g_original_import.second);
patch_steam_import("SteamAPI_Shutdown", steam::SteamAPI_Shutdown);
component_loader::post_unpack();
return steam::SteamAPI_RestartAppIfNecessary();
}
void patch_imports()
{
patch_steam_import("SteamAPI_RegisterCallback", steam::SteamAPI_RegisterCallback);
patch_steam_import("SteamAPI_RegisterCallResult", steam::SteamAPI_RegisterCallResult);
patch_steam_import("SteamGameServer_Shutdown", steam::SteamGameServer_Shutdown);
patch_steam_import("SteamGameServer_RunCallbacks", steam::SteamGameServer_RunCallbacks);
patch_steam_import("SteamGameServer_GetHSteamPipe", steam::SteamGameServer_GetHSteamPipe);
patch_steam_import("SteamGameServer_GetHSteamUser", steam::SteamGameServer_GetHSteamUser);
patch_steam_import("SteamInternal_GameServer_Init", steam::SteamInternal_GameServer_Init);
patch_steam_import("SteamAPI_UnregisterCallResult", steam::SteamAPI_UnregisterCallResult);
patch_steam_import("SteamAPI_UnregisterCallback", steam::SteamAPI_UnregisterCallback);
patch_steam_import("SteamAPI_RunCallbacks", steam::SteamAPI_RunCallbacks);
patch_steam_import("SteamInternal_CreateInterface", steam::SteamInternal_CreateInterface);
patch_steam_import("SteamAPI_GetHSteamUser", steam::SteamAPI_GetHSteamUser);
patch_steam_import("SteamAPI_GetHSteamPipe", steam::SteamAPI_GetHSteamPipe);
patch_steam_import("SteamAPI_Init", steam::SteamAPI_Init);
//patch_steam_import("SteamAPI_Shutdown", steam::SteamAPI_Shutdown);
g_original_import = patch_steam_import("SteamAPI_RestartAppIfNecessary", restart_app_if_necessary_stub);
utils::hook::set(utils::nt::library{}.get_iat_entry("kernel32.dll", "ExitProcess"), exit_hook);
2022-05-23 11:57:45 -04:00
}
2022-05-21 06:04:08 -04:00
2022-09-18 02:48:12 -04:00
void remove_crash_file()
{
const utils::nt::library game{};
const auto game_file = game.get_path();
auto game_path = std::filesystem::path(game_file);
game_path.replace_extension(".start");
utils::io::remove_file(game_path.generic_string());
}
2022-05-23 11:57:45 -04:00
bool run()
{
2022-05-27 13:08:39 -04:00
srand(uint32_t(time(nullptr)) ^ ~(GetTickCount() * GetCurrentProcessId()));
2022-05-23 11:57:45 -04:00
{
auto premature_shutdown = true;
const auto _ = utils::finally([&premature_shutdown]()
{
if (premature_shutdown)
{
component_loader::pre_destroy();
}
});
try
{
patch_imports();
2022-09-18 02:48:12 -04:00
remove_crash_file();
2022-05-23 11:57:45 -04:00
2022-05-29 10:46:49 -04:00
if (!component_loader::pre_start())
2022-05-23 11:57:45 -04:00
{
return false;
}
premature_shutdown = false;
}
catch (std::exception& e)
{
MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR);
return false;
}
}
return true;
}
class patch
{
public:
patch() = default;
2022-05-30 13:06:59 -04:00
patch(void* source, void* target)
: source_(source)
{
memcpy(this->data_, source, sizeof(this->data_));
utils::hook::jump(this->source_, target, true, true);
}
~patch()
{
if (source_)
{
utils::hook::copy(this->source_, this->data_, sizeof(this->data_));
}
}
patch(patch&& obj) noexcept
: patch()
{
this->operator=(std::move(obj));
}
patch& operator=(patch&& obj) noexcept
{
if (this != &obj)
{
this->~patch();
this->source_ = obj.source_;
memcpy(this->data_, obj.data_, sizeof(this->data_));
obj.source_ = nullptr;
}
return *this;
}
private:
2022-05-30 13:06:59 -04:00
void* source_{nullptr};
uint8_t data_[15]{};
};
std::vector<patch> initialization_hooks{};
uint8_t* get_entry_point()
{
const utils::nt::library game{};
return game.get_ptr() + game.get_optional_header()->AddressOfEntryPoint;
}
std::vector<uint8_t*> get_tls_callbacks()
{
const utils::nt::library game{};
const auto& entry = game.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
2022-05-30 13:06:59 -04:00
if (!entry.VirtualAddress || !entry.Size)
{
return {};
}
const auto* tls_dir = reinterpret_cast<IMAGE_TLS_DIRECTORY*>(game.get_ptr() + entry.VirtualAddress);
auto* callback = reinterpret_cast<uint8_t**>(tls_dir->AddressOfCallBacks);
std::vector<uint8_t*> addresses{};
2022-05-30 13:06:59 -04:00
while (callback && *callback)
{
addresses.emplace_back(*callback);
++callback;
}
return addresses;
}
int patch_main()
{
2022-05-30 13:06:59 -04:00
if (!run())
{
return 1;
}
2022-05-29 12:23:52 -04:00
initialization_hooks.clear();
return reinterpret_cast<int(*)()>(get_entry_point())();
}
void nullsub()
{
}
void patch_entry_point()
{
initialization_hooks.emplace_back(get_entry_point(), patch_main);
2022-05-30 13:06:59 -04:00
for (auto* tls_callback : get_tls_callbacks())
{
initialization_hooks.emplace_back(tls_callback, nullsub);
}
}
2022-05-21 06:04:08 -04:00
}
BOOL WINAPI DllMain(HINSTANCE, const DWORD reason, LPVOID)
{
2022-05-23 11:57:45 -04:00
if (reason == DLL_PROCESS_ATTACH)
{
patch_entry_point();
2022-05-23 11:57:45 -04:00
}
2022-05-29 10:46:49 -04:00
2022-05-23 11:57:45 -04:00
return TRUE;
2022-05-21 06:04:08 -04:00
}
extern "C" __declspec(dllexport)
2022-05-23 11:57:45 -04:00
HRESULT D3D11CreateDevice(void* adapter, const uint64_t driver_type,
const HMODULE software, const UINT flags,
const void* p_feature_levels, const UINT feature_levels,
const UINT sdk_version, void** device, void* feature_level,
void** immediate_context)
2022-05-21 06:04:08 -04:00
{
2022-05-23 11:57:45 -04:00
static auto func = []
{
char dir[MAX_PATH]{0};
GetSystemDirectoryA(dir, sizeof(dir));
2022-05-21 06:04:08 -04:00
2022-05-23 11:57:45 -04:00
const auto d3d11 = utils::nt::library::load(dir + "/d3d11.dll"s);
return d3d11.get_proc<decltype(&D3D11CreateDevice)>("D3D11CreateDevice");
}();
2022-05-21 06:04:08 -04:00
2022-05-23 11:57:45 -04:00
return func(adapter, driver_type, software, flags, p_feature_levels, feature_levels, sdk_version, device,
feature_level, immediate_context);
2022-05-21 06:04:08 -04:00
}