diff --git a/src/client/component/arxan.cpp b/src/client/component/arxan.cpp index f4a44654..069e2021 100644 --- a/src/client/component/arxan.cpp +++ b/src/client/component/arxan.cpp @@ -696,9 +696,8 @@ namespace arxan return zw_terminate_process_hook.invoke(process_handle, exit_status); } - class component final : public component_interface + struct component final : component_interface { - public: void post_load() override { auto* dll_characteristics = &utils::nt::library().get_optional_header()->DllCharacteristics; diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 11c80085..8b226d29 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -107,9 +107,8 @@ namespace auth return guid; } - class component final : public component_interface + struct component final : client_component_interface { - public: void post_unpack() override { // Patch steam id bit check diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp index 10a5b9a7..ff6e41ae 100644 --- a/src/client/component/bots.cpp +++ b/src/client/component/bots.cpp @@ -41,9 +41,8 @@ namespace bots } } - class component final : public component_interface + struct component final : client_component_interface { - public: void post_unpack() override { utils::hook::jump(0x141653B70_g, get_bot_name); diff --git a/src/client/component/branding.cpp b/src/client/component/branding.cpp index 72b23f52..a57edad4 100644 --- a/src/client/component/branding.cpp +++ b/src/client/component/branding.cpp @@ -27,9 +27,8 @@ namespace branding } } - class component final : public component_interface + struct component final : client_component_interface { - public: void post_unpack() override { scheduler::loop(draw_branding, scheduler::renderer); diff --git a/src/client/component/colors.cpp b/src/client/component/colors.cpp index 95299e3c..79913e96 100644 --- a/src/client/component/colors.cpp +++ b/src/client/component/colors.cpp @@ -30,9 +30,8 @@ namespace colors utils::hook::copy(g_color_table + index * 4, color_float, sizeof(color_float)); } - class component final : public component_interface + struct component final : client_component_interface { - public: void post_unpack() override { patch_color<1>(255, 49, 49); // 1 - Red diff --git a/src/client/component/command.cpp b/src/client/component/command.cpp index 72889d4a..aa01ae5b 100644 --- a/src/client/component/command.cpp +++ b/src/client/component/command.cpp @@ -46,9 +46,8 @@ namespace command } } - class component final : public component_interface + struct component final : client_component_interface { - public: void post_unpack() override { // Disable whitelist diff --git a/src/client/component/console.cpp b/src/client/component/console.cpp index 43d3e096..18ff80f1 100644 --- a/src/client/component/console.cpp +++ b/src/client/component/console.cpp @@ -193,9 +193,8 @@ namespace console } } - class component final : public component_interface + struct component final : client_component_interface { - public: void post_unpack() override { utils::hook::set(0x14133D2FE_g, 0xEB); // Always enable ingame console diff --git a/src/client/component/dedicated.cpp b/src/client/component/dedicated.cpp index 7f2ebd58..70431910 100644 --- a/src/client/component/dedicated.cpp +++ b/src/client/component/dedicated.cpp @@ -9,9 +9,8 @@ namespace dedicated { } - class component final : public component_interface + struct component final : server_component_interface { - public: void post_unpack() override { } diff --git a/src/client/component/demonware.cpp b/src/client/component/demonware.cpp index 3e31c656..c9e9d622 100644 --- a/src/client/component/demonware.cpp +++ b/src/client/component/demonware.cpp @@ -441,9 +441,8 @@ namespace demonware } } - class component final : public component_interface + struct component final : component_interface { - public: component() { udp_servers.create("stun.us.demonware.net"); @@ -477,6 +476,11 @@ namespace demonware { server_thread = utils::thread::create_named_thread("Demonware", server_main); + if (game::is_server()) + { + return; + } + utils::hook::set(0x14293E829_g, 0x0); // CURLOPT_SSL_VERIFYPEER utils::hook::set(0x15F3CCFED_g, 0xAF); // CURLOPT_SSL_VERIFYHOST utils::hook::set(0x1430B9810_g, 0x0); // HTTPS -> HTTP @@ -489,7 +493,7 @@ namespace demonware utils::hook::call(0x141EC458C_g, get_ffotd_name); // Return unlocalized ffotd name utils::hook::set(0x141F04550_g, 0xC300000001B8); // Kill LPC_File_SafeWrite utils::hook::set(0x141F03180_g, 0xC300000001B8); // Kill LPC_DeleteStale - + utils::hook::set(0x141E0AAAB_g, 0xEB); // Release un-handled reportReward spamming loop } diff --git a/src/client/component/discord.cpp b/src/client/component/discord.cpp index ef30639c..c288683a 100644 --- a/src/client/component/discord.cpp +++ b/src/client/component/discord.cpp @@ -32,7 +32,7 @@ namespace discord } } - class component final : public component_interface + class component final : public client_component_interface { public: void post_load() override diff --git a/src/client/component/exception.cpp b/src/client/component/exception.cpp index 4bd95e69..1dae9fad 100644 --- a/src/client/component/exception.cpp +++ b/src/client/component/exception.cpp @@ -193,9 +193,8 @@ namespace exception } } - class component final : public component_interface + struct component final : component_interface { - public: component() { main_thread_id = GetCurrentThreadId(); diff --git a/src/client/component/icon.cpp b/src/client/component/icon.cpp index 2dff47e1..8416a3c3 100644 --- a/src/client/component/icon.cpp +++ b/src/client/component/icon.cpp @@ -29,9 +29,8 @@ namespace icon } } - class component final : public component_interface + struct component final : component_interface { - public: void post_load() override { load_icon_a_hook.create(LoadIconA, load_icon_a_stub); diff --git a/src/client/component/loot.cpp b/src/client/component/loot.cpp index 773b0c93..5c96fbdb 100644 --- a/src/client/component/loot.cpp +++ b/src/client/component/loot.cpp @@ -14,7 +14,8 @@ namespace loot utils::hook::detour liveinventory_getitemquantity_hook; utils::hook::detour liveinventory_areextraslotspurchased_hook; - int loot_getitemquantity_stub(const game::ControllerIndex_t /*controller_index*/, const game::eModes mode, const int /*item_id*/) + int loot_getitemquantity_stub(const game::ControllerIndex_t /*controller_index*/, const game::eModes mode, + const int /*item_id*/) { if (mode == game::eModes::MODE_ZOMBIES) { @@ -27,7 +28,8 @@ namespace loot int liveinventory_getitemquantity_stub(const game::ControllerIndex_t controller_index, const int item_id) { // Item id's for extra CaC slots, CWL camo's and paid specialist outfits - if (item_id == 99003 || item_id >= 99018 && item_id <= 99021 || item_id == 99025 || item_id >= 90047 && item_id <= 90064) + if (item_id == 99003 || item_id >= 99018 && item_id <= 99021 || item_id == 99025 || item_id >= 90047 && + item_id <= 90064) { return 1; } @@ -47,9 +49,8 @@ namespace loot } }; - class component final : public component_interface + struct component final : client_component_interface { - public: void post_unpack() override { scheduler::once(set_dvars_on_startup, scheduler::pipeline::main); diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index bfc35ba9..27f6880f 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -210,9 +210,8 @@ namespace network return 2; } - class component final : public component_interface + struct component final : client_component_interface { - public: void post_unpack() override { //utils::hook::jump(0x14143CAB0_g, ret2); // patch dwGetConnectionStatus diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp index 416d3940..4134a952 100644 --- a/src/client/component/party.cpp +++ b/src/client/component/party.cpp @@ -217,9 +217,8 @@ namespace party network::send(host, "getInfo", challenge); } - class component final : public component_interface + struct component final : client_component_interface { - public: void post_unpack() override { utils::hook::jump(0x141E19B60_g, 0x141E19BB6_g); // patch steam id validity check diff --git a/src/client/component/scheduler.cpp b/src/client/component/scheduler.cpp index 0c75b321..4df10dce 100644 --- a/src/client/component/scheduler.cpp +++ b/src/client/component/scheduler.cpp @@ -149,9 +149,8 @@ namespace scheduler }, type, delay); } - class component final : public component_interface + struct component final : component_interface { - public: void post_load() override { thread = utils::thread::create_named_thread("Async Scheduler", []() @@ -166,9 +165,12 @@ namespace scheduler void post_unpack() override { - r_end_frame_hook.create(0x142273560_g, r_end_frame_stub); // some func called before R_EndFrame, maybe SND_EndFrame? - g_run_frame_hook.create(0x14065C360_g, server_frame_stub); // GlassSv_Update - main_frame_hook.create(0x1420F9860_g, main_frame_stub); // Com_Frame_Try_Block_Function + if (!game::is_server()) + { + r_end_frame_hook.create(0x142273560_g, r_end_frame_stub); // some func called before R_EndFrame, maybe SND_EndFrame? + g_run_frame_hook.create(0x14065C360_g, server_frame_stub); // GlassSv_Update + main_frame_hook.create(0x1420F9860_g, main_frame_stub); // Com_Frame_Try_Block_Function + } } void pre_destroy() override diff --git a/src/client/component/splash.cpp b/src/client/component/splash.cpp index 354a8ddd..bdf70d4c 100644 --- a/src/client/component/splash.cpp +++ b/src/client/component/splash.cpp @@ -165,9 +165,8 @@ namespace splash } } - class component final : public component_interface + struct component final : client_component_interface { - public: component() { enable_dpi_awareness(); diff --git a/src/client/component/steam_proxy.cpp b/src/client/component/steam_proxy.cpp index 92f5a194..cad0ec65 100644 --- a/src/client/component/steam_proxy.cpp +++ b/src/client/component/steam_proxy.cpp @@ -53,7 +53,7 @@ namespace steam_proxy { std::string name = utils::string::va("CLIENTENGINE_INTERFACE_VERSION%03i", i); auto* const temp_client_engine = steam_client_module - .invoke("CreateInterface", name.data(), nullptr); + .invoke("CreateInterface", name.data(), nullptr); if (temp_client_engine) return temp_client_engine; } @@ -76,7 +76,7 @@ namespace steam_proxy steam_pipe = steam_client_module.invoke("Steam_CreateSteamPipe"); global_user = steam_client_module.invoke( - "Steam_ConnectToGlobalUser", steam_pipe); + "Steam_ConnectToGlobalUser", steam_pipe); client_user = client_engine.invoke(8, global_user, steam_pipe); client_utils = client_engine.invoke(14, steam_pipe); @@ -205,9 +205,8 @@ namespace steam_proxy } } - class component final : public component_interface + struct component final : component_interface { - public: void post_load() override { load_client(); @@ -312,7 +311,7 @@ namespace steam_proxy } void access_subscribed_items( - const std::function& callback) + const std::function& callback) { subscribed_items.access(callback); } diff --git a/src/client/game/game.cpp b/src/client/game/game.cpp index 528c9702..3b2f27e0 100644 --- a/src/client/game/game.cpp +++ b/src/client/game/game.cpp @@ -5,18 +5,33 @@ namespace game { + namespace + { + const utils::nt::library& get_host_library() + { + static auto host = [] + { + utils::nt::library host{}; + if (!host || host == utils::nt::library::get_by_address(get_base)) + { + throw std::runtime_error("Invalid host application"); + } + + return host; + }(); + return host; + } + } + size_t get_base() { - static auto base = [] - { - const utils::nt::library host{}; - if (!host || host == utils::nt::library::get_by_address(get_base)) - { - throw std::runtime_error("Invalid host application"); - } - - return reinterpret_cast(host.get_ptr()); - }(); + static auto base = reinterpret_cast(get_host_library().get_ptr()); return base; } + + bool is_server() + { + static auto server = get_host_library().get_optional_header()->CheckSum == 0x14C28B4; + return server; + } } diff --git a/src/client/game/game.hpp b/src/client/game/game.hpp index 4410d479..83cd194c 100644 --- a/src/client/game/game.hpp +++ b/src/client/game/game.hpp @@ -5,6 +5,7 @@ namespace game { size_t get_base(); + bool is_server(); inline size_t relocate(const size_t val) { diff --git a/src/client/loader/component_interface.hpp b/src/client/loader/component_interface.hpp index 73674add..69e0e31e 100644 --- a/src/client/loader/component_interface.hpp +++ b/src/client/loader/component_interface.hpp @@ -10,9 +10,17 @@ enum class component_priority arxan, }; -class component_interface +enum class component_type { -public: + client, + server, + any, +}; + +struct component_interface +{ + static constexpr component_type type = component_type::any; + virtual ~component_interface() = default; virtual void post_load() @@ -32,3 +40,13 @@ public: return component_priority::min; } }; + +struct client_component_interface : component_interface +{ + static constexpr component_type type = component_type::client; +}; + +struct server_component_interface : component_interface +{ + static constexpr component_type type = component_type::server; +}; diff --git a/src/client/loader/component_loader.cpp b/src/client/loader/component_loader.cpp index 8176866e..e3395f60 100644 --- a/src/client/loader/component_loader.cpp +++ b/src/client/loader/component_loader.cpp @@ -23,9 +23,9 @@ namespace component_loader return *components; } - std::vector& get_registration_functors() + std::vector>& get_registration_functors() { - static std::vector functors; + static std::vector> functors; return functors; } @@ -42,25 +42,28 @@ namespace component_loader } } - void register_component(registration_functor functor) + void register_component(registration_functor functor, component_type type) { if (!get_components().empty()) { throw std::runtime_error("Registration is too late"); } - get_registration_functors().push_back(std::move(functor)); + get_registration_functors().emplace_back(std::move(functor), type); } - bool activate() + bool activate(bool server) { - static auto res = [] + static auto res = [server] { try { for (auto& functor : get_registration_functors()) { - activate_component(functor()); + if (functor.second == component_type::any || server == (functor.second == component_type::server)) + { + activate_component(functor.first()); + } } } catch (premature_shutdown_trigger&) diff --git a/src/client/loader/component_loader.hpp b/src/client/loader/component_loader.hpp index f4abb11b..8d0a4ac4 100644 --- a/src/client/loader/component_loader.hpp +++ b/src/client/loader/component_loader.hpp @@ -5,9 +5,9 @@ namespace component_loader { using registration_functor = std::function()>; - void register_component(registration_functor functor); + void register_component(registration_functor functor, component_type type); - bool activate(); + bool activate(bool server); bool post_load(); void post_unpack(); void pre_destroy(); @@ -33,7 +33,7 @@ namespace component_loader register_component([] { return std::make_unique(); - }); + }, T::type); } }; }; diff --git a/src/client/loader/loader.cpp b/src/client/loader/loader.cpp index 4aecad81..8e8fd580 100644 --- a/src/client/loader/loader.cpp +++ b/src/client/loader/loader.cpp @@ -100,7 +100,7 @@ namespace loader auto* rel_info = offset_pointer(relocation, sizeof(IMAGE_BASE_RELOCATION)); const auto* rel_info_end = offset_pointer( - rel_info, relocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)); + rel_info, relocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)); for (; rel_info < rel_info_end; ++rel_info) { diff --git a/src/client/main.cpp b/src/client/main.cpp index 4bf5deb9..8d0e297f 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -28,7 +28,8 @@ namespace const auto game_entry = game.get_iat_entry("steam_api64.dll", func); if (!game_entry) { - throw std::runtime_error("Import '" + func + "' not found!"); + //throw std::runtime_error("Import '" + func + "' not found!"); + return {nullptr, nullptr}; } const auto original_import = game_entry; @@ -183,12 +184,16 @@ namespace { remove_crash_file(); - if (!component_loader::activate()) + const auto client_binary = "BlackOps3.exe"s; + const auto server_binary = "BlackOps3_UnrankedDedicatedServer.exe"s; + const auto has_server = utils::io::file_exists(server_binary); + + if (!component_loader::activate(has_server)) { return 1; } - entry_point = load_process("BlackOps3.exe"); + entry_point = load_process(has_server ? server_binary : client_binary); if (!entry_point) { throw std::runtime_error("Unable to load binary into memory"); diff --git a/src/common/utils/flags.cpp b/src/common/utils/flags.cpp index 09f13114..bbce3c73 100644 --- a/src/common/utils/flags.cpp +++ b/src/common/utils/flags.cpp @@ -3,51 +3,42 @@ #include "nt.hpp" #include +#include + +#include "finally.hpp" namespace utils::flags { - void parse_flags(std::vector& flags) + std::unordered_set parse_flags() { - int num_args; + int num_args{}; auto* const argv = CommandLineToArgvW(GetCommandLineW(), &num_args); - - flags.clear(); - - if (argv) + const auto _ = finally([&argv] { - for (auto i = 0; i < num_args; ++i) + if (argv) { - std::wstring wide_flag(argv[i]); - if (wide_flag[0] == L'-') - { - wide_flag.erase(wide_flag.begin()); - flags.emplace_back(string::convert(wide_flag)); - } + LocalFree(argv); } + }); - LocalFree(argv); + std::unordered_set flags{}; + + for (auto i = 0; i < num_args && argv; ++i) + { + std::wstring wide_flag(argv[i]); + if (wide_flag[0] == L'-') + { + wide_flag.erase(wide_flag.begin()); + flags.emplace(string::to_lower(string::convert(wide_flag))); + } } + + return flags; } bool has_flag(const std::string& flag) { - static auto parsed = false; - static std::vector enabled_flags; - - if (!parsed) - { - parse_flags(enabled_flags); - parsed = true; - } - - for (const auto& entry : enabled_flags) - { - if (string::to_lower(entry) == string::to_lower(flag)) - { - return true; - } - } - - return false; + static const auto enabled_flags = parse_flags(); + return enabled_flags.contains(string::to_lower(flag)); } }