diff --git a/src/game/demonware/services/bdStorage.cpp b/src/game/demonware/services/bdStorage.cpp index 4fc8f33..a0a5210 100644 --- a/src/game/demonware/services/bdStorage.cpp +++ b/src/game/demonware/services/bdStorage.cpp @@ -32,7 +32,7 @@ namespace demonware void bdStorage::map_publisher_resource(const std::string& expression, const INT id) { - const auto res = FindResource(::utils::nt::module(), MAKEINTRESOURCE(id), RT_RCDATA); + const auto res = FindResource(::utils::nt::library(), MAKEINTRESOURCE(id), RT_RCDATA); if (!res) return; const auto handle = LoadResource(nullptr, res); diff --git a/src/launcher/html/html_frame.cpp b/src/launcher/html/html_frame.cpp index 8e85682..7649240 100644 --- a/src/launcher/html/html_frame.cpp +++ b/src/launcher/html/html_frame.cpp @@ -170,7 +170,7 @@ void html_frame::set_browser_feature(const std::string& feature, DWORD value) KEY_ALL_ACCESS, &key) != ERROR_SUCCESS) return; - const utils::nt::module self; + const utils::nt::library self; const auto name = self.get_name(); RegSetValueExA(key, name.data(), 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); diff --git a/src/launcher/launcher.cpp b/src/launcher/launcher.cpp index ba635c2..4fc0fbb 100644 --- a/src/launcher/launcher.cpp +++ b/src/launcher/launcher.cpp @@ -64,7 +64,7 @@ void launcher::select_mode(const mode mode) std::string launcher::load_content(const int res) { - const auto resource = FindResource(utils::nt::module(), MAKEINTRESOURCE(res), RT_RCDATA); + const auto resource = FindResource(utils::nt::library(), MAKEINTRESOURCE(res), RT_RCDATA); if (!resource) return {}; const auto handle = LoadResource(nullptr, resource); diff --git a/src/loader/binary_loader.cpp b/src/loader/binary_loader.cpp index 37c143c..7d25cd3 100644 --- a/src/loader/binary_loader.cpp +++ b/src/loader/binary_loader.cpp @@ -12,7 +12,7 @@ namespace binary_loader { std::string load_resource(const int id) { - const auto res = FindResource(::utils::nt::module(), MAKEINTRESOURCE(id), RT_RCDATA); + const auto res = FindResource(::utils::nt::library(), MAKEINTRESOURCE(id), RT_RCDATA); if (!res) return {}; const auto handle = LoadResource(nullptr, res); diff --git a/src/loader/loader.cpp b/src/loader/loader.cpp index 4d6682a..38089ae 100644 --- a/src/loader/loader.cpp +++ b/src/loader/loader.cpp @@ -7,12 +7,12 @@ loader::loader(const launcher::mode mode) : mode_(mode) { } -FARPROC loader::load(const utils::nt::module& module) const +FARPROC loader::load(const utils::nt::library& module) const { const auto buffer = binary_loader::load(this->mode_); if (buffer.empty()) return nullptr; - const utils::nt::module source(HMODULE(buffer.data())); + const utils::nt::library source(HMODULE(buffer.data())); if (!source) return nullptr; this->load_sections(module, source); @@ -69,7 +69,7 @@ void loader::set_import_resolver(const std::functionimport_resolver_ = resolver; } -void loader::load_section(const utils::nt::module& target, const utils::nt::module& source, +void loader::load_section(const utils::nt::library& target, const utils::nt::library& source, IMAGE_SECTION_HEADER* section) { void* target_ptr = target.get_ptr() + section->VirtualAddress; @@ -90,7 +90,7 @@ void loader::load_section(const utils::nt::module& target, const utils::nt::modu } } -void loader::load_sections(const utils::nt::module& target, const utils::nt::module& source) const +void loader::load_sections(const utils::nt::library& target, const utils::nt::library& source) const { for (auto& section : source.get_section_headers()) { @@ -98,7 +98,7 @@ void loader::load_sections(const utils::nt::module& target, const utils::nt::mod } } -void loader::load_imports(const utils::nt::module& target, const utils::nt::module& source) const +void loader::load_imports(const utils::nt::library& target, const utils::nt::library& source) const { const auto import_directory = &source.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; @@ -124,7 +124,7 @@ void loader::load_imports(const utils::nt::module& target, const utils::nt::modu // is this an ordinal-only import? if (IMAGE_SNAP_BY_ORDINAL(*name_table_entry)) { - auto module = utils::nt::module::load(name); + auto module = utils::nt::library::load(name); if (module) { function = GetProcAddress(module, MAKEINTRESOURCEA(IMAGE_ORDINAL(*name_table_entry))); @@ -140,7 +140,7 @@ void loader::load_imports(const utils::nt::module& target, const utils::nt::modu if (this->import_resolver_) function = this->import_resolver_(name, function_name); if (!function) { - auto module = utils::nt::module::load(name); + auto module = utils::nt::library::load(name); if (module) { function = GetProcAddress(module, function_name.data()); diff --git a/src/loader/loader.hpp b/src/loader/loader.hpp index b95f1fa..10307b3 100644 --- a/src/loader/loader.hpp +++ b/src/loader/loader.hpp @@ -7,7 +7,7 @@ class loader final public: explicit loader(launcher::mode mode); - FARPROC load(const utils::nt::module& module) const; + FARPROC load(const utils::nt::library& module) const; void set_import_resolver(const std::function& resolver); @@ -15,8 +15,8 @@ private: launcher::mode mode_; std::function import_resolver_; - static void load_section(const utils::nt::module& target, const utils::nt::module& source, + static void load_section(const utils::nt::library& target, const utils::nt::library& source, IMAGE_SECTION_HEADER* section); - void load_sections(const utils::nt::module& target, const utils::nt::module& source) const; - void load_imports(const utils::nt::module& target, const utils::nt::module& source) const; + void load_sections(const utils::nt::library& target, const utils::nt::library& source) const; + void load_imports(const utils::nt::library& target, const utils::nt::library& source) const; }; diff --git a/src/main.cpp b/src/main.cpp index 081b6f6..293fc3d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,7 +20,7 @@ DECLSPEC_NORETURN void WINAPI exit_hook(const int code) void verify_tls() { - const utils::nt::module self; + const utils::nt::library self; const auto self_tls = reinterpret_cast(self.get_ptr() + self.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); @@ -59,7 +59,7 @@ launcher::mode detect_mode_from_arguments() FARPROC load_binary(const launcher::mode mode) { loader loader(mode); - utils::nt::module self; + utils::nt::library self; loader.set_import_resolver([self](const std::string& module, const std::string& function) -> FARPROC { diff --git a/src/module/dw.cpp b/src/module/dw.cpp index 7985f58..b68c45b 100644 --- a/src/module/dw.cpp +++ b/src/module/dw.cpp @@ -144,7 +144,7 @@ namespace demonware bool register_hook(const std::string& process, void* stub) { - const utils::nt::module main; + const utils::nt::library main; auto result = false; result = result || utils::hook::iat(main, "wsock32.dll", process, stub); diff --git a/src/module/game_launcher.cpp b/src/module/game_launcher.cpp index 7850fa5..65e1496 100644 --- a/src/module/game_launcher.cpp +++ b/src/module/game_launcher.cpp @@ -36,7 +36,7 @@ private: static void launch_game(const bool singleplayer) { - const utils::nt::module self; + const utils::nt::library self; STARTUPINFOA s_info; PROCESS_INFORMATION p_info; diff --git a/src/module/steam_proxy.cpp b/src/module/steam_proxy.cpp index c5a0f32..86d20f0 100644 --- a/src/module/steam_proxy.cpp +++ b/src/module/steam_proxy.cpp @@ -57,7 +57,7 @@ public: } private: - utils::nt::module steam_client_module_; + utils::nt::library steam_client_module_; steam::interface client_engine_; steam::interface client_user_; @@ -105,9 +105,9 @@ private: const auto steam_path = ::steam::get_steam_install_directory(); if (steam_path.empty()) return; - utils::nt::module::load(steam_path + "tier0_s.dll"); - utils::nt::module::load(steam_path + "vstdlib_s.dll"); - this->steam_client_module_ = utils::nt::module::load(steam_path + "steamclient.dll"); + utils::nt::library::load(steam_path + "tier0_s.dll"); + utils::nt::library::load(steam_path + "vstdlib_s.dll"); + this->steam_client_module_ = utils::nt::library::load(steam_path + "steamclient.dll"); if (!this->steam_client_module_) return; this->client_engine_ = load_client_engine(); @@ -130,7 +130,7 @@ private: this->client_utils_.invoke("SetAppIDForCurrentPipe", app_id, false); - const utils::nt::module self; + const utils::nt::library self; const auto path = self.get_path(); char our_directory[MAX_PATH] = {0}; @@ -168,7 +168,7 @@ private: this->steam_pipe_ = nullptr; this->global_user_ = nullptr; - this->steam_client_module_ = utils::nt::module{nullptr}; + this->steam_client_module_ = utils::nt::library{nullptr}; } }; diff --git a/src/steam/interface.cpp b/src/steam/interface.cpp index 244cccd..74e0d11 100644 --- a/src/steam/interface.cpp +++ b/src/steam/interface.cpp @@ -109,7 +109,7 @@ namespace steam bool interface::is_rdata(void* pointer) { - const auto pointer_lib = utils::nt::module::get_by_address(pointer); + const auto pointer_lib = utils::nt::library::get_by_address(pointer); for (const auto& section : pointer_lib.get_section_headers()) { diff --git a/src/steam/steam.cpp b/src/steam/steam.cpp index 25fa293..642b1f2 100644 --- a/src/steam/steam.cpp +++ b/src/steam/steam.cpp @@ -3,7 +3,7 @@ namespace steam { - ::utils::nt::module overlay(nullptr); + ::utils::nt::library overlay(nullptr); uint64_t callbacks::call_id_ = 0; std::recursive_mutex callbacks::mutex_; @@ -107,14 +107,14 @@ namespace steam bool SteamAPI_Init() { - overlay = ::utils::nt::module("gameoverlayrenderer.dll"); + overlay = ::utils::nt::library("gameoverlayrenderer.dll"); if (!overlay) { const auto steam_path = get_steam_install_directory(); if (!steam_path.empty()) { - overlay = ::utils::nt::module::load(steam_path + "gameoverlayrenderer.dll"); + overlay = ::utils::nt::library::load(steam_path + "gameoverlayrenderer.dll"); } } diff --git a/src/steam/steam.hpp b/src/steam/steam.hpp index 688d21c..91f4809 100644 --- a/src/steam/steam.hpp +++ b/src/steam/steam.hpp @@ -120,5 +120,5 @@ namespace steam std::string get_steam_install_directory(); - extern ::utils::nt::module overlay; + extern ::utils::nt::library overlay; } diff --git a/src/utils/hook.cpp b/src/utils/hook.cpp index aaeaea6..7902ecd 100644 --- a/src/utils/hook.cpp +++ b/src/utils/hook.cpp @@ -113,7 +113,7 @@ namespace utils } } - bool hook::iat(const nt::module module, const std::string& target_module, const std::string& process, void* stub) + bool hook::iat(const nt::library module, const std::string& target_module, const std::string& process, void* stub) { if (!module.is_valid()) return false; diff --git a/src/utils/hook.hpp b/src/utils/hook.hpp index 2702991..f35d25b 100644 --- a/src/utils/hook.hpp +++ b/src/utils/hook.hpp @@ -83,7 +83,7 @@ namespace utils void* get_original() const; void quick(); - static bool iat(nt::module module, const std::string& target_module, const std::string& process, void* stub); + static bool iat(nt::library module, const std::string& target_module, const std::string& process, void* stub); static void nop(void* place, size_t length); static void nop(DWORD place, size_t length); diff --git a/src/utils/nt.cpp b/src/utils/nt.cpp index be87d6c..77df056 100644 --- a/src/utils/nt.cpp +++ b/src/utils/nt.cpp @@ -3,66 +3,71 @@ namespace utils::nt { - module module::load(const std::string& name) + library library::load(const std::string& name) { - return module(LoadLibraryA(name.data())); + return library(LoadLibraryA(name.data())); } - module module::get_by_address(void* address) + library library::load(const std::filesystem::path& path) + { + return library::load(path.generic_string()); + } + + library library::get_by_address(void* address) { HMODULE handle = nullptr; - GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast(address), &handle); - return module(handle); + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, static_cast(address), &handle); + return library(handle); } - module::module() + library::library() { this->module_ = GetModuleHandleA(nullptr); } - module::module(const std::string& name) + library::library(const std::string& name) { this->module_ = GetModuleHandleA(name.data()); } - module::module(const HMODULE handle) + library::library(const HMODULE handle) { this->module_ = handle; } - bool module::operator==(const module& obj) const + bool library::operator==(const library& obj) const { return this->module_ == obj.module_; } - module::operator bool() const + library::operator bool() const { return this->is_valid(); } - module::operator HMODULE() const + library::operator HMODULE() const { return this->get_handle(); } - PIMAGE_NT_HEADERS module::get_nt_headers() const + PIMAGE_NT_HEADERS library::get_nt_headers() const { if (!this->is_valid()) return nullptr; return reinterpret_cast(this->get_ptr() + this->get_dos_header()->e_lfanew); } - PIMAGE_DOS_HEADER module::get_dos_header() const + PIMAGE_DOS_HEADER library::get_dos_header() const { return reinterpret_cast(this->get_ptr()); } - PIMAGE_OPTIONAL_HEADER module::get_optional_header() const + PIMAGE_OPTIONAL_HEADER library::get_optional_header() const { if (!this->is_valid()) return nullptr; return &this->get_nt_headers()->OptionalHeader; } - std::vector module::get_section_headers() const + std::vector library::get_section_headers() const { std::vector headers; @@ -78,12 +83,12 @@ namespace utils::nt return headers; } - std::uint8_t* module::get_ptr() const + std::uint8_t* library::get_ptr() const { return reinterpret_cast(this->module_); } - void module::unprotect() const + void library::unprotect() const { if (!this->is_valid()) return; @@ -92,24 +97,24 @@ namespace utils::nt &protection); } - size_t module::get_relative_entry_point() const + size_t library::get_relative_entry_point() const { if (!this->is_valid()) return 0; return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint; } - void* module::get_entry_point() const + void* library::get_entry_point() const { if (!this->is_valid()) return nullptr; return this->get_ptr() + this->get_relative_entry_point(); } - bool module::is_valid() const + bool library::is_valid() const { return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE; } - std::string module::get_name() const + std::string library::get_name() const { if (!this->is_valid()) return ""; @@ -120,7 +125,7 @@ namespace utils::nt return path.substr(pos + 1); } - std::string module::get_path() const + std::string library::get_path() const { if (!this->is_valid()) return ""; @@ -130,7 +135,15 @@ namespace utils::nt return name; } - void module::free() + std::string library::get_folder() const + { + if (!this->is_valid()) return ""; + + const auto path = std::filesystem::path(this->get_path()); + return path.parent_path().generic_string(); + } + + void library::free() { if (this->is_valid()) { @@ -139,19 +152,19 @@ namespace utils::nt } } - HMODULE module::get_handle() const + HMODULE library::get_handle() const { return this->module_; } - void** module::get_iat_entry(const std::string& module_name, const std::string& proc_name) const + void** library::get_iat_entry(const std::string& module_name, const std::string& proc_name) const { if (!this->is_valid()) return nullptr; - const module other_module(module_name); + const library other_module(module_name); if (!other_module.is_valid()) return nullptr; - const auto target_function = other_module.get_proc(proc_name); + auto* const target_function = other_module.get_proc(proc_name); if (!target_function) return nullptr; auto* header = this->get_optional_header(); @@ -197,8 +210,46 @@ namespace utils::nt void raise_hard_exception() { int data = false; - const module ntdll("ntdll.dll"); + const library ntdll("ntdll.dll"); ntdll.invoke_pascal("RtlAdjustPrivilege", 19, true, false, &data); ntdll.invoke_pascal("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data); } + + std::string load_resource(const int id) + { + auto* const res = FindResource(library(), MAKEINTRESOURCE(id), RT_RCDATA); + if (!res) return {}; + + auto* const handle = LoadResource(nullptr, res); + if (!handle) return {}; + + return std::string(LPSTR(LockResource(handle)), SizeofResource(nullptr, res)); + } + + void relaunch_self() + { + const utils::nt::library self; + + STARTUPINFOA startup_info; + PROCESS_INFORMATION process_info; + + ZeroMemory(&startup_info, sizeof(startup_info)); + ZeroMemory(&process_info, sizeof(process_info)); + startup_info.cb = sizeof(startup_info); + + char current_dir[MAX_PATH]; + GetCurrentDirectoryA(sizeof(current_dir), current_dir); + auto* const command_line = GetCommandLineA(); + + CreateProcessA(self.get_path().data(), command_line, nullptr, nullptr, false, NULL, nullptr, current_dir, + &startup_info, &process_info); + + if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) CloseHandle(process_info.hThread); + if (process_info.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) CloseHandle(process_info.hProcess); + } + + void terminate(const uint32_t code) + { + TerminateProcess(GetCurrentProcess(), code); + } } diff --git a/src/utils/nt.hpp b/src/utils/nt.hpp index 0f52ed2..b42ba41 100644 --- a/src/utils/nt.hpp +++ b/src/utils/nt.hpp @@ -2,22 +2,23 @@ namespace utils::nt { - class module final + class library final { public: - static module load(const std::string& name); - static module get_by_address(void* address); + static library load(const std::string& name); + static library load(const std::filesystem::path& path); + static library get_by_address(void* address); - module(); - explicit module(const std::string& name); - explicit module(HMODULE handle); + library(); + explicit library(const std::string& name); + explicit library(HMODULE handle); - module(const module& a) : module_(a.module_) + library(const library& a) : module_(a.module_) { } - bool operator!=(const module& obj) const { return !(*this == obj); }; - bool operator==(const module& obj) const; + bool operator!=(const library& obj) const { return !(*this == obj); }; + bool operator==(const library& obj) const; operator bool() const; operator HMODULE() const; @@ -29,6 +30,7 @@ namespace utils::nt bool is_valid() const; std::string get_name() const; std::string get_path() const; + std::string get_folder() const; std::uint8_t* get_ptr() const; void free(); @@ -44,7 +46,7 @@ namespace utils::nt template std::function get(const std::string& process) const { - if (!this->is_valid()) std::function(); + if (!this->is_valid()) return std::function(); return static_cast(this->get_proc(process)); } @@ -84,5 +86,9 @@ namespace utils::nt HMODULE module_; }; - void raise_hard_exception(); + __declspec(noreturn) void raise_hard_exception(); + std::string load_resource(int id); + + void relaunch_self(); + __declspec(noreturn) void terminate(uint32_t code = 0); }